X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmesa%2Fmain%2Fapi_validate.c;h=6f025080038c534f43e49876cacf9c45d1b7dbb8;hb=27d70b7266cc5e8562b4cccae763976834eb0ce2;hp=4929a9310d48a43243ae9ba8ee17e856ee4118f2;hpb=0072acd447dc6be652e63752e50215c3105322c8;p=mesa.git diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c index 4929a9310d4..6f025080038 100644 --- a/src/mesa/main/api_validate.c +++ b/src/mesa/main/api_validate.c @@ -22,13 +22,17 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include "glheader.h" #include "api_validate.h" #include "bufferobj.h" #include "context.h" #include "imports.h" +#include "mfeatures.h" #include "mtypes.h" +#include "enums.h" #include "vbo/vbo.h" +#include /** @@ -64,8 +68,8 @@ _mesa_max_buffer_index(struct gl_context *ctx, GLuint count, GLenum type, if (_mesa_is_bufferobj(elementBuf)) { /* elements are in a user-defined buffer object. need to map it */ - map = ctx->Driver.MapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, - GL_READ_ONLY, elementBuf); + map = ctx->Driver.MapBufferRange(ctx, 0, elementBuf->Size, + GL_MAP_READ_BIT, elementBuf); /* Actual address is the sum of pointers */ indices = (const GLvoid *) ADD_POINTERS(map, (const GLubyte *) indices); } @@ -88,7 +92,7 @@ _mesa_max_buffer_index(struct gl_context *ctx, GLuint count, GLenum type, } if (map) { - ctx->Driver.UnmapBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, elementBuf); + ctx->Driver.UnmapBuffer(ctx, elementBuf); } return max; @@ -106,28 +110,45 @@ check_valid_to_render(struct gl_context *ctx, const char *function) } switch (ctx->API) { -#if FEATURE_es2_glsl case API_OPENGLES2: /* For ES2, we can draw if any vertex array is enabled (and we * should always have a vertex program/shader). */ if (ctx->Array.ArrayObj->_Enabled == 0x0 || !ctx->VertexProgram._Current) return GL_FALSE; break; -#endif -#if FEATURE_ES1 || FEATURE_GL case API_OPENGLES: - case API_OPENGL: - /* For regular OpenGL, only draw if we have vertex positions - * (regardless of whether or not we have a vertex program/shader). */ - if (!ctx->Array.ArrayObj->Vertex.Enabled && - !ctx->Array.ArrayObj->VertexAttrib[0].Enabled) + /* For OpenGL ES, only draw if we have vertex positions + */ + if (!ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled) return GL_FALSE; break; -#endif + + case API_OPENGL: + case API_OPENGL_CORE: + { + const struct gl_shader_program *vsProg = + ctx->Shader.CurrentVertexProgram; + GLboolean haveVertexShader = (vsProg && vsProg->LinkStatus); + GLboolean haveVertexProgram = ctx->VertexProgram._Enabled; + if (haveVertexShader || haveVertexProgram) { + /* Draw regardless of whether or not we have any vertex arrays. + * (Ex: could draw a point using a constant vertex pos) + */ + return GL_TRUE; + } + else { + /* Draw if we have vertex positions (GL_VERTEX_ARRAY or generic + * array [0]). + */ + return (ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_POS].Enabled || + ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled); + } + } + break; default: - ASSERT_NO_FEATURE(); + assert(!"Invalid API value in check_valid_to_render()"); } return GL_TRUE; @@ -159,12 +180,12 @@ check_index_bounds(struct gl_context *ctx, GLsizei count, GLenum type, memset(&ib, 0, sizeof(ib)); ib.type = type; ib.ptr = indices; - ib.obj = ctx->Array.ElementArrayBufferObj; + ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj; - vbo_get_minmax_index(ctx, &prim, &ib, &min, &max); + vbo_get_minmax_indices(ctx, &prim, &ib, &min, &max, 1); if ((int)(min + basevertex) < 0 || - max + basevertex > ctx->Array.ArrayObj->_MaxElement) { + max + basevertex >= ctx->Array.ArrayObj->_MaxElement) { /* the max element is out of bounds of one or more enabled arrays */ _mesa_warning(ctx, "glDrawElements() index=%u is out of bounds (max=%u)", max, ctx->Array.ArrayObj->_MaxElement); @@ -175,6 +196,113 @@ check_index_bounds(struct gl_context *ctx, GLsizei count, GLenum type, } +/** + * Is 'mode' a valid value for glBegin(), glDrawArrays(), glDrawElements(), + * etc? The set of legal values depends on whether geometry shaders/programs + * are supported. + */ +GLboolean +_mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name) +{ + bool valid_enum; + + switch (mode) { + case GL_POINTS: + case GL_LINES: + case GL_LINE_LOOP: + case GL_LINE_STRIP: + case GL_TRIANGLES: + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + valid_enum = true; + break; + case GL_QUADS: + case GL_QUAD_STRIP: + case GL_POLYGON: + valid_enum = (ctx->API == API_OPENGL); + break; + case GL_LINES_ADJACENCY: + case GL_LINE_STRIP_ADJACENCY: + case GL_TRIANGLES_ADJACENCY: + case GL_TRIANGLE_STRIP_ADJACENCY: + valid_enum = _mesa_is_desktop_gl(ctx) + && ctx->Extensions.ARB_geometry_shader4; + break; + default: + valid_enum = false; + break; + } + + if (!valid_enum) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(mode=%x)", name, mode); + return GL_FALSE; + } + + /* From the GL_EXT_transform_feedback spec: + * + * "The error INVALID_OPERATION is generated if Begin, or any command + * that performs an explicit Begin, is called when: + * + * * a geometry shader is not active and does not match the + * allowed begin modes for the current transform feedback state as + * given by table X.1. + * + * * a geometry shader is active and the output primitive type of the + * geometry shader does not match the allowed begin modes for the + * current transform feedback state as given by table X.1. + * + */ + if (ctx->TransformFeedback.CurrentObject->Active && + !ctx->TransformFeedback.CurrentObject->Paused) { + GLboolean pass = GL_TRUE; + + switch (mode) { + case GL_POINTS: + pass = ctx->TransformFeedback.Mode == GL_POINTS; + break; + case GL_LINES: + case GL_LINE_STRIP: + case GL_LINE_LOOP: + pass = ctx->TransformFeedback.Mode == GL_LINES; + break; + default: + pass = ctx->TransformFeedback.Mode == GL_TRIANGLES; + break; + } + if (!pass) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(mode=%s vs transform feedback %s)", + name, + _mesa_lookup_prim_by_nr(mode), + _mesa_lookup_prim_by_nr(ctx->TransformFeedback.Mode)); + return GL_FALSE; + } + } + + return GL_TRUE; +} + +/** + * Verify that the element type is valid. + * + * Generates \c GL_INVALID_ENUM and returns \c false if it is not. + */ +static bool +valid_elements_type(struct gl_context *ctx, GLenum type, const char *name) +{ + switch (type) { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + return true; + + default: + _mesa_error(ctx, GL_INVALID_ENUM, "%s(type = %s)", name, + _mesa_lookup_enum_by_nr(type)); + return false; + } +} + /** * Error checking for glDrawElements(). Includes parameter checking * and VBO bounds checking. @@ -186,6 +314,7 @@ _mesa_validate_DrawElements(struct gl_context *ctx, const GLvoid *indices, GLint basevertex) { ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + FLUSH_CURRENT(ctx, 0); if (count <= 0) { if (count < 0) @@ -193,27 +322,21 @@ _mesa_validate_DrawElements(struct gl_context *ctx, return GL_FALSE; } - if (mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) { - _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)" ); + if (!_mesa_valid_prim_mode(ctx, mode, "glDrawElements")) { return GL_FALSE; } - if (type != GL_UNSIGNED_INT && - type != GL_UNSIGNED_BYTE && - type != GL_UNSIGNED_SHORT) - { - _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)" ); + if (!valid_elements_type(ctx, type, "glDrawElements")) return GL_FALSE; - } if (!check_valid_to_render(ctx, "glDrawElements")) return GL_FALSE; /* Vertex buffer object tests */ - if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) { + if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) { /* use indices in the buffer object */ /* make sure count doesn't go outside buffer bounds */ - if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) { + if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) { _mesa_warning(ctx, "glDrawElements index out of buffer bounds"); return GL_FALSE; } @@ -231,6 +354,72 @@ _mesa_validate_DrawElements(struct gl_context *ctx, } +/** + * Error checking for glMultiDrawElements(). Includes parameter checking + * and VBO bounds checking. + * \return GL_TRUE if OK to render, GL_FALSE if error found + */ +GLboolean +_mesa_validate_MultiDrawElements(struct gl_context *ctx, + GLenum mode, const GLsizei *count, + GLenum type, const GLvoid * const *indices, + GLuint primcount, const GLint *basevertex) +{ + unsigned i; + + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + FLUSH_CURRENT(ctx, 0); + + for (i = 0; i < primcount; i++) { + if (count[i] <= 0) { + if (count[i] < 0) + _mesa_error(ctx, GL_INVALID_VALUE, + "glMultiDrawElements(count)" ); + return GL_FALSE; + } + } + + if (!_mesa_valid_prim_mode(ctx, mode, "glMultiDrawElements")) { + return GL_FALSE; + } + + if (!valid_elements_type(ctx, type, "glMultiDrawElements")) + return GL_FALSE; + + if (!check_valid_to_render(ctx, "glMultiDrawElements")) + return GL_FALSE; + + /* Vertex buffer object tests */ + if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) { + /* use indices in the buffer object */ + /* make sure count doesn't go outside buffer bounds */ + for (i = 0; i < primcount; i++) { + if (index_bytes(type, count[i]) > + ctx->Array.ArrayObj->ElementArrayBufferObj->Size) { + _mesa_warning(ctx, + "glMultiDrawElements index out of buffer bounds"); + return GL_FALSE; + } + } + } + else { + /* not using a VBO */ + for (i = 0; i < primcount; i++) { + if (!indices[i]) + return GL_FALSE; + } + } + + for (i = 0; i < primcount; i++) { + if (!check_index_bounds(ctx, count[i], type, indices[i], + basevertex ? basevertex[i] : 0)) + return GL_FALSE; + } + + return GL_TRUE; +} + + /** * Error checking for glDrawRangeElements(). Includes parameter checking * and VBO bounds checking. @@ -243,6 +432,7 @@ _mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode, const GLvoid *indices, GLint basevertex) { ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + FLUSH_CURRENT(ctx, 0); if (count <= 0) { if (count < 0) @@ -250,8 +440,7 @@ _mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode, return GL_FALSE; } - if (mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) { - _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)" ); + if (!_mesa_valid_prim_mode(ctx, mode, "glDrawRangeElements")) { return GL_FALSE; } @@ -260,21 +449,17 @@ _mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode, return GL_FALSE; } - if (type != GL_UNSIGNED_INT && - type != GL_UNSIGNED_BYTE && - type != GL_UNSIGNED_SHORT) { - _mesa_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)" ); + if (!valid_elements_type(ctx, type, "glDrawRangeElements")) return GL_FALSE; - } if (!check_valid_to_render(ctx, "glDrawRangeElements")) return GL_FALSE; /* Vertex buffer object tests */ - if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) { + if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) { /* use indices in the buffer object */ /* make sure count doesn't go outside buffer bounds */ - if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) { + if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) { _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds"); return GL_FALSE; } @@ -302,6 +487,7 @@ _mesa_validate_DrawArrays(struct gl_context *ctx, GLenum mode, GLint start, GLsizei count) { ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + FLUSH_CURRENT(ctx, 0); if (count <= 0) { if (count < 0) @@ -309,8 +495,7 @@ _mesa_validate_DrawArrays(struct gl_context *ctx, return GL_FALSE; } - if (mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) { - _mesa_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)" ); + if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArrays")) { return GL_FALSE; } @@ -328,9 +513,10 @@ _mesa_validate_DrawArrays(struct gl_context *ctx, GLboolean _mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint first, - GLsizei count, GLsizei primcount) + GLsizei count, GLsizei numInstances) { ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + FLUSH_CURRENT(ctx, 0); if (count <= 0) { if (count < 0) @@ -339,27 +525,25 @@ _mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint fi return GL_FALSE; } - if (mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glDrawArraysInstanced(mode=0x%x)", mode); + if (first < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glDrawArraysInstanced(start=%d)", first); return GL_FALSE; } - if (primcount <= 0) { - if (primcount < 0) - _mesa_error(ctx, GL_INVALID_VALUE, - "glDrawArraysInstanced(primcount=%d)", primcount); + if (!_mesa_valid_prim_mode(ctx, mode, "glDrawArraysInstanced")) { return GL_FALSE; } - if (!check_valid_to_render(ctx, "glDrawArraysInstanced(invalid to render)")) + if (numInstances <= 0) { + if (numInstances < 0) + _mesa_error(ctx, GL_INVALID_VALUE, + "glDrawArraysInstanced(numInstances=%d)", numInstances); return GL_FALSE; + } - if (ctx->CompileFlag) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glDrawArraysInstanced(display list"); + if (!check_valid_to_render(ctx, "glDrawArraysInstanced(invalid to render)")) return GL_FALSE; - } if (ctx->Const.CheckArrayBounds) { if (first + count > (GLint) ctx->Array.ArrayObj->_MaxElement) @@ -373,9 +557,11 @@ _mesa_validate_DrawArraysInstanced(struct gl_context *ctx, GLenum mode, GLint fi GLboolean _mesa_validate_DrawElementsInstanced(struct gl_context *ctx, GLenum mode, GLsizei count, GLenum type, - const GLvoid *indices, GLsizei primcount) + const GLvoid *indices, GLsizei numInstances, + GLint basevertex) { ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + FLUSH_CURRENT(ctx, 0); if (count <= 0) { if (count < 0) @@ -384,24 +570,17 @@ _mesa_validate_DrawElementsInstanced(struct gl_context *ctx, return GL_FALSE; } - if (mode > GL_TRIANGLE_STRIP_ADJACENCY_ARB) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glDrawElementsInstanced(mode = 0x%x)", mode); + if (!_mesa_valid_prim_mode(ctx, mode, "glDrawElementsInstanced")) { return GL_FALSE; } - if (type != GL_UNSIGNED_INT && - type != GL_UNSIGNED_BYTE && - type != GL_UNSIGNED_SHORT) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glDrawElementsInstanced(type=0x%x)", type); + if (!valid_elements_type(ctx, type, "glDrawElementsInstanced")) return GL_FALSE; - } - if (primcount <= 0) { - if (primcount < 0) + if (numInstances <= 0) { + if (numInstances < 0) _mesa_error(ctx, GL_INVALID_VALUE, - "glDrawElementsInstanced(primcount=%d)", primcount); + "glDrawElementsInstanced(numInstances=%d)", numInstances); return GL_FALSE; } @@ -409,10 +588,10 @@ _mesa_validate_DrawElementsInstanced(struct gl_context *ctx, return GL_FALSE; /* Vertex buffer object tests */ - if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj)) { + if (_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) { /* use indices in the buffer object */ /* make sure count doesn't go outside buffer bounds */ - if (index_bytes(type, count) > ctx->Array.ElementArrayBufferObj->Size) { + if (index_bytes(type, count) > ctx->Array.ArrayObj->ElementArrayBufferObj->Size) { _mesa_warning(ctx, "glDrawElementsInstanced index out of buffer bounds"); return GL_FALSE; @@ -424,8 +603,54 @@ _mesa_validate_DrawElementsInstanced(struct gl_context *ctx, return GL_FALSE; } - if (!check_index_bounds(ctx, count, type, indices, 0)) + if (!check_index_bounds(ctx, count, type, indices, basevertex)) return GL_FALSE; return GL_TRUE; } + + +GLboolean +_mesa_validate_DrawTransformFeedback(struct gl_context *ctx, + GLenum mode, + struct gl_transform_feedback_object *obj, + GLuint stream, + GLsizei numInstances) +{ + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); + FLUSH_CURRENT(ctx, 0); + + if (!_mesa_valid_prim_mode(ctx, mode, "glDrawTransformFeedback*(mode)")) { + return GL_FALSE; + } + + if (!obj) { + _mesa_error(ctx, GL_INVALID_VALUE, "glDrawTransformFeedback*(name)"); + return GL_FALSE; + } + + if (!obj->EndedAnytime) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawTransformFeedback*"); + return GL_FALSE; + } + + if (stream >= ctx->Const.MaxVertexStreams) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glDrawTransformFeedbackStream*(index>=MaxVertexStream)"); + return GL_FALSE; + } + + if (numInstances <= 0) { + if (numInstances < 0) + _mesa_error(ctx, GL_INVALID_VALUE, + "glDrawTransformFeedback*Instanced(numInstances=%d)", + numInstances); + return GL_FALSE; + } + + if (!check_valid_to_render(ctx, "glDrawTransformFeedback*")) { + return GL_FALSE; + } + + return GL_TRUE; +}