#include "state.h"
#include "transformfeedback.h"
#include "uniforms.h"
-#include "vbo/vbo.h"
#include "program/prog_print.h"
* the blend equation or "blend_support_all_equations", the error
* INVALID_OPERATION is generated [...]"
*/
- const struct gl_program *prog = ctx->_Shader->_CurrentFragmentProgram;
+ const struct gl_program *prog = ctx->FragmentProgram._Current;
const GLbitfield blend_support = !prog ? 0 : prog->sh.fs.BlendSupport;
if ((blend_support & ctx->Color._AdvancedBlendMode) == 0) {
/* 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) {
+ if (!ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX] &&
+ ctx->VertexProgram.Enabled &&
+ !_mesa_arb_vertex_program_enabled(ctx)) {
_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) {
+ if (ctx->FragmentProgram.Enabled &&
+ !_mesa_arb_fragment_program_enabled(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(fragment program not valid)", where);
return GL_FALSE;
return GL_FALSE;
}
+ /* From the GL_NV_fill_rectangle spec:
+ *
+ * "An INVALID_OPERATION error is generated by Begin or any Draw command if
+ * only one of the front and back polygon mode is FILL_RECTANGLE_NV."
+ */
+ if ((ctx->Polygon.FrontMode == GL_FILL_RECTANGLE_NV) !=
+ (ctx->Polygon.BackMode == GL_FILL_RECTANGLE_NV)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "GL_FILL_RECTANGLE_NV must be used as both front/back "
+ "polygon mode or neither");
+ return GL_FALSE;
+ }
+
#ifdef DEBUG
if (ctx->_Shader->Flags & GLSL_LOG) {
- struct gl_shader_program **shProg = ctx->_Shader->CurrentProgram;
- gl_shader_stage i;
+ struct gl_program **prog = ctx->_Shader->CurrentProgram;
- for (i = 0; i < MESA_SHADER_STAGES; i++) {
- if (shProg[i] == NULL || shProg[i]->_LinkedShaders[i] == NULL ||
- shProg[i]->_LinkedShaders[i]->Program->_Used)
+ for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+ if (prog[i] == NULL || prog[i]->_Used)
continue;
/* This is the first time this shader is being used.
* 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]->Program);
+ _mesa_append_uniforms_to_file(prog[i]);
}
- for (i = 0; i < MESA_SHADER_STAGES; i++) {
- if (shProg[i] != NULL && shProg[i]->_LinkedShaders[i] != NULL)
- shProg[i]->_LinkedShaders[i]->Program->_Used = GL_TRUE;
+ for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+ if (prog[i] != NULL)
+ prog[i]->_Used = GL_TRUE;
}
}
#endif
return false;
}
- if (!_mesa_all_buffers_are_unmapped(ctx->Array.VAO)) {
+ /* Section 6.3.2 from the GL 4.5:
+ * "Any GL command which attempts to read from, write to, or change
+ * the state of a buffer object may generate an INVALID_OPERATION error if
+ * all or part of the buffer object is mapped ... However, only commands
+ * which explicitly describe this error are required to do so. If an error
+ * is not generated, such commands will have undefined results and may
+ * result in GL interruption or termination."
+ *
+ * Only some buffer API functions require INVALID_OPERATION with mapped
+ * buffers. No other functions list such an error, thus it's not required
+ * to report INVALID_OPERATION for draw calls with mapped buffers.
+ */
+ if (!ctx->Const.AllowMappedBuffersDuringExecution &&
+ !_mesa_all_buffers_are_unmapped(ctx->Array.VAO)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(vertex buffers are mapped)", function);
return false;
}
+ /* Section 11.2 (Tessellation) of the ES 3.2 spec says:
+ *
+ * "An INVALID_OPERATION error is generated by any command that
+ * transfers vertices to the GL if the current program state has
+ * one but not both of a tessellation control shader and tessellation
+ * evaluation shader."
+ *
+ * The OpenGL spec argues that this is allowed because a tess ctrl shader
+ * without a tess eval shader can be used with transform feedback.
+ * However, glBeginTransformFeedback doesn't allow GL_PATCHES and
+ * therefore doesn't allow tessellation.
+ *
+ * Further investigation showed that this is indeed a spec bug and
+ * a tess ctrl shader without a tess eval shader shouldn't have been
+ * allowed, because there is no API in GL 4.0 that can make use this
+ * to produce something useful.
+ *
+ * Also, all vendors except one don't support a tess ctrl shader without
+ * a tess eval shader anyway.
+ */
+ if (ctx->TessCtrlProgram._Current && !ctx->TessEvalProgram._Current) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(tess eval shader is missing)", function);
+ return false;
+ }
+
switch (ctx->API) {
case API_OPENGLES2:
- /* For ES2, we can draw if we have a vertex program/shader). */
- return ctx->VertexProgram._Current != NULL;
-
- case API_OPENGLES:
- /* For OpenGL ES, only draw if we have vertex positions
+ /* Section 11.2 (Tessellation) of the ES 3.2 spec says:
+ *
+ * "An INVALID_OPERATION error is generated by any command that
+ * transfers vertices to the GL if the current program state has
+ * one but not both of a tessellation control shader and tessellation
+ * evaluation shader."
*/
- if (!ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_POS].Enabled)
+ if (_mesa_is_gles3(ctx) &&
+ ctx->TessEvalProgram._Current && !ctx->TessCtrlProgram._Current) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(tess ctrl shader is missing)", function);
return false;
+ }
break;
case API_OPENGL_CORE:
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(no VAO bound)", function);
return false;
}
+ break;
- /* The spec argues that this is allowed because a tess ctrl shader
- * without a tess eval shader can be used with transform feedback.
- * However, glBeginTransformFeedback doesn't allow GL_PATCHES and
- * therefore doesn't allow tessellation.
- *
- * Further investigation showed that this is indeed a spec bug and
- * a tess ctrl shader without a tess eval shader shouldn't have been
- * allowed, because there is no API in GL 4.0 that can make use this
- * to produce something useful.
- *
- * Also, all vendors except one don't support a tess ctrl shader without
- * a tess eval shader anyway.
- */
- if (ctx->TessCtrlProgram._Current && !ctx->TessEvalProgram._Current) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(tess eval shader is missing)", function);
- return false;
- }
-
- /* Section 7.3 (Program Objects) of the OpenGL 4.5 Core Profile spec
- * says:
- *
- * "If there is no active program for the vertex or fragment shader
- * stages, the results of vertex and/or fragment processing will be
- * undefined. However, this is not an error."
- *
- * The fragment shader is not tested here because other state (e.g.,
- * GL_RASTERIZER_DISCARD) affects whether or not we actually care.
- */
- return ctx->VertexProgram._Current != NULL;
-
+ case API_OPENGLES:
case API_OPENGL_COMPAT:
- if (ctx->VertexProgram._Current != NULL) {
- /* Draw regardless of whether or not we have any vertex arrays.
- * (Ex: could draw a point using a constant vertex pos)
- */
- return true;
- } else {
- /* Draw if we have vertex positions (GL_VERTEX_ARRAY or generic
- * array [0]).
- */
- return (ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_POS].Enabled ||
- ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled);
- }
break;
default:
* Note: This may be called during display list compilation.
*/
bool
-_mesa_is_valid_prim_mode(struct gl_context *ctx, GLenum mode)
+_mesa_is_valid_prim_mode(const struct gl_context *ctx, GLenum mode)
{
/* The overwhelmingly common case is (mode <= GL_TRIANGLE_FAN). Test that
* first and exit. You would think that a switch-statement would be the
if (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) {
const GLenum geom_mode =
ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->
- _LinkedShaders[MESA_SHADER_GEOMETRY]->info.Geom.InputType;
- struct gl_shader_program *tes =
+ info.gs.input_primitive;
+ struct gl_program *tes =
ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL];
GLenum mode_before_gs = mode;
if (tes) {
- struct gl_linked_shader *tes_sh =
- tes->_LinkedShaders[MESA_SHADER_TESS_EVAL];
- if (tes_sh->info.TessEval.PointMode)
+ if (tes->info.tess.point_mode)
mode_before_gs = GL_POINTS;
- else if (tes_sh->info.TessEval.PrimitiveMode == GL_ISOLINES)
+ else if (tes->info.tess.primitive_mode == GL_ISOLINES)
mode_before_gs = GL_LINES;
else
/* the GL_QUADS mode generates triangles too */
if(ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) {
switch (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->
- _LinkedShaders[MESA_SHADER_GEOMETRY]->
- info.Geom.OutputType) {
+ info.gs.output_primitive) {
case GL_POINTS:
pass = ctx->TransformFeedback.Mode == GL_POINTS;
break;
}
}
else if (ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL]) {
- struct gl_shader_program *tes =
+ struct gl_program *tes =
ctx->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL];
- struct gl_linked_shader *tes_sh =
- tes->_LinkedShaders[MESA_SHADER_TESS_EVAL];
- if (tes_sh->info.TessEval.PointMode)
+ if (tes->info.tess.point_mode)
pass = ctx->TransformFeedback.Mode == GL_POINTS;
- else if (tes_sh->info.TessEval.PrimitiveMode == GL_ISOLINES)
+ else if (tes->info.tess.primitive_mode == GL_ISOLINES)
pass = ctx->TransformFeedback.Mode == GL_LINES;
else
pass = ctx->TransformFeedback.Mode == GL_TRIANGLES;
* to have been overlooked. The body of the spec only explicitly allows
* the indirect versions.
*/
- if (_mesa_is_gles3(ctx) && !ctx->Extensions.OES_geometry_shader &&
+ if (_mesa_is_gles3(ctx) &&
+ !_mesa_has_OES_geometry_shader(ctx) &&
_mesa_is_xfb_active_and_unpaused(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(transform feedback active)", caller);
if (!check_valid_to_render(ctx, caller))
return false;
- /* Not using a VBO for indices, so avoid NULL pointer derefs later.
- */
- if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj) && indices == NULL)
- return false;
-
- if (count == 0)
- return false;
-
return true;
}
_mesa_validate_MultiDrawElements(struct gl_context *ctx,
GLenum mode, const GLsizei *count,
GLenum type, const GLvoid * const *indices,
- GLuint primcount)
+ GLsizei primcount)
{
- unsigned i;
+ GLsizei i;
FLUSH_CURRENT(ctx, 0);
+ /*
+ * Section 2.3.1 (Errors) of the OpenGL 4.5 (Core Profile) spec says:
+ *
+ * "If a negative number is provided where an argument of type sizei or
+ * sizeiptr is specified, an INVALID_VALUE error is generated."
+ *
+ * and in the same section:
+ *
+ * "In other cases, there are no side effects unless otherwise noted;
+ * the command which generates the error is ignored so that it has no
+ * effect on GL state or framebuffer contents."
+ *
+ * Hence, check both primcount and all the count[i].
+ */
+ if (primcount < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glMultiDrawElements(primcount=%d)", primcount);
+ return GL_FALSE;
+ }
+
for (i = 0; i < primcount; i++) {
if (count[i] < 0) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glDrawRangeElements");
}
+
static bool
-validate_draw_arrays(struct gl_context *ctx, const char *func,
- GLenum mode, GLsizei count, GLsizei numInstances)
+need_xfb_remaining_prims_check(const struct gl_context *ctx)
{
- struct gl_transform_feedback_object *xfb_obj
- = ctx->TransformFeedback.CurrentObject;
- FLUSH_CURRENT(ctx, 0);
-
- if (count < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "%s(count)", func);
- return false;
- }
-
- if (!_mesa_valid_prim_mode(ctx, mode, func))
- return false;
-
- if (!check_valid_to_render(ctx, func))
- return false;
-
/* From the GLES3 specification, section 2.14.2 (Transform Feedback
* Primitive Capture):
*
* is removed and replaced with the GL behavior (primitives are not
* written and the corresponding counter is not updated)..."
*/
- if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx) &&
- !_mesa_has_OES_geometry_shader(ctx) &&
- !_mesa_has_OES_tessellation_shader(ctx)) {
- size_t prim_count = vbo_count_tessellated_primitives(mode, count, 1);
+ return _mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx) &&
+ !_mesa_has_OES_geometry_shader(ctx) &&
+ !_mesa_has_OES_tessellation_shader(ctx);
+}
+
+
+/**
+ * Figure out the number of transform feedback primitives that will be output
+ * considering the drawing mode, number of vertices, and instance count,
+ * assuming that no geometry shading is done and primitive restart is not
+ * used.
+ *
+ * This is used by driver back-ends in implementing the PRIMITIVES_GENERATED
+ * and TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN queries. It is also used to
+ * pre-validate draw calls in GLES3 (where draw calls only succeed if there is
+ * enough room in the transform feedback buffer for the result).
+ */
+static size_t
+count_tessellated_primitives(GLenum mode, GLuint count, GLuint num_instances)
+{
+ size_t num_primitives;
+ switch (mode) {
+ case GL_POINTS:
+ num_primitives = count;
+ break;
+ case GL_LINE_STRIP:
+ num_primitives = count >= 2 ? count - 1 : 0;
+ break;
+ case GL_LINE_LOOP:
+ num_primitives = count >= 2 ? count : 0;
+ break;
+ case GL_LINES:
+ num_primitives = count / 2;
+ break;
+ case GL_TRIANGLE_STRIP:
+ case GL_TRIANGLE_FAN:
+ case GL_POLYGON:
+ num_primitives = count >= 3 ? count - 2 : 0;
+ break;
+ case GL_TRIANGLES:
+ num_primitives = count / 3;
+ break;
+ case GL_QUAD_STRIP:
+ num_primitives = count >= 4 ? ((count / 2) - 1) * 2 : 0;
+ break;
+ case GL_QUADS:
+ num_primitives = (count / 4) * 2;
+ break;
+ case GL_LINES_ADJACENCY:
+ num_primitives = count / 4;
+ break;
+ case GL_LINE_STRIP_ADJACENCY:
+ num_primitives = count >= 4 ? count - 3 : 0;
+ break;
+ case GL_TRIANGLES_ADJACENCY:
+ num_primitives = count / 6;
+ break;
+ case GL_TRIANGLE_STRIP_ADJACENCY:
+ num_primitives = count >= 6 ? (count - 4) / 2 : 0;
+ break;
+ default:
+ assert(!"Unexpected primitive type in count_tessellated_primitives");
+ num_primitives = 0;
+ break;
+ }
+ return num_primitives * num_instances;
+}
+
+
+static bool
+validate_draw_arrays(struct gl_context *ctx, const char *func,
+ GLenum mode, GLsizei count, GLsizei numInstances)
+{
+ FLUSH_CURRENT(ctx, 0);
+
+ if (count < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(count)", func);
+ return false;
+ }
+
+ if (!_mesa_valid_prim_mode(ctx, mode, func))
+ return false;
+
+ if (!check_valid_to_render(ctx, func))
+ return false;
+
+ if (need_xfb_remaining_prims_check(ctx)) {
+ struct gl_transform_feedback_object *xfb_obj
+ = ctx->TransformFeedback.CurrentObject;
+ size_t prim_count = count_tessellated_primitives(mode, count, numInstances);
if (xfb_obj->GlesRemainingPrims < prim_count) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(exceeds transform feedback size)", func);
}
+/**
+ * Called to error check the function parameters.
+ *
+ * Note that glMultiDrawArrays is not part of GLES, so there's limited scope
+ * for sharing code with the validation of glDrawArrays.
+ */
+bool
+_mesa_validate_MultiDrawArrays(struct gl_context *ctx, GLenum mode,
+ const GLsizei *count, GLsizei primcount)
+{
+ int i;
+
+ FLUSH_CURRENT(ctx, 0);
+
+ if (!_mesa_valid_prim_mode(ctx, mode, "glMultiDrawArrays"))
+ return false;
+
+ if (!check_valid_to_render(ctx, "glMultiDrawArrays"))
+ return false;
+
+ if (primcount < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glMultiDrawArrays(primcount=%d)",
+ primcount);
+ return false;
+ }
+
+ for (i = 0; i < primcount; ++i) {
+ if (count[i] < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glMultiDrawArrays(count[%d]=%d)",
+ i, count[i]);
+ return false;
+ }
+ }
+
+ if (need_xfb_remaining_prims_check(ctx)) {
+ struct gl_transform_feedback_object *xfb_obj
+ = ctx->TransformFeedback.CurrentObject;
+ size_t xfb_prim_count = 0;
+
+ for (i = 0; i < primcount; ++i)
+ xfb_prim_count += count_tessellated_primitives(mode, count[i], 1);
+
+ if (xfb_obj->GlesRemainingPrims < xfb_prim_count) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glMultiDrawArrays(exceeds transform feedback size)");
+ return false;
+ }
+ xfb_obj->GlesRemainingPrims -= xfb_prim_count;
+ }
+
+ return true;
+}
+
+
GLboolean
_mesa_validate_DrawElementsInstanced(struct gl_context *ctx,
GLenum mode, GLsizei count, GLenum type,
return valid_draw_indirect_parameters(
ctx, "glMultiDrawElementsIndirectCountARB", drawcount);
}
-
-static bool
-check_valid_to_compute(struct gl_context *ctx, const char *function)
-{
- struct gl_shader_program *prog;
-
- if (!_mesa_has_compute_shaders(ctx)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "unsupported function (%s) called",
- function);
- return false;
- }
-
- /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders:
- *
- * "An INVALID_OPERATION error is generated if there is no active program
- * for the compute shader stage."
- */
- prog = ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE];
- if (prog == NULL || prog->_LinkedShaders[MESA_SHADER_COMPUTE] == NULL) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(no active compute shader)",
- function);
- return false;
- }
-
- return true;
-}
-
-GLboolean
-_mesa_validate_DispatchCompute(struct gl_context *ctx,
- const GLuint *num_groups)
-{
- struct gl_shader_program *prog;
- int i;
- FLUSH_CURRENT(ctx, 0);
-
- if (!check_valid_to_compute(ctx, "glDispatchCompute"))
- return GL_FALSE;
-
- for (i = 0; i < 3; i++) {
- /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders:
- *
- * "An INVALID_VALUE error is generated if any of num_groups_x,
- * num_groups_y and num_groups_z are greater than or equal to the
- * maximum work group count for the corresponding dimension."
- *
- * However, the "or equal to" portions appears to be a specification
- * bug. In all other areas, the specification appears to indicate that
- * the number of workgroups can match the MAX_COMPUTE_WORK_GROUP_COUNT
- * value. For example, under DispatchComputeIndirect:
- *
- * "If any of num_groups_x, num_groups_y or num_groups_z is greater than
- * the value of MAX_COMPUTE_WORK_GROUP_COUNT for the corresponding
- * dimension then the results are undefined."
- *
- * Additionally, the OpenGLES 3.1 specification does not contain "or
- * equal to" as an error condition.
- */
- if (num_groups[i] > ctx->Const.MaxComputeWorkGroupCount[i]) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glDispatchCompute(num_groups_%c)", 'x' + i);
- return GL_FALSE;
- }
- }
-
- /* The ARB_compute_variable_group_size spec says:
- *
- * "An INVALID_OPERATION error is generated by DispatchCompute if the active
- * program for the compute shader stage has a variable work group size."
- */
- prog = ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE];
- if (prog->Comp.LocalSizeVariable) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glDispatchCompute(variable work group size forbidden)");
- return GL_FALSE;
- }
-
- return GL_TRUE;
-}
-
-GLboolean
-_mesa_validate_DispatchComputeGroupSizeARB(struct gl_context *ctx,
- const GLuint *num_groups,
- const GLuint *group_size)
-{
- struct gl_shader_program *prog;
- GLuint total_invocations = 1;
- int i;
-
- FLUSH_CURRENT(ctx, 0);
-
- if (!check_valid_to_compute(ctx, "glDispatchComputeGroupSizeARB"))
- return GL_FALSE;
-
- /* The ARB_compute_variable_group_size spec says:
- *
- * "An INVALID_OPERATION error is generated by
- * DispatchComputeGroupSizeARB if the active program for the compute
- * shader stage has a fixed work group size."
- */
- prog = ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE];
- if (!prog->Comp.LocalSizeVariable) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glDispatchComputeGroupSizeARB(fixed work group size "
- "forbidden)");
- return GL_FALSE;
- }
-
- for (i = 0; i < 3; i++) {
- /* The ARB_compute_variable_group_size spec says:
- *
- * "An INVALID_VALUE error is generated if any of num_groups_x,
- * num_groups_y and num_groups_z are greater than or equal to the
- * maximum work group count for the corresponding dimension."
- */
- if (num_groups[i] > ctx->Const.MaxComputeWorkGroupCount[i]) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glDispatchComputeGroupSizeARB(num_groups_%c)", 'x' + i);
- return GL_FALSE;
- }
-
- /* The ARB_compute_variable_group_size spec says:
- *
- * "An INVALID_VALUE error is generated by DispatchComputeGroupSizeARB if
- * any of <group_size_x>, <group_size_y>, or <group_size_z> is less than
- * or equal to zero or greater than the maximum local work group size
- * for compute shaders with variable group size
- * (MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB) in the corresponding
- * dimension."
- *
- * However, the "less than" is a spec bug because they are declared as
- * unsigned integers.
- */
- if (group_size[i] == 0 ||
- group_size[i] > ctx->Const.MaxComputeVariableGroupSize[i]) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glDispatchComputeGroupSizeARB(group_size_%c)", 'x' + i);
- return GL_FALSE;
- }
-
- total_invocations *= group_size[i];
- }
-
- /* The ARB_compute_variable_group_size spec says:
- *
- * "An INVALID_VALUE error is generated by DispatchComputeGroupSizeARB if
- * the product of <group_size_x>, <group_size_y>, and <group_size_z> exceeds
- * the implementation-dependent maximum local work group invocation count
- * for compute shaders with variable group size
- * (MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB)."
- */
- if (total_invocations > ctx->Const.MaxComputeVariableGroupInvocations) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glDispatchComputeGroupSizeARB(product of local_sizes "
- "exceeds MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB "
- "(%d > %d))", total_invocations,
- ctx->Const.MaxComputeVariableGroupInvocations);
- return GL_FALSE;
- }
-
- return GL_TRUE;
-}
-
-static GLboolean
-valid_dispatch_indirect(struct gl_context *ctx,
- GLintptr indirect,
- GLsizei size, const char *name)
-{
- const uint64_t end = (uint64_t) indirect + size;
- struct gl_shader_program *prog;
-
- if (!check_valid_to_compute(ctx, name))
- return GL_FALSE;
-
- /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders:
- *
- * "An INVALID_VALUE error is generated if indirect is negative or is not a
- * multiple of four."
- */
- if (indirect & (sizeof(GLuint) - 1)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "%s(indirect is not aligned)", name);
- return GL_FALSE;
- }
-
- if (indirect < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "%s(indirect is less than zero)", name);
- return GL_FALSE;
- }
-
- /* From the OpenGL 4.3 Core Specification, Chapter 19, Compute Shaders:
- *
- * "An INVALID_OPERATION error is generated if no buffer is bound to the
- * DRAW_INDIRECT_BUFFER binding, or if the command would source data
- * beyond the end of the buffer object."
- */
- if (!_mesa_is_bufferobj(ctx->DispatchIndirectBuffer)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s: no buffer bound to DISPATCH_INDIRECT_BUFFER", name);
- return GL_FALSE;
- }
-
- if (_mesa_check_disallowed_mapping(ctx->DispatchIndirectBuffer)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(DISPATCH_INDIRECT_BUFFER is mapped)", name);
- return GL_FALSE;
- }
-
- if (ctx->DispatchIndirectBuffer->Size < end) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(DISPATCH_INDIRECT_BUFFER too small)", name);
- return GL_FALSE;
- }
-
- /* The ARB_compute_variable_group_size spec says:
- *
- * "An INVALID_OPERATION error is generated if the active program for the
- * compute shader stage has a variable work group size."
- */
- prog = ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE];
- if (prog->Comp.LocalSizeVariable) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(variable work group size forbidden)", name);
- return GL_FALSE;
- }
-
- return GL_TRUE;
-}
-
-GLboolean
-_mesa_validate_DispatchComputeIndirect(struct gl_context *ctx,
- GLintptr indirect)
-{
- FLUSH_CURRENT(ctx, 0);
-
- return valid_dispatch_indirect(ctx, indirect, 3 * sizeof(GLuint),
- "glDispatchComputeIndirect");
-}