}
-/**
- * Find the max index in the given element/index buffer
- */
-GLuint
-_mesa_max_buffer_index(struct gl_context *ctx, GLuint count, GLenum type,
- const void *indices,
- struct gl_buffer_object *elementBuf)
-{
- const GLubyte *map = NULL;
- GLuint max = 0;
- GLuint i;
-
- if (_mesa_is_bufferobj(elementBuf)) {
- /* elements are in a user-defined buffer object. need to map it */
- 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);
- }
-
- if (type == GL_UNSIGNED_INT) {
- for (i = 0; i < count; i++)
- if (((GLuint *) indices)[i] > max)
- max = ((GLuint *) indices)[i];
- }
- else if (type == GL_UNSIGNED_SHORT) {
- for (i = 0; i < count; i++)
- if (((GLushort *) indices)[i] > max)
- max = ((GLushort *) indices)[i];
- }
- else {
- ASSERT(type == GL_UNSIGNED_BYTE);
- for (i = 0; i < count; i++)
- if (((GLubyte *) indices)[i] > max)
- max = ((GLubyte *) indices)[i];
- }
-
- if (map) {
- ctx->Driver.UnmapBuffer(ctx, elementBuf);
- }
-
- return max;
-}
-
-
/**
* Check if OK to draw arrays/elements.
*/
-static GLboolean
+static bool
check_valid_to_render(struct gl_context *ctx, const char *function)
{
if (!_mesa_valid_to_render(ctx, function)) {
- return GL_FALSE;
+ return false;
}
switch (ctx->API) {
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.VAO->_Enabled == 0x0 || !ctx->VertexProgram._Current)
- return GL_FALSE;
+ /* For ES2, we can draw if we have a vertex program/shader). */
+ if (!ctx->VertexProgram._Current)
+ return false;
break;
case API_OPENGLES:
/* For OpenGL ES, only draw if we have vertex positions
*/
if (!ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_POS].Enabled)
- return GL_FALSE;
+ return false;
break;
- case API_OPENGL_COMPAT:
case API_OPENGL_CORE:
- {
- const struct gl_shader_program *vsProg =
- ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX];
- 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.VAO->VertexAttrib[VERT_ATTRIB_POS].Enabled ||
- ctx->Array.VAO->VertexAttrib[VERT_ATTRIB_GENERIC0].Enabled);
- }
+ /* Section 10.4 (Drawing Commands Using Vertex Arrays) of the OpenGL 4.5
+ * Core Profile spec says:
+ *
+ * "An INVALID_OPERATION error is generated if no vertex array
+ * object is bound (see section 10.3.1)."
+ */
+ if (ctx->Array.VAO == ctx->Array.DefaultVAO) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no VAO bound)", function);
+ return false;
+ }
+ /* fallthrough */
+ case API_OPENGL_COMPAT: {
+ const struct gl_shader_program *const vsProg =
+ ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX];
+ const bool haveVertexShader = (vsProg && vsProg->LinkStatus);
+ const bool 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 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:
- assert(!"Invalid API value in check_valid_to_render()");
}
- return GL_TRUE;
-}
-
-
-/**
- * Do bounds checking on array element indexes. Check that the vertices
- * pointed to by the indices don't lie outside buffer object bounds.
- * \return GL_TRUE if OK, GL_FALSE if any indexed vertex goes is out of bounds
- */
-static GLboolean
-check_index_bounds(struct gl_context *ctx, GLsizei count, GLenum type,
- const GLvoid *indices, GLint basevertex)
-{
- struct _mesa_prim prim;
- struct _mesa_index_buffer ib;
- GLuint min, max;
-
- /* Only the X Server needs to do this -- otherwise, accessing outside
- * array/BO bounds allows application termination.
- */
- if (!ctx->Const.CheckArrayBounds)
- return GL_TRUE;
-
- memset(&prim, 0, sizeof(prim));
- prim.count = count;
-
- memset(&ib, 0, sizeof(ib));
- ib.type = type;
- ib.ptr = indices;
- ib.obj = ctx->Array.VAO->ElementArrayBufferObj;
-
- vbo_get_minmax_indices(ctx, &prim, &ib, &min, &max, 1);
-
- if ((int)(min + basevertex) < 0 ||
- max + basevertex >= ctx->Array.VAO->_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.VAO->_MaxElement);
- return GL_FALSE;
+ default:
+ unreachable("Invalid API value in check_valid_to_render()");
}
- return GL_TRUE;
+ return true;
}
* TRIANGLES_ADJACENCY_ARB or TRIANGLE_STRIP_ADJACENCY_ARB.
*
*/
- if (ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY]) {
+ if (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) {
const GLenum geom_mode =
- ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY]->Geom.InputType;
+ ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->Geom.InputType;
switch (mode) {
case GL_POINTS:
valid_enum = (geom_mode == GL_POINTS);
if (_mesa_is_xfb_active_and_unpaused(ctx)) {
GLboolean pass = GL_TRUE;
- if(ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY]) {
- switch (ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY]->Geom.OutputType) {
+ if(ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]) {
+ switch (ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]->Geom.OutputType) {
case GL_POINTS:
pass = ctx->TransformFeedback.Mode == GL_POINTS;
break;
}
}
-/**
- * Error checking for glDrawElements(). Includes parameter checking
- * and VBO bounds checking.
- * \return GL_TRUE if OK to render, GL_FALSE if error found
- */
-GLboolean
-_mesa_validate_DrawElements(struct gl_context *ctx,
- GLenum mode, GLsizei count, GLenum type,
- const GLvoid *indices, GLint basevertex)
+static bool
+validate_DrawElements_common(struct gl_context *ctx,
+ GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices,
+ const char *caller)
{
- FLUSH_CURRENT(ctx, 0);
-
/* From the GLES3 specification, section 2.14.2 (Transform Feedback
* Primitive Capture):
*
*/
if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glDrawElements(transform feedback active)");
- return GL_FALSE;
+ "%s(transform feedback active)", caller);
+ return false;
}
if (count < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glDrawElements(count)" );
- return GL_FALSE;
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(count)", caller);
+ return false;
}
- if (!_mesa_valid_prim_mode(ctx, mode, "glDrawElements")) {
- return GL_FALSE;
+ if (!_mesa_valid_prim_mode(ctx, mode, caller)) {
+ return false;
}
- if (!valid_elements_type(ctx, type, "glDrawElements"))
- return GL_FALSE;
+ if (!valid_elements_type(ctx, type, caller))
+ return false;
- if (!check_valid_to_render(ctx, "glDrawElements"))
- return GL_FALSE;
+ if (!check_valid_to_render(ctx, caller))
+ return false;
/* Vertex buffer object tests */
- if (_mesa_is_bufferobj(ctx->Array.VAO->ElementArrayBufferObj)) {
+ if (_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj)) {
/* use indices in the buffer object */
/* make sure count doesn't go outside buffer bounds */
- if (index_bytes(type, count) > ctx->Array.VAO->ElementArrayBufferObj->Size) {
- _mesa_warning(ctx, "glDrawElements index out of buffer bounds");
- return GL_FALSE;
+ if (index_bytes(type, count) > ctx->Array.VAO->IndexBufferObj->Size) {
+ _mesa_warning(ctx, "%s index out of buffer bounds", caller);
+ return false;
}
}
else {
/* not using a VBO */
if (!indices)
- return GL_FALSE;
+ return false;
}
- if (!check_index_bounds(ctx, count, type, indices, basevertex))
- return GL_FALSE;
-
if (count == 0)
- return GL_FALSE;
+ return false;
- return GL_TRUE;
+ return true;
+}
+
+/**
+ * Error checking for glDrawElements(). Includes parameter checking
+ * and VBO bounds checking.
+ * \return GL_TRUE if OK to render, GL_FALSE if error found
+ */
+GLboolean
+_mesa_validate_DrawElements(struct gl_context *ctx,
+ GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices)
+{
+ FLUSH_CURRENT(ctx, 0);
+
+ return validate_DrawElements_common(ctx, mode, count, type, indices,
+ "glDrawElements");
}
_mesa_validate_MultiDrawElements(struct gl_context *ctx,
GLenum mode, const GLsizei *count,
GLenum type, const GLvoid * const *indices,
- GLuint primcount, const GLint *basevertex)
+ GLuint primcount)
{
unsigned i;
return GL_FALSE;
/* Vertex buffer object tests */
- if (_mesa_is_bufferobj(ctx->Array.VAO->ElementArrayBufferObj)) {
+ if (_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj)) {
/* 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.VAO->ElementArrayBufferObj->Size) {
+ ctx->Array.VAO->IndexBufferObj->Size) {
_mesa_warning(ctx,
"glMultiDrawElements index out of buffer bounds");
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;
}
_mesa_validate_DrawRangeElements(struct gl_context *ctx, GLenum mode,
GLuint start, GLuint end,
GLsizei count, GLenum type,
- const GLvoid *indices, GLint basevertex)
+ const GLvoid *indices)
{
FLUSH_CURRENT(ctx, 0);
- /* From the GLES3 specification, section 2.14.2 (Transform Feedback
- * Primitive Capture):
- *
- * The error INVALID_OPERATION is also generated by DrawElements,
- * DrawElementsInstanced, and DrawRangeElements while transform feedback
- * is active and not paused, regardless of mode.
- */
- if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glDrawElements(transform feedback active)");
- return GL_FALSE;
- }
-
- if (count < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(count)" );
- return GL_FALSE;
- }
-
- if (!_mesa_valid_prim_mode(ctx, mode, "glDrawRangeElements")) {
- return GL_FALSE;
- }
-
if (end < start) {
_mesa_error(ctx, GL_INVALID_VALUE, "glDrawRangeElements(end<start)");
return GL_FALSE;
}
- 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.VAO->ElementArrayBufferObj)) {
- /* use indices in the buffer object */
- /* make sure count doesn't go outside buffer bounds */
- if (index_bytes(type, count) > ctx->Array.VAO->ElementArrayBufferObj->Size) {
- _mesa_warning(ctx, "glDrawRangeElements index out of buffer bounds");
- return GL_FALSE;
- }
- }
- else {
- /* not using a VBO */
- if (!indices)
- return GL_FALSE;
- }
-
- if (!check_index_bounds(ctx, count, type, indices, basevertex))
- return GL_FALSE;
-
- if (count == 0)
- return GL_FALSE;
-
- return GL_TRUE;
+ return validate_DrawElements_common(ctx, mode, count, type, indices,
+ "glDrawRangeElements");
}
* \return GL_TRUE if OK to render, GL_FALSE if error found
*/
GLboolean
-_mesa_validate_DrawArrays(struct gl_context *ctx,
- GLenum mode, GLint start, GLsizei count)
+_mesa_validate_DrawArrays(struct gl_context *ctx, GLenum mode, GLsizei count)
{
struct gl_transform_feedback_object *xfb_obj
= ctx->TransformFeedback.CurrentObject;
if (!check_valid_to_render(ctx, "glDrawArrays"))
return GL_FALSE;
- if (ctx->Const.CheckArrayBounds) {
- if (start + count > (GLint) ctx->Array.VAO->_MaxElement)
- return GL_FALSE;
- }
-
/* From the GLES3 specification, section 2.14.2 (Transform Feedback
* Primitive Capture):
*
if (!check_valid_to_render(ctx, "glDrawArraysInstanced(invalid to render)"))
return GL_FALSE;
- if (ctx->Const.CheckArrayBounds) {
- if (first + count > (GLint) ctx->Array.VAO->_MaxElement)
- return GL_FALSE;
- }
-
/* From the GLES3 specification, section 2.14.2 (Transform Feedback
* Primitive Capture):
*
GLboolean
_mesa_validate_DrawElementsInstanced(struct gl_context *ctx,
GLenum mode, GLsizei count, GLenum type,
- const GLvoid *indices, GLsizei numInstances,
- GLint basevertex)
+ const GLvoid *indices, GLsizei numInstances)
{
FLUSH_CURRENT(ctx, 0);
- /* From the GLES3 specification, section 2.14.2 (Transform Feedback
- * Primitive Capture):
- *
- * The error INVALID_OPERATION is also generated by DrawElements,
- * DrawElementsInstanced, and DrawRangeElements while transform feedback
- * is active and not paused, regardless of mode.
- */
- if (_mesa_is_gles3(ctx) && _mesa_is_xfb_active_and_unpaused(ctx)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glDrawElements(transform feedback active)");
- return GL_FALSE;
- }
-
- if (count < 0) {
+ if (numInstances < 0) {
_mesa_error(ctx, GL_INVALID_VALUE,
- "glDrawElementsInstanced(count=%d)", count);
- return GL_FALSE;
- }
-
- if (!_mesa_valid_prim_mode(ctx, mode, "glDrawElementsInstanced")) {
- return GL_FALSE;
- }
-
- if (!valid_elements_type(ctx, type, "glDrawElementsInstanced"))
- return GL_FALSE;
-
- if (numInstances <= 0) {
- if (numInstances < 0)
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glDrawElementsInstanced(numInstances=%d)", numInstances);
+ "glDrawElementsInstanced(numInstances=%d)", numInstances);
return GL_FALSE;
}
- if (!check_valid_to_render(ctx, "glDrawElementsInstanced"))
- return GL_FALSE;
-
- /* Vertex buffer object tests */
- if (_mesa_is_bufferobj(ctx->Array.VAO->ElementArrayBufferObj)) {
- /* use indices in the buffer object */
- /* make sure count doesn't go outside buffer bounds */
- if (index_bytes(type, count) > ctx->Array.VAO->ElementArrayBufferObj->Size) {
- _mesa_warning(ctx,
- "glDrawElementsInstanced index out of buffer bounds");
- return GL_FALSE;
- }
- }
- else {
- /* not using a VBO */
- if (!indices)
- return GL_FALSE;
- }
-
- if (count == 0)
- return GL_FALSE;
-
- if (!check_index_bounds(ctx, count, type, indices, basevertex))
- return GL_FALSE;
-
- return GL_TRUE;
+ return validate_DrawElements_common(ctx, mode, count, type, indices,
+ "glDrawElementsInstanced")
+ && (numInstances > 0);
}
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 (!obj->EndedAnytime) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawTransformFeedback*");
+ return GL_FALSE;
+ }
+
if (numInstances <= 0) {
if (numInstances < 0)
_mesa_error(ctx, GL_INVALID_VALUE,
return GL_FALSE;
}
- if (_mesa_bufferobj_mapped(ctx->DrawIndirectBuffer)) {
+ if (_mesa_check_disallowed_mapping(ctx->DrawIndirectBuffer)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(DRAW_INDIRECT_BUFFER is mapped)", name);
return GL_FALSE;
* If no element array buffer is bound, an INVALID_OPERATION error is
* generated.
*/
- if (!_mesa_is_bufferobj(ctx->Array.VAO->ElementArrayBufferObj)) {
+ if (!_mesa_is_bufferobj(ctx->Array.VAO->IndexBufferObj)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(no buffer bound to GL_ELEMENT_ARRAY_BUFFER)", name);
return GL_FALSE;