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 <airlied@redhat.com>
This commit is contained in:
Dave Airlie
2012-03-24 13:33:00 +00:00
parent a75c6163e6
commit f8cf79936b
9 changed files with 154 additions and 6 deletions

View File

@@ -420,6 +420,11 @@ public:
*/ */
int location; int location;
/**
* output index for dual source blending.
*/
int index;
/** /**
* Built-in state that backs this uniform * Built-in state that backs this uniform
* *

View File

@@ -63,6 +63,11 @@ legal_src_factor(const struct gl_context *ctx, GLenum factor)
case GL_CONSTANT_ALPHA: case GL_CONSTANT_ALPHA:
case GL_ONE_MINUS_CONSTANT_ALPHA: case GL_ONE_MINUS_CONSTANT_ALPHA:
return GL_TRUE; 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: default:
return GL_FALSE; return GL_FALSE;
} }
@@ -93,6 +98,12 @@ legal_dst_factor(const struct gl_context *ctx, GLenum factor)
case GL_CONSTANT_ALPHA: case GL_CONSTANT_ALPHA:
case GL_ONE_MINUS_CONSTANT_ALPHA: case GL_ONE_MINUS_CONSTANT_ALPHA:
return GL_TRUE; 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: default:
return GL_FALSE; return GL_FALSE;
} }

View File

@@ -1695,7 +1695,39 @@ _mesa_set_mvp_with_dp4( struct gl_context *ctx,
ctx->mvp_with_dp4 = flag; 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 * 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; return GL_FALSE;
} }
if (_mesa_check_blend_func_error(ctx) == GL_FALSE) {
return GL_FALSE;
}
#ifdef DEBUG #ifdef DEBUG
if (ctx->Shader.Flags & GLSL_LOG) { if (ctx->Shader.Flags & GLSL_LOG) {
struct gl_shader_program *shProg[MESA_SHADER_TYPES]; struct gl_shader_program *shProg[MESA_SHADER_TYPES];

View File

@@ -333,6 +333,7 @@ EXTRA_EXT(ARB_copy_buffer);
EXTRA_EXT(EXT_framebuffer_sRGB); EXTRA_EXT(EXT_framebuffer_sRGB);
EXTRA_EXT(ARB_texture_buffer_object); EXTRA_EXT(ARB_texture_buffer_object);
EXTRA_EXT(OES_EGL_image_external); EXTRA_EXT(OES_EGL_image_external);
EXTRA_EXT(ARB_blend_func_extended);
static const int static const int
extra_ARB_vertex_program_ARB_fragment_program_NV_vertex_program[] = { 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_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_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 */ #endif /* FEATURE_GL */
}; };

View File

@@ -2263,6 +2263,7 @@ struct gl_shader_program
* and they are \b not the values returned by \c glGetFragDataLocation. * and they are \b not the values returned by \c glGetFragDataLocation.
*/ */
struct string_to_uint_map *FragDataBindings; struct string_to_uint_map *FragDataBindings;
struct string_to_uint_map *FragDataIndexBindings;
/** /**
* Transform feedback varyings last specified by * Transform feedback varyings last specified by
@@ -2814,6 +2815,9 @@ struct gl_constants
/* GL_ARB_robustness */ /* GL_ARB_robustness */
GLenum ResetStrategy; GLenum ResetStrategy;
/* GL_ARB_blend_func_extended */
GLuint MaxDualSourceDrawBuffers;
/** /**
* Whether the implementation strips out and ignores texture borders. * Whether the implementation strips out and ignores texture borders.
* *

View File

@@ -238,11 +238,18 @@ _mesa_longest_attribute_name_length(struct gl_shader_program *shProg)
void GLAPIENTRY void GLAPIENTRY
_mesa_BindFragDataLocation(GLuint program, GLuint colorNumber, _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
const GLchar *name) 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); GET_CURRENT_CONTEXT(ctx);
struct gl_shader_program *const shProg = struct gl_shader_program *const shProg =
_mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocation"); _mesa_lookup_shader_program_err(ctx, program, "glBindFragDataLocationIndexed");
if (!shProg) if (!shProg)
return; return;
@@ -250,13 +257,22 @@ _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
return; return;
if (strncmp(name, "gl_", 3) == 0) { if (strncmp(name, "gl_", 3) == 0) {
_mesa_error(ctx, GL_INVALID_OPERATION, _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragDataLocationIndexed(illegal name)");
"glBindFragDataLocation(illegal name)");
return; return;
} }
if (colorNumber >= ctx->Const.MaxDrawBuffers) { if (index > 1) {
_mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocation(index)"); _mesa_error(ctx, GL_INVALID_VALUE, "glBindFragDataLocationIndexed(index)");
return;
}
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; return;
} }
@@ -265,11 +281,68 @@ _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
* between built-in attributes and user-defined attributes. * between built-in attributes and user-defined attributes.
*/ */
shProg->FragDataBindings->put(colorNumber + FRAG_RESULT_DATA0, name); shProg->FragDataBindings->put(colorNumber + FRAG_RESULT_DATA0, name);
shProg->FragDataIndexBindings->put(index, name);
/* /*
* Note that this binding won't go into effect until * Note that this binding won't go into effect until
* glLinkProgram is called again. * 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 GLint GLAPIENTRY

View File

@@ -1748,6 +1748,9 @@ _mesa_init_shader_dispatch(struct _glapi_table *exec)
SET_ReleaseShaderCompiler(exec, _mesa_ReleaseShaderCompiler); SET_ReleaseShaderCompiler(exec, _mesa_ReleaseShaderCompiler);
SET_GetShaderPrecisionFormat(exec, _mesa_GetShaderPrecisionFormat); SET_GetShaderPrecisionFormat(exec, _mesa_GetShaderPrecisionFormat);
/* GL_ARB_blend_func_extended */
SET_BindFragDataLocationIndexed(exec, _mesa_BindFragDataLocationIndexed);
SET_GetFragDataIndex(exec, _mesa_GetFragDataIndex);
#endif /* FEATURE_GL */ #endif /* FEATURE_GL */
} }

View File

@@ -86,6 +86,9 @@ _mesa_GetAttachedObjectsARB(GLhandleARB, GLsizei, GLsizei *, GLhandleARB *);
extern GLint GLAPIENTRY extern GLint GLAPIENTRY
_mesa_GetFragDataLocation(GLuint program, const GLchar *name); _mesa_GetFragDataLocation(GLuint program, const GLchar *name);
extern GLint GLAPIENTRY
_mesa_GetFragDataIndex(GLuint program, const GLchar *name);
extern GLhandleARB GLAPIENTRY extern GLhandleARB GLAPIENTRY
_mesa_GetHandleARB(GLenum pname); _mesa_GetHandleARB(GLenum pname);
@@ -127,6 +130,10 @@ extern void GLAPIENTRY
_mesa_BindFragDataLocation(GLuint program, GLuint colorNumber, _mesa_BindFragDataLocation(GLuint program, GLuint colorNumber,
const GLchar *name); const GLchar *name);
extern void GLAPIENTRY
_mesa_BindFragDataLocationIndexed(GLuint program, GLuint colorNumber,
GLuint index, const GLchar *name);
extern void GLAPIENTRY extern void GLAPIENTRY
_mesa_GetActiveAttribARB(GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, _mesa_GetActiveAttribARB(GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *,
GLenum *, GLcharARB *); GLenum *, GLcharARB *);

View File

@@ -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->AttributeBindings = string_to_uint_map_ctor();
prog->FragDataBindings = string_to_uint_map_ctor(); prog->FragDataBindings = string_to_uint_map_ctor();
prog->FragDataIndexBindings = string_to_uint_map_ctor();
#if FEATURE_ARB_geometry_shader4 #if FEATURE_ARB_geometry_shader4
prog->Geom.VerticesOut = 0; prog->Geom.VerticesOut = 0;
@@ -319,6 +320,11 @@ _mesa_free_shader_program_data(struct gl_context *ctx,
shProg->FragDataBindings = NULL; shProg->FragDataBindings = NULL;
} }
if (shProg->FragDataIndexBindings) {
string_to_uint_map_dtor(shProg->FragDataIndexBindings);
shProg->FragDataIndexBindings = NULL;
}
/* detach shaders */ /* detach shaders */
for (i = 0; i < shProg->NumShaders; i++) { for (i = 0; i < shProg->NumShaders; i++) {
_mesa_reference_shader(ctx, &shProg->Shaders[i], NULL); _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);