[Mesa-dev] [PATCH 1/7] mesa: add support for ARB_blend_func_extended (v3)

Brian Paul brianp at vmware.com
Wed Apr 4 08:15:28 PDT 2012


On 04/03/2012 07:16 AM, Dave Airlie wrote:
> From: Dave Airlie<airlied at redhat.com>
>
> Add implementations of the two API functions,
> Add a new strings to uint mapping for index bindings
> Add the blending mode validation for SRC1 + SRC_ALPHA_SATURATE
> Add get for MAX_DUAL_SOURCE_DRAW_BUFFERS
>
> v2:
> Add check in valid_to_render to address case in spec ERRORS.
>
> v3:
> Add index to ir.h so this patch compiles on its own
> fixup comment
>
> The GLSL patch will setup the indices.
>
> Signed-off-by: Dave Airlie<airlied at redhat.com>
> ---
>   src/glsl/ir.h                  |    5 ++
>   src/mesa/main/blend.c          |   11 +++++
>   src/mesa/main/context.c        |   35 ++++++++++++++++
>   src/mesa/main/get.c            |    3 +
>   src/mesa/main/mtypes.h         |    4 ++
>   src/mesa/main/shader_query.cpp |   85 +++++++++++++++++++++++++++++++++++++---
>   src/mesa/main/shaderapi.c      |    3 +
>   src/mesa/main/shaderapi.h      |    7 +++
>   src/mesa/main/shaderobj.c      |    6 +++
>   9 files changed, 153 insertions(+), 6 deletions(-)
>
> diff --git a/src/glsl/ir.h b/src/glsl/ir.h
> index b1ae6db..9450e8f 100644
> --- a/src/glsl/ir.h
> +++ b/src/glsl/ir.h
> @@ -421,6 +421,11 @@ public:
>      int location;
>
>      /**
> +    * output index for dual source blending.
> +    */
> +   int index;
> +
> +   /**
>       * Built-in state that backs this uniform
>       *
>       * Once set at variable creation, \c state_slots must remain invariant.
> diff --git a/src/mesa/main/blend.c b/src/mesa/main/blend.c
> index 09acdf5..bc446ed 100644
> --- a/src/mesa/main/blend.c
> +++ b/src/mesa/main/blend.c
> @@ -63,6 +63,11 @@ legal_src_factor(const struct gl_context *ctx, GLenum factor)
>      case GL_CONSTANT_ALPHA:
>      case GL_ONE_MINUS_CONSTANT_ALPHA:
>         return GL_TRUE;
> +   case GL_SRC1_COLOR:
> +   case GL_SRC1_ALPHA:
> +   case GL_ONE_MINUS_SRC1_COLOR:
> +   case GL_ONE_MINUS_SRC1_ALPHA:
> +      return ctx->Extensions.ARB_blend_func_extended;
>      default:
>         return GL_FALSE;
>      }
> @@ -93,6 +98,12 @@ legal_dst_factor(const struct gl_context *ctx, GLenum factor)
>      case GL_CONSTANT_ALPHA:
>      case GL_ONE_MINUS_CONSTANT_ALPHA:
>         return GL_TRUE;
> +   case GL_SRC_ALPHA_SATURATE:
> +   case GL_SRC1_COLOR:
> +   case GL_SRC1_ALPHA:
> +   case GL_ONE_MINUS_SRC1_COLOR:
> +   case GL_ONE_MINUS_SRC1_ALPHA:
> +      return ctx->Extensions.ARB_blend_func_extended;
>      default:
>         return GL_FALSE;
>      }
> diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c
> index 83e5de4..cff002e 100644
> --- a/src/mesa/main/context.c
> +++ b/src/mesa/main/context.c
> @@ -1695,7 +1695,38 @@ _mesa_set_mvp_with_dp4( struct gl_context *ctx,
>      ctx->mvp_with_dp4 = flag;
>   }
>
> +static int blend_factor_is_dual_src(GLenum factor)

How about this:

static GLboolean
blend_factor_is_dual_src(GLenum factor)


> +{
> +   return factor == GL_SRC1_COLOR || factor == GL_SRC1_ALPHA ||
> +      factor == GL_ONE_MINUS_SRC1_COLOR || factor == GL_ONE_MINUS_SRC1_ALPHA;
> +}
>
> +/*
> + * ARB_blend_func_extended - ERRORS section
> + * "The error INVALID_OPERATION is generated by Begin or any procedure that
> + *  implicitly calls Begin if any draw buffer has a blend function requiring the
> + *  second color input (SRC1_COLOR, ONE_MINUS_SRC1_COLOR, SRC1_ALPHA or
> + *  ONE_MINUS_SRC1_ALPHA), and a framebuffer is bound that has more than
> + *  the value of MAX_DUAL_SOURCE_DRAW_BUFFERS-1 active color attachements."
> + */
> +static GLboolean
> +_mesa_check_blend_func_error(struct gl_context *ctx)
> +{
> +   int i;

GLuint i (to prevent signed/unsigned comparison warning with MSVC).


> +   for (i = 0; i<  ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
> +      if (blend_factor_is_dual_src(ctx->Color.Blend[i].SrcRGB) ||
> +          blend_factor_is_dual_src(ctx->Color.Blend[i].DstRGB) ||
> +          blend_factor_is_dual_src(ctx->Color.Blend[i].SrcA) ||
> +          blend_factor_is_dual_src(ctx->Color.Blend[i].DstA)) {
> +         if (i>= ctx->Const.MaxDualSourceDrawBuffers) {
> +            _mesa_error(ctx, GL_INVALID_OPERATION,
> +                        "dual source blend on illegal attachment");
> +            return GL_FALSE;
> +         }
> +      }
> +   }
> +   return GL_TRUE;
> +}

It seems to me that we could have a flag in the blending state that 
indicates if any of the terms are extended.  Then we could reduce the 
cost of this per-draw check.  Maybe try that in a follow-on patch.


>
>   /**
>    * Prior to drawing anything with glBegin, glDrawArrays, etc. this function
> @@ -1816,6 +1847,10 @@ _mesa_valid_to_render(struct gl_context *ctx, const char *where)
>         return GL_FALSE;
>      }
>
> +   if (_mesa_check_blend_func_error(ctx) == GL_FALSE) {
> +      return GL_FALSE;
> +   }
> +
>   #ifdef DEBUG
>      if (ctx->Shader.Flags&  GLSL_LOG) {
>         struct gl_shader_program *shProg[MESA_SHADER_TYPES];
> diff --git a/src/mesa/main/get.c b/src/mesa/main/get.c
> index 9a5ca53..55dc205 100644
> --- a/src/mesa/main/get.c
> +++ b/src/mesa/main/get.c
> @@ -333,6 +333,7 @@ EXTRA_EXT(ARB_copy_buffer);
>   EXTRA_EXT(EXT_framebuffer_sRGB);
>   EXTRA_EXT(ARB_texture_buffer_object);
>   EXTRA_EXT(OES_EGL_image_external);
> +EXTRA_EXT(ARB_blend_func_extended);
>
>   static const int
>   extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program[] = {
> @@ -1304,6 +1305,8 @@ static const struct value_desc values[] = {
>      { GL_MAX_DEBUG_LOGGED_MESSAGES_ARB, CONST(MAX_DEBUG_LOGGED_MESSAGES), NO_EXTRA },
>      { GL_MAX_DEBUG_MESSAGE_LENGTH_ARB, CONST(MAX_DEBUG_MESSAGE_LENGTH), NO_EXTRA },
>
> +   { GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, CONTEXT_INT(Const.MaxDualSourceDrawBuffers), extra_ARB_blend_func_extended },
> +
>   #endif /* FEATURE_GL */
>   };
>
> diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
> index a3827d4..e26f589 100644
> --- a/src/mesa/main/mtypes.h
> +++ b/src/mesa/main/mtypes.h
> @@ -2261,6 +2261,7 @@ struct gl_shader_program
>       * and they are \b not the values returned by \c glGetFragDataLocation.
>       */
>      struct string_to_uint_map *FragDataBindings;
> +   struct string_to_uint_map *FragDataIndexBindings;
>
>      /**
>       * Transform feedback varyings last specified by
> @@ -2812,6 +2813,9 @@ struct gl_constants
>      /* GL_ARB_robustness */
>      GLenum ResetStrategy;
>
> +   /* GL_ARB_blend_func_extended */
> +   GLuint MaxDualSourceDrawBuffers;
> +
>      /**
>       * Whether the implementation strips out and ignores texture borders.
>       *
> diff --git a/src/mesa/main/shader_query.cpp b/src/mesa/main/shader_query.cpp
> index 8ab1812..02a48ba 100644
> --- a/src/mesa/main/shader_query.cpp
> +++ b/src/mesa/main/shader_query.cpp
> @@ -239,10 +239,17 @@ void GLAPIENTRY
>   _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
>   			   const GLchar *name)
>   {
> +   _mesa_BindFragDataLocationIndexed(program, colorNumber, 0, name);
> +}
> +
> +void GLAPIENTRY
> +_mesa_BindFragDataLocationIndexed(GLuint program, GLuint colorNumber,
> +                                  GLuint index, const GLchar *name)
> +{
>      GET_CURRENT_CONTEXT(ctx);
>
>      struct gl_shader_program *const shProg =
> -      _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocation");
> +      _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocationIndexed");
>      if (!shProg)
>         return;
>
> @@ -250,13 +257,22 @@ _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
>         return;
>
>      if (strncmp(name, "gl_", 3) == 0) {
> -      _mesa_error(ctx, GL_INVALID_OPERATION,
> -                  "glBindFragDataLocation(illegal name)");
> +      _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragDataLocationIndexed(illegal name)");
> +      return;
> +   }
> +
> +   if (index>  1) {
> +      _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(index)");
>         return;
>      }
>
> -   if (colorNumber>= ctx->Const.MaxDrawBuffers) {
> -      _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocation(index)");
> +   if (index == 0&&  colorNumber>= ctx->Const.MaxDrawBuffers) {
> +      _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
> +      return;
> +   }
> +
> +   if (index == 1&&  colorNumber>= ctx->Const.MaxDualSourceDrawBuffers) {
> +      _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(colorNumber)");
>         return;
>      }
>
> @@ -265,11 +281,68 @@ _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
>       * between built-in attributes and user-defined attributes.
>       */
>      shProg->FragDataBindings->put(colorNumber + FRAG_RESULT_DATA0, name);
> -
> +   shProg->FragDataIndexBindings->put(index, name);
>      /*
>       * Note that this binding won't go into effect until
>       * glLinkProgram is called again.
>       */
> +
> +}
> +
> +GLint GLAPIENTRY
> +_mesa_GetFragDataIndex(GLuint program, const GLchar *name)
> +{
> +   GET_CURRENT_CONTEXT(ctx);
> +   struct gl_shader_program *const shProg =
> +      _mesa_lookup_shader_program_err(ctx, program, "glGetFragDataIndex");
> +
> +   if (!shProg) {
> +      return -1;
> +   }
> +
> +   if (!shProg->LinkStatus) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION,
> +                  "glGetFragDataIndex(program not linked)");
> +      return -1;
> +   }
> +
> +   if (!name)
> +      return -1;
> +
> +   if (strncmp(name, "gl_", 3) == 0) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION,
> +                  "glGetFragDataIndex(illegal name)");
> +      return -1;
> +   }
> +
> +   /* Not having a fragment shader is not an error.
> +    */
> +   if (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)
> +      return -1;
> +
> +   exec_list *ir = shProg->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir;
> +   foreach_list(node, ir) {
> +      const ir_variable *const var = ((ir_instruction *) node)->as_variable();
> +
> +      /* The extra check against FRAG_RESULT_DATA0 is because
> +       * glGetFragDataLocation cannot be used on "conventional" attributes.
> +       *
> +       * From page 95 of the OpenGL 3.0 spec:
> +       *
> +       *     "If name is not an active attribute, if name is a conventional
> +       *     attribute, or if an error occurs, -1 will be returned."
> +       */
> +      if (var == NULL
> +          || var->mode != ir_var_out
> +          || var->location == -1
> +          || var->location<  FRAG_RESULT_DATA0)
> +         continue;
> +
> +      if (strcmp(var->name, name) == 0)
> +         return var->index;
> +   }
> +
> +   return -1;
>   }
>
>   GLint GLAPIENTRY
> diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c
> index 0e655a0..e0f20b6 100644
> --- a/src/mesa/main/shaderapi.c
> +++ b/src/mesa/main/shaderapi.c
> @@ -1748,6 +1748,9 @@ _mesa_init_shader_dispatch(struct _glapi_table *exec)
>      SET_ReleaseShaderCompiler(exec, _mesa_ReleaseShaderCompiler);
>      SET_GetShaderPrecisionFormat(exec, _mesa_GetShaderPrecisionFormat);
>
> +   /* GL_ARB_blend_func_extended */
> +   SET_BindFragDataLocationIndexed(exec, _mesa_BindFragDataLocationIndexed);
> +   SET_GetFragDataIndex(exec, _mesa_GetFragDataIndex);
>   #endif /* FEATURE_GL */
>   }
>
> diff --git a/src/mesa/main/shaderapi.h b/src/mesa/main/shaderapi.h
> index 0ffebdb..4886959 100644
> --- a/src/mesa/main/shaderapi.h
> +++ b/src/mesa/main/shaderapi.h
> @@ -86,6 +86,9 @@ _mesa_GetAttachedObjectsARB(GLhandleARB, GLsizei, GLsizei *, GLhandleARB *);
>   extern GLint GLAPIENTRY
>   _mesa_GetFragDataLocation(GLuint program, const GLchar *name);
>
> +extern GLint GLAPIENTRY
> +_mesa_GetFragDataIndex(GLuint program, const GLchar *name);
> +
>   extern GLhandleARB GLAPIENTRY
>   _mesa_GetHandleARB(GLenum pname);
>
> @@ -128,6 +131,10 @@ _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
>                              const GLchar *name);
>
>   extern void GLAPIENTRY
> +_mesa_BindFragDataLocationIndexed(GLuint program, GLuint colorNumber,
> +                                  GLuint index, const GLchar *name);
> +
> +extern void GLAPIENTRY
>   _mesa_GetActiveAttribARB(GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *,
>                            GLenum *, GLcharARB *);
>
> diff --git a/src/mesa/main/shaderobj.c b/src/mesa/main/shaderobj.c
> index 36f208d..7eb6f0b 100644
> --- a/src/mesa/main/shaderobj.c
> +++ b/src/mesa/main/shaderobj.c
> @@ -242,6 +242,7 @@ _mesa_init_shader_program(struct gl_context *ctx, struct gl_shader_program *prog
>
>      prog->AttributeBindings = string_to_uint_map_ctor();
>      prog->FragDataBindings = string_to_uint_map_ctor();
> +   prog->FragDataIndexBindings = string_to_uint_map_ctor();
>
>   #if FEATURE_ARB_geometry_shader4
>      prog->Geom.VerticesOut = 0;
> @@ -319,6 +320,11 @@ _mesa_free_shader_program_data(struct gl_context *ctx,
>         shProg->FragDataBindings = NULL;
>      }
>
> +   if (shProg->FragDataIndexBindings) {
> +      string_to_uint_map_dtor(shProg->FragDataIndexBindings);
> +      shProg->FragDataIndexBindings = NULL;
> +   }
> +
>      /* detach shaders */
>      for (i = 0; i<  shProg->NumShaders; i++) {
>         _mesa_reference_shader(ctx,&shProg->Shaders[i], NULL);



More information about the mesa-dev mailing list