From f8cf79936b42405a8366613b80e3bde21aadaa02 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 24 Mar 2012 13:33:00 +0000 Subject: [PATCH] mesa: add support for ARB_blend_func_extended (v4) 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 v4: fixup Brian's comments The GLSL patch will setup the indices. Signed-off-by: Dave Airlie --- src/glsl/ir.h | 5 +++ src/mesa/main/blend.c | 11 ++++++ src/mesa/main/context.c | 36 ++++++++++++++++++ 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, 154 insertions(+), 6 deletions(-) diff --git a/src/glsl/ir.h b/src/glsl/ir.h index b1ae6db7416..9450e8f8430 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 09acdf5c588..bc446edcabb 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 83e5de47a88..51b024143ad 100644 --- a/src/mesa/main/context.c +++ b/src/mesa/main/context.c @@ -1695,7 +1695,39 @@ _mesa_set_mvp_with_dp4( struct gl_context *ctx, ctx->mvp_with_dp4 = flag; } +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) +{ + GLuint i; + 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; +} /** * Prior to drawing anything with glBegin, glDrawArrays, etc. this function @@ -1816,6 +1848,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 9a5ca53345b..55dc20550a8 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 8e441c232b7..bfa320a52d7 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2263,6 +2263,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 @@ -2814,6 +2815,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 8ab18126c9e..02a48ba60a6 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 0e655a0d8ef..e0f20b638a0 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 0ffebdb075f..4886959d5fb 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 36f208d6c09..7eb6f0bdab0 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); -- 2.11.0