diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c index 6cb626a5805..05691d25da0 100644 --- a/src/mesa/main/api_validate.c +++ b/src/mesa/main/api_validate.c @@ -30,9 +30,198 @@ #include "context.h" #include "imports.h" #include "mtypes.h" +#include "pipelineobj.h" #include "enums.h" -#include "vbo/vbo.h" +#include "state.h" #include "transformfeedback.h" +#include "uniforms.h" +#include "vbo/vbo.h" +#include "program/prog_print.h" + + +static bool +check_blend_func_error(struct gl_context *ctx) +{ + /* The ARB_blend_func_extended spec's ERRORS section says: + * + * "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." + */ + for (unsigned i = ctx->Const.MaxDualSourceDrawBuffers; + i < ctx->DrawBuffer->_NumColorDrawBuffers; + i++) { + if (ctx->Color.Blend[i]._UsesDualSrc) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "dual source blend on illegal attachment"); + return false; + } + } + + if (ctx->Color.BlendEnabled && ctx->Color._AdvancedBlendMode) { + /* The KHR_blend_equation_advanced spec says: + * + * "If any non-NONE draw buffer uses a blend equation found in table + * X.1 or X.2, the error INVALID_OPERATION is generated by Begin or + * any operation that implicitly calls Begin (such as DrawElements) + * if: + * + * * the draw buffer for color output zero selects multiple color + * buffers (e.g., FRONT_AND_BACK in the default framebuffer); or + * + * * the draw buffer for any other color output is not NONE." + */ + if (ctx->DrawBuffer->ColorDrawBuffer[0] == GL_FRONT_AND_BACK) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "advanced blending is active and draw buffer for color " + "output zero selects multiple color buffers"); + return false; + } + + for (unsigned i = 1; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { + if (ctx->DrawBuffer->ColorDrawBuffer[i] != GL_NONE) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "advanced blending is active with multiple color " + "draw buffers"); + return false; + } + } + + /* The KHR_blend_equation_advanced spec says: + * + * "Advanced blending equations require the use of a fragment shader + * with a matching "blend_support" layout qualifier. If the current + * blend equation is found in table X.1 or X.2, and the active + * fragment shader does not include the layout qualifier matching + * the blend equation or "blend_support_all_equations", the error + * INVALID_OPERATION is generated [...]" + */ + const struct gl_shader_program *sh_prog = + ctx->_Shader->_CurrentFragmentProgram; + const GLbitfield blend_support = !sh_prog ? 0 : + sh_prog->_LinkedShaders[MESA_SHADER_FRAGMENT]->info.BlendSupport; + + if ((blend_support & ctx->Color._AdvancedBlendMode) == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "fragment shader does not allow advanced blending mode " + "(%s)", + _mesa_enum_to_string(ctx->Color.Blend[0].EquationRGB)); + } + } + + return true; +} + + +/** + * Prior to drawing anything with glBegin, glDrawArrays, etc. this function + * is called to see if it's valid to render. This involves checking that + * the current shader is valid and the framebuffer is complete. + * It also check the current pipeline object is valid if any. + * If an error is detected it'll be recorded here. + * \return GL_TRUE if OK to render, GL_FALSE if not + */ +GLboolean +_mesa_valid_to_render(struct gl_context *ctx, const char *where) +{ + /* This depends on having up to date derived state (shaders) */ + if (ctx->NewState) + _mesa_update_state(ctx); + + if (ctx->API == API_OPENGL_COMPAT) { + /* Any shader stages that are not supplied by the GLSL shader and have + * assembly shaders enabled must now be validated. + */ + if (!ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX] + && ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(vertex program not valid)", where); + return GL_FALSE; + } + + if (!ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT]) { + if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(fragment program not valid)", where); + return GL_FALSE; + } + + /* If drawing to integer-valued color buffers, there must be an + * active fragment shader (GL_EXT_texture_integer). + */ + if (ctx->DrawBuffer && ctx->DrawBuffer->_IntegerColor) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(integer format but no fragment shader)", where); + return GL_FALSE; + } + } + } + + /* A pipeline object is bound */ + if (ctx->_Shader->Name && !ctx->_Shader->Validated) { + if (!_mesa_validate_program_pipeline(ctx, ctx->_Shader)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glValidateProgramPipeline failed to validate the " + "pipeline"); + return GL_FALSE; + } + } + + /* If a program is active and SSO not in use, check if validation of + * samplers succeeded for the active program. */ + if (ctx->_Shader->ActiveProgram && ctx->_Shader != ctx->Pipeline.Current) { + char errMsg[100]; + if (!_mesa_sampler_uniforms_are_valid(ctx->_Shader->ActiveProgram, + errMsg, 100)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", errMsg); + return GL_FALSE; + } + } + + if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, + "%s(incomplete framebuffer)", where); + return GL_FALSE; + } + + if (!check_blend_func_error(ctx)) { + return GL_FALSE; + } + +#ifdef DEBUG + if (ctx->_Shader->Flags & GLSL_LOG) { + struct gl_shader_program **shProg = ctx->_Shader->CurrentProgram; + gl_shader_stage i; + + for (i = 0; i < MESA_SHADER_STAGES; i++) { + if (shProg[i] == NULL || shProg[i]->_Used + || shProg[i]->_LinkedShaders[i] == NULL) + continue; + + /* This is the first time this shader is being used. + * Append shader's constants/uniforms to log file. + * + * Only log data for the program target that matches the shader + * target. It's possible to have a program bound to the vertex + * shader target that also supplied a fragment shader. If that + * program isn't also bound to the fragment shader target we don't + * want to log its fragment data. + */ + _mesa_append_uniforms_to_file(shProg[i]->_LinkedShaders[i]); + } + + for (i = 0; i < MESA_SHADER_STAGES; i++) { + if (shProg[i] != NULL) + shProg[i]->_Used = GL_TRUE; + } + } +#endif + + return GL_TRUE; +} /** diff --git a/src/mesa/main/api_validate.h b/src/mesa/main/api_validate.h index 5b321e3ac99..2eba834c50d 100644 --- a/src/mesa/main/api_validate.h +++ b/src/mesa/main/api_validate.h @@ -35,6 +35,9 @@ struct gl_context; struct gl_transform_feedback_object; +extern GLboolean +_mesa_valid_to_render(struct gl_context *ctx, const char *where); + extern bool _mesa_is_valid_prim_mode(struct gl_context *ctx, GLenum mode); diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c index f550b0c556d..697b5186fb8 100644 --- a/src/mesa/main/context.c +++ b/src/mesa/main/context.c @@ -122,7 +122,6 @@ #include "shaderobj.h" #include "shaderimage.h" #include "util/strtod.h" -#include "state.h" #include "stencil.h" #include "texcompress_s3tc.h" #include "texstate.h" @@ -131,18 +130,16 @@ #include "varray.h" #include "version.h" #include "viewport.h" -#include "vtxfmt.h" #include "program/program.h" -#include "program/prog_print.h" #include "math/m_matrix.h" #include "main/dispatch.h" /* for _gloffset_COUNT */ -#include "uniforms.h" #include "macros.h" #ifdef USE_SPARC_ASM #include "sparc/sparc.h" #endif +#include "compiler/glsl_types.h" #include "compiler/glsl/glsl_parser_extras.h" #include @@ -1857,189 +1854,6 @@ _mesa_Flush(void) } -static bool -check_blend_func_error(struct gl_context *ctx) -{ - /* The ARB_blend_func_extended spec's ERRORS section says: - * - * "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." - */ - for (unsigned i = ctx->Const.MaxDualSourceDrawBuffers; - i < ctx->DrawBuffer->_NumColorDrawBuffers; - i++) { - if (ctx->Color.Blend[i]._UsesDualSrc) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "dual source blend on illegal attachment"); - return false; - } - } - - if (ctx->Color.BlendEnabled && ctx->Color._AdvancedBlendMode) { - /* The KHR_blend_equation_advanced spec says: - * - * "If any non-NONE draw buffer uses a blend equation found in table - * X.1 or X.2, the error INVALID_OPERATION is generated by Begin or - * any operation that implicitly calls Begin (such as DrawElements) - * if: - * - * * the draw buffer for color output zero selects multiple color - * buffers (e.g., FRONT_AND_BACK in the default framebuffer); or - * - * * the draw buffer for any other color output is not NONE." - */ - if (ctx->DrawBuffer->ColorDrawBuffer[0] == GL_FRONT_AND_BACK) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "advanced blending is active and draw buffer for color " - "output zero selects multiple color buffers"); - return false; - } - - for (unsigned i = 1; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { - if (ctx->DrawBuffer->ColorDrawBuffer[i] != GL_NONE) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "advanced blending is active with multiple color " - "draw buffers"); - return false; - } - } - - /* The KHR_blend_equation_advanced spec says: - * - * "Advanced blending equations require the use of a fragment shader - * with a matching "blend_support" layout qualifier. If the current - * blend equation is found in table X.1 or X.2, and the active - * fragment shader does not include the layout qualifier matching - * the blend equation or "blend_support_all_equations", the error - * INVALID_OPERATION is generated [...]" - */ - const struct gl_shader_program *sh_prog = - ctx->_Shader->_CurrentFragmentProgram; - const GLbitfield blend_support = !sh_prog ? 0 : - sh_prog->_LinkedShaders[MESA_SHADER_FRAGMENT]->info.BlendSupport; - - if ((blend_support & ctx->Color._AdvancedBlendMode) == 0) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "fragment shader does not allow advanced blending mode " - "(%s)", - _mesa_enum_to_string(ctx->Color.Blend[0].EquationRGB)); - } - } - - return true; -} - - -/** - * Prior to drawing anything with glBegin, glDrawArrays, etc. this function - * is called to see if it's valid to render. This involves checking that - * the current shader is valid and the framebuffer is complete. - * It also check the current pipeline object is valid if any. - * If an error is detected it'll be recorded here. - * \return GL_TRUE if OK to render, GL_FALSE if not - */ -GLboolean -_mesa_valid_to_render(struct gl_context *ctx, const char *where) -{ - /* This depends on having up to date derived state (shaders) */ - if (ctx->NewState) - _mesa_update_state(ctx); - - if (ctx->API == API_OPENGL_COMPAT) { - /* Any shader stages that are not supplied by the GLSL shader and have - * assembly shaders enabled must now be validated. - */ - if (!ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX] - && ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(vertex program not valid)", where); - return GL_FALSE; - } - - if (!ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT]) { - if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(fragment program not valid)", where); - return GL_FALSE; - } - - /* If drawing to integer-valued color buffers, there must be an - * active fragment shader (GL_EXT_texture_integer). - */ - if (ctx->DrawBuffer && ctx->DrawBuffer->_IntegerColor) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(integer format but no fragment shader)", where); - return GL_FALSE; - } - } - } - - /* A pipeline object is bound */ - if (ctx->_Shader->Name && !ctx->_Shader->Validated) { - if (!_mesa_validate_program_pipeline(ctx, ctx->_Shader)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glValidateProgramPipeline failed to validate the " - "pipeline"); - return GL_FALSE; - } - } - - /* If a program is active and SSO not in use, check if validation of - * samplers succeeded for the active program. */ - if (ctx->_Shader->ActiveProgram && ctx->_Shader != ctx->Pipeline.Current) { - char errMsg[100]; - if (!_mesa_sampler_uniforms_are_valid(ctx->_Shader->ActiveProgram, - errMsg, 100)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s", errMsg); - return GL_FALSE; - } - } - - if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { - _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, - "%s(incomplete framebuffer)", where); - return GL_FALSE; - } - - if (!check_blend_func_error(ctx)) { - return GL_FALSE; - } - -#ifdef DEBUG - if (ctx->_Shader->Flags & GLSL_LOG) { - struct gl_shader_program **shProg = ctx->_Shader->CurrentProgram; - gl_shader_stage i; - - for (i = 0; i < MESA_SHADER_STAGES; i++) { - if (shProg[i] == NULL || shProg[i]->_Used - || shProg[i]->_LinkedShaders[i] == NULL) - continue; - - /* This is the first time this shader is being used. - * Append shader's constants/uniforms to log file. - * - * Only log data for the program target that matches the shader - * target. It's possible to have a program bound to the vertex - * shader target that also supplied a fragment shader. If that - * program isn't also bound to the fragment shader target we don't - * want to log its fragment data. - */ - _mesa_append_uniforms_to_file(shProg[i]->_LinkedShaders[i]); - } - - for (i = 0; i < MESA_SHADER_STAGES; i++) { - if (shProg[i] != NULL) - shProg[i]->_Used = GL_TRUE; - } - } -#endif - - return GL_TRUE; -} /*@}*/ diff --git a/src/mesa/main/context.h b/src/mesa/main/context.h index 520b3bbfb9a..9704a96e11f 100644 --- a/src/mesa/main/context.h +++ b/src/mesa/main/context.h @@ -152,9 +152,6 @@ _mesa_get_dispatch(struct gl_context *ctx); extern void _mesa_set_context_lost_dispatch(struct gl_context *ctx); -extern GLboolean -_mesa_valid_to_render(struct gl_context *ctx, const char *where); - /** \name Miscellaneous */ diff --git a/src/mesa/main/drawpix.c b/src/mesa/main/drawpix.c index 720a082ce6d..ec1d2618cad 100644 --- a/src/mesa/main/drawpix.c +++ b/src/mesa/main/drawpix.c @@ -24,6 +24,7 @@ #include "glheader.h" #include "imports.h" +#include "api_validate.h" #include "bufferobj.h" #include "context.h" #include "drawpix.h"