[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