v2: Removed some stray extern qualifiers. Documented use of Draw*IndirectCommand sizes.
Removed separate extension enable flag for ARB_multi_draw_indirect since this can always be supported by looping. Kept generation of GL_INVALID_OPERATION in display list compile. The spec doesn't say anything about them, but all the direct drawing commands that support instancing do the same. --- src/mapi/glapi/gen/Makefile.am | 1 + src/mapi/glapi/gen/gl_API.xml | 4 +- src/mesa/main/api_validate.c | 153 +++++++++++++++++++ src/mesa/main/api_validate.h | 26 ++++ src/mesa/main/bufferobj.c | 9 + src/mesa/main/dd.h | 12 ++ src/mesa/main/dlist.c | 41 +++++ src/mesa/main/extensions.c | 2 + src/mesa/main/get.c | 5 + src/mesa/main/get_hash_params.py | 2 + src/mesa/main/mtypes.h | 3 + src/mesa/main/tests/dispatch_sanity.cpp | 8 +- src/mesa/main/vtxfmt.c | 7 + src/mesa/vbo/vbo_exec_array.c | 249 +++++++++++++++++++++++++++++++ src/mesa/vbo/vbo_save_api.c | 53 +++++++ 15 files changed, 570 insertions(+), 5 deletions(-) diff --git a/src/mapi/glapi/gen/Makefile.am b/src/mapi/glapi/gen/Makefile.am index 36e47e2..243c148 100644 --- a/src/mapi/glapi/gen/Makefile.am +++ b/src/mapi/glapi/gen/Makefile.am @@ -96,6 +96,7 @@ API_XML = \ ARB_depth_clamp.xml \ ARB_draw_buffers_blend.xml \ ARB_draw_elements_base_vertex.xml \ + ARB_draw_indirect.xml \ ARB_draw_instanced.xml \ ARB_ES2_compatibility.xml \ ARB_ES3_compatibility.xml \ diff --git a/src/mapi/glapi/gen/gl_API.xml b/src/mapi/glapi/gen/gl_API.xml index df95924..f22fdac 100644 --- a/src/mapi/glapi/gen/gl_API.xml +++ b/src/mapi/glapi/gen/gl_API.xml @@ -8240,6 +8240,8 @@ <!-- ARB extensions #86...#93 --> +<xi:include href="ARB_draw_indirect.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/> + <category name="GL_ARB_transform_feedback3" number="94"> <enum name="MAX_TRANSFORM_FEEDBACK_BUFFERS" value="0x8E70"/> <enum name="MAX_VERTEX_STREAMS" value="0x8E71"/> @@ -8317,7 +8319,7 @@ <xi:include href="ARB_invalidate_subdata.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/> -<!-- ARB extensions #133...#138 --> +<!-- ARB extensions #134...#138 --> <xi:include href="ARB_texture_buffer_range.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/> diff --git a/src/mesa/main/api_validate.c b/src/mesa/main/api_validate.c index 53b0021..e875c5d 100644 --- a/src/mesa/main/api_validate.c +++ b/src/mesa/main/api_validate.c @@ -737,3 +737,156 @@ _mesa_validate_DrawTransformFeedback(struct gl_context *ctx, return GL_TRUE; } + +static GLboolean +valid_draw_indirect(struct gl_context *ctx, + GLenum mode, const GLvoid *indirect, + GLsizei size, const char *name) +{ + const GLsizeiptr end = (GLsizeiptr)indirect + size; + + if (!_mesa_valid_prim_mode(ctx, mode, name)) + return GL_FALSE; + + if ((GLsizeiptr)indirect & (sizeof(GLuint) - 1)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(indirect is not aligned)", name); + return GL_FALSE; + } + + if (_mesa_is_bufferobj(ctx->DrawIndirectBuffer)) { + if (_mesa_bufferobj_mapped(ctx->DrawIndirectBuffer)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(DRAW_INDIRECT_BUFFER is mapped)", name); + return GL_FALSE; + } + if (ctx->DrawIndirectBuffer->Size < end) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(DRAW_INDIRECT_BUFFER too small)", name); + return GL_FALSE; + } + } else { + if (ctx->API != API_OPENGL_COMPAT) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s: no buffer bound to DRAW_INDIRECT_BUFFER", name); + return GL_FALSE; + } + } + + if (!check_valid_to_render(ctx, name)) + return GL_FALSE; + + return GL_TRUE; +} + +static inline GLboolean +valid_draw_indirect_elements(struct gl_context *ctx, + GLenum mode, GLenum type, const GLvoid *indirect, + GLsizeiptr size, const char *name) +{ + if (!valid_elements_type(ctx, type, name)) + return GL_FALSE; + + /* + * Unlike regular DrawElementsInstancedBaseVertex commands, the indices + * may not come from a client array and must come from an index buffer. + * If no element array buffer is bound, an INVALID_OPERATION error is + * generated. + */ + if (!_mesa_is_bufferobj(ctx->Array.ArrayObj->ElementArrayBufferObj)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(no buffer bound to GL_ELEMENT_ARRAY_BUFFER)", name); + return GL_FALSE; + } + + return valid_draw_indirect(ctx, mode, indirect, size, name); +} + +static inline GLboolean +valid_draw_indirect_multi(struct gl_context *ctx, + GLsizei primcount, GLsizei stride, + const char *name) +{ + if (primcount < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(primcount < 0)", name); + return GL_FALSE; + } + + if (stride % 4) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(stride %% 4)", name); + return GL_FALSE; + } + + return GL_TRUE; +} + +GLboolean +_mesa_validate_DrawArraysIndirect(struct gl_context *ctx, + GLenum mode, + const GLvoid *indirect) +{ + FLUSH_CURRENT(ctx, 0); + + return valid_draw_indirect(ctx, mode, + indirect, 4 * sizeof(GLuint), + "glDrawArraysIndirect"); +} + +GLboolean +_mesa_validate_DrawElementsIndirect(struct gl_context *ctx, + GLenum mode, GLenum type, + const GLvoid *indirect) +{ + FLUSH_CURRENT(ctx, 0); + + return valid_draw_indirect_elements(ctx, mode, type, + indirect, 5 * sizeof(GLuint), + "glDrawElementsIndirect"); +} + +GLboolean +_mesa_validate_MultiDrawArraysIndirect(struct gl_context *ctx, + GLenum mode, + const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + GLsizeiptr size = 0; + if (primcount) /* &(last command) + sizeof(DrawArraysIndirectCommand) */ + size = (primcount - 1) * stride + 4 * sizeof(GLuint); + + FLUSH_CURRENT(ctx, 0); + + if (!valid_draw_indirect_multi(ctx, primcount, stride, + "glMultiDrawArraysIndirect")) + return GL_FALSE; + + if (!valid_draw_indirect(ctx, mode, indirect, size, + "glMultiDrawArraysIndirect")) + return GL_FALSE; + + return GL_TRUE; +} + +GLboolean +_mesa_validate_MultiDrawElementsIndirect(struct gl_context *ctx, + GLenum mode, GLenum type, + const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + GLsizeiptr size = 0; + if (primcount) /* &(last command) + sizeof(DrawElementsIndirectCommand) */ + size = (primcount - 1) * stride + 5 * sizeof(GLuint); + + FLUSH_CURRENT(ctx, 0); + + if (!valid_draw_indirect_multi(ctx, primcount, stride, + "glMultiDrawElementsIndirect")) + return GL_FALSE; + + if (!valid_draw_indirect_elements(ctx, mode, type, + indirect, size, + "glMultiDrawElementsIndirect")) + return GL_FALSE; + + return GL_TRUE; +} diff --git a/src/mesa/main/api_validate.h b/src/mesa/main/api_validate.h index 0ca9c90..38c6efd 100644 --- a/src/mesa/main/api_validate.h +++ b/src/mesa/main/api_validate.h @@ -85,5 +85,31 @@ _mesa_validate_DrawTransformFeedback(struct gl_context *ctx, GLuint stream, GLsizei numInstances); +extern GLboolean +_mesa_validate_DrawArraysIndirect(struct gl_context *ctx, + GLenum mode, + const GLvoid *indirect); + +extern GLboolean +_mesa_validate_DrawElementsIndirect(struct gl_context *ctx, + GLenum mode, + GLenum type, + const GLvoid *indirect); + +extern GLboolean +_mesa_validate_MultiDrawArraysIndirect(struct gl_context *ctx, + GLenum mode, + const GLvoid *indirect, + GLsizei primcount, + GLsizei stride); + +extern GLboolean +_mesa_validate_MultiDrawElementsIndirect(struct gl_context *ctx, + GLenum mode, + GLenum type, + const GLvoid *indirect, + GLsizei primcount, + GLsizei stride); + #endif diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c index b82ba7b..0fe01d4 100644 --- a/src/mesa/main/bufferobj.c +++ b/src/mesa/main/bufferobj.c @@ -87,6 +87,10 @@ get_buffer_target(struct gl_context *ctx, GLenum target) return &ctx->CopyReadBuffer; case GL_COPY_WRITE_BUFFER: return &ctx->CopyWriteBuffer; + case GL_DRAW_INDIRECT_BUFFER: + if (ctx->Extensions.ARB_draw_indirect) + return &ctx->DrawIndirectBuffer; + break; case GL_TRANSFORM_FEEDBACK_BUFFER: if (ctx->Extensions.EXT_transform_feedback) { return &ctx->TransformFeedback.CurrentBuffer; @@ -875,6 +879,11 @@ _mesa_DeleteBuffers(GLsizei n, const GLuint *ids) _mesa_BindBuffer( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); } + /* unbind ARB_draw_indirect binding point */ + if (ctx->DrawIndirectBuffer == bufObj) { + _mesa_BindBuffer( GL_DRAW_INDIRECT_BUFFER, 0 ); + } + /* unbind ARB_copy_buffer binding points */ if (ctx->CopyReadBuffer == bufObj) { _mesa_BindBuffer( GL_COPY_READ_BUFFER, 0 ); diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h index 8f3cd3d..51a78b4 100644 --- a/src/mesa/main/dd.h +++ b/src/mesa/main/dd.h @@ -1078,6 +1078,18 @@ typedef struct { GLuint name, GLuint stream, GLsizei primcount); + void (GLAPIENTRYP DrawArraysIndirect)(GLenum mode, + const GLvoid *indirect); + void (GLAPIENTRYP DrawElementsIndirect)(GLenum mode, GLenum type, + const GLvoid *indirect); + void (GLAPIENTRYP MultiDrawArraysIndirect)(GLenum mode, + const GLvoid *indirect, + GLsizei primcount, + GLsizei stride); + void (GLAPIENTRYP MultiDrawElementsIndirect)(GLenum mode, GLenum type, + const GLvoid *indirect, + GLsizei primcount, + GLsizei stride); /*@}*/ /** diff --git a/src/mesa/main/dlist.c b/src/mesa/main/dlist.c index 4b20d89..45e7439 100644 --- a/src/mesa/main/dlist.c +++ b/src/mesa/main/dlist.c @@ -1356,6 +1356,41 @@ save_DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, "glDrawElementsInstancedBaseVertexBaseInstance() during display list compile"); } +static void GLAPIENTRY +save_DrawArraysIndirect(GLenum mode, const GLvoid *indirect) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_error(ctx, GL_INVALID_OPERATION, + "glDrawArraysIndirect() during display list compile"); +} + +static void GLAPIENTRY +save_DrawElementsIndirect(GLenum mode, GLenum type, const GLvoid *indirect) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_error(ctx, GL_INVALID_OPERATION, + "glDrawElementsIndirect() during display list compile"); +} + +static void GLAPIENTRY +save_MultiDrawArraysIndirect(GLenum mode, const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMultiDrawArraysIndirect() during display list compile"); +} + +static void GLAPIENTRY +save_MultiDrawElementsIndirect(GLenum mode, GLenum type, + const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMultiDrawElementsIndirect() during display list compile"); +} + static void invalidate_saved_current_state( struct gl_context *ctx ) { GLint i; @@ -9620,6 +9655,12 @@ _mesa_save_vtxfmt_init(GLvertexformat * vfmt) vfmt->DrawElementsInstancedBaseInstance = save_DrawElementsInstancedBaseInstance; vfmt->DrawElementsInstancedBaseVertexBaseInstance = save_DrawElementsInstancedBaseVertexBaseInstance; + /* GL_ARB_draw_indirect and GL_ARB_multi_draw_indirect */ + vfmt->DrawArraysIndirect = save_DrawArraysIndirect; + vfmt->MultiDrawArraysIndirect = save_MultiDrawArraysIndirect; + vfmt->DrawElementsIndirect = save_DrawElementsIndirect; + vfmt->MultiDrawElementsIndirect = save_MultiDrawElementsIndirect; + /* The driver is required to implement these as * 1) They can probably do a better job. * 2) A lot of new mechanisms would have to be added to this module diff --git a/src/mesa/main/extensions.c b/src/mesa/main/extensions.c index c7f038b..a124c04 100644 --- a/src/mesa/main/extensions.c +++ b/src/mesa/main/extensions.c @@ -93,6 +93,7 @@ static const struct extension extension_table[] = { { "GL_ARB_draw_buffers", o(dummy_true), GL, 2002 }, { "GL_ARB_draw_buffers_blend", o(ARB_draw_buffers_blend), GL, 2009 }, { "GL_ARB_draw_elements_base_vertex", o(ARB_draw_elements_base_vertex), GL, 2009 }, + { "GL_ARB_draw_indirect", o(ARB_draw_indirect), GLC, 2010 }, { "GL_ARB_draw_instanced", o(ARB_draw_instanced), GL, 2008 }, { "GL_ARB_explicit_attrib_location", o(ARB_explicit_attrib_location), GL, 2009 }, { "GL_ARB_fragment_coord_conventions", o(ARB_fragment_coord_conventions), GL, 2009 }, @@ -109,6 +110,7 @@ static const struct extension extension_table[] = { { "GL_ARB_invalidate_subdata", o(dummy_true), GL, 2012 }, { "GL_ARB_map_buffer_alignment", o(ARB_map_buffer_alignment), GL, 2011 }, { "GL_ARB_map_buffer_range", o(ARB_map_buffer_range), GL, 2008 }, + { "GL_ARB_multi_draw_indirect", o(ARB_draw_indirect), GLC, 2012 }, { "GL_ARB_multisample", o(dummy_true), GLL, 1994 }, { "GL_ARB_multitexture", o(dummy_true), GLL, 1998 }, { "GL_ARB_occlusion_query2", o(ARB_occlusion_query2), GL, 2003 }, diff --git a/src/mesa/main/get.c b/src/mesa/main/get.c index 582ef31..f0f44aa 100644 --- a/src/mesa/main/get.c +++ b/src/mesa/main/get.c @@ -356,6 +356,7 @@ EXTRA_EXT(ARB_map_buffer_alignment); EXTRA_EXT(ARB_texture_cube_map_array); EXTRA_EXT(ARB_texture_buffer_range); EXTRA_EXT(ARB_texture_multisample); +EXTRA_EXT(ARB_draw_indirect); static const int extra_NV_primitive_restart[] = { @@ -853,6 +854,10 @@ find_custom_value(struct gl_context *ctx, const struct value_desc *d, union valu _mesa_problem(ctx, "driver doesn't implement GetTimestamp"); } break; + /* GL_ARB_draw_indirect */ + case GL_DRAW_INDIRECT_BUFFER_BINDING: + v->value_int = ctx->DrawIndirectBuffer->Name; + break; } } diff --git a/src/mesa/main/get_hash_params.py b/src/mesa/main/get_hash_params.py index 7d4f7e2..68513dc 100644 --- a/src/mesa/main/get_hash_params.py +++ b/src/mesa/main/get_hash_params.py @@ -715,6 +715,8 @@ descriptor=[ { "apis": ["GL_CORE"], "params": [ # GL_ARB_texture_buffer_range [ "TEXTURE_BUFFER_OFFSET_ALIGNMENT", "CONTEXT_INT(Const.TextureBufferOffsetAlignment), extra_ARB_texture_buffer_range" ], +# GL_ARB_draw_indirect + [ "DRAW_INDIRECT_BUFFER_BINDING", "LOC_CUSTOM, TYPE_INT, 0, extra_ARB_draw_indirect" ], ]} ] diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index ace6938..b7852c7 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2953,6 +2953,7 @@ struct gl_extensions GLboolean ARB_depth_texture; GLboolean ARB_draw_buffers_blend; GLboolean ARB_draw_elements_base_vertex; + GLboolean ARB_draw_indirect; GLboolean ARB_draw_instanced; GLboolean ARB_fragment_coord_conventions; GLboolean ARB_fragment_program; @@ -3515,6 +3516,8 @@ struct gl_context struct gl_transform_feedback_state TransformFeedback; + struct gl_buffer_object *DrawIndirectBuffer; /** < GL_ARB_draw_indirect */ + struct gl_buffer_object *CopyReadBuffer; /**< GL_ARB_copy_buffer */ struct gl_buffer_object *CopyWriteBuffer; /**< GL_ARB_copy_buffer */ diff --git a/src/mesa/main/tests/dispatch_sanity.cpp b/src/mesa/main/tests/dispatch_sanity.cpp index ffd83fe..dedaef4 100644 --- a/src/mesa/main/tests/dispatch_sanity.cpp +++ b/src/mesa/main/tests/dispatch_sanity.cpp @@ -674,8 +674,8 @@ const struct function gl_core_functions_possible[] = { { "glVertexAttribP3uiv", 43, -1 }, { "glVertexAttribP4ui", 43, -1 }, { "glVertexAttribP4uiv", 43, -1 }, -// { "glDrawArraysIndirect", 43, -1 }, // XXX: Add to xml -// { "glDrawElementsIndirect", 43, -1 }, // XXX: Add to xml + { "glDrawArraysIndirect", 43, -1 }, + { "glDrawElementsIndirect", 43, -1 }, // { "glUniform1d", 43, -1 }, // XXX: Add to xml // { "glUniform2d", 43, -1 }, // XXX: Add to xml // { "glUniform3d", 43, -1 }, // XXX: Add to xml @@ -884,8 +884,8 @@ const struct function gl_core_functions_possible[] = { { "glInvalidateBufferData", 43, -1 }, { "glInvalidateFramebuffer", 43, -1 }, { "glInvalidateSubFramebuffer", 43, -1 }, -// { "glMultiDrawArraysIndirect", 43, -1 }, // XXX: Add to xml -// { "glMultiDrawElementsIndirect", 43, -1 }, // XXX: Add to xml + { "glMultiDrawArraysIndirect", 43, -1 }, + { "glMultiDrawElementsIndirect", 43, -1 }, // { "glGetProgramInterfaceiv", 43, -1 }, // XXX: Add to xml // { "glGetProgramResourceIndex", 43, -1 }, // XXX: Add to xml // { "glGetProgramResourceName", 43, -1 }, // XXX: Add to xml diff --git a/src/mesa/main/vtxfmt.c b/src/mesa/main/vtxfmt.c index 8669c40..92a9374 100644 --- a/src/mesa/main/vtxfmt.c +++ b/src/mesa/main/vtxfmt.c @@ -147,6 +147,13 @@ install_vtxfmt(struct gl_context *ctx, struct _glapi_table *tab, vfmt->DrawTransformFeedbackStreamInstanced); } + if (_mesa_is_desktop_gl(ctx)) { + SET_DrawArraysIndirect(tab, vfmt->DrawArraysIndirect); + SET_DrawElementsIndirect(tab, vfmt->DrawElementsIndirect); + SET_MultiDrawArraysIndirect(tab, vfmt->MultiDrawArraysIndirect); + SET_MultiDrawElementsIndirect(tab, vfmt->MultiDrawElementsIndirect); + } + /* Originally for GL_NV_vertex_program, this is also used by dlist.c */ if (ctx->API == API_OPENGL_COMPAT) { SET_VertexAttrib1fNV(tab, vfmt->VertexAttrib1fNV); diff --git a/src/mesa/vbo/vbo_exec_array.c b/src/mesa/vbo/vbo_exec_array.c index 93674e2..75fda00 100644 --- a/src/mesa/vbo/vbo_exec_array.c +++ b/src/mesa/vbo/vbo_exec_array.c @@ -1359,6 +1359,251 @@ vbo_exec_DrawTransformFeedbackStreamInstanced(GLenum mode, GLuint name, vbo_draw_transform_feedback(ctx, mode, obj, stream, primcount); } +static void +vbo_validated_drawarraysindirect(struct gl_context *ctx, + GLenum mode, const GLvoid *indirect) +{ + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + struct _mesa_prim prim[1]; + + vbo_bind_arrays(ctx); + + memset(prim, 0, sizeof(prim)); + prim[0].begin = 1; + prim[0].end = 1; + prim[0].mode = mode; + prim[0].indirect_offset = (GLsizeiptr)indirect; + + /* NOTE: We do NOT want to handle primitive restart here, nor perform any + * other checks that require knowledge of the values in the command buffer. + * That would deafeat the whole purpose of this function. + */ + + check_buffers_are_unmapped(exec->array.inputs); + vbo->draw_prims(ctx, prim, 1, + NULL, GL_TRUE, 0, 0, + NULL, + ctx->DrawIndirectBuffer); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) + _mesa_flush(ctx); +} + +static void +vbo_validated_multidrawarraysindirect(struct gl_context *ctx, + GLenum mode, + const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + struct _mesa_prim *prim; + GLsizei i; + GLsizeiptr offset = (GLsizeiptr)indirect; + + if (primcount == 0) + return; + prim = calloc(1, primcount * sizeof(*prim)); + if (prim == NULL) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawArraysIndirect"); + return; + } + + vbo_bind_arrays(ctx); + + memset(prim, 0, primcount * sizeof(*prim)); + prim[0].begin = 1; + prim[primcount - 1].end = 1; + for (i = 0; i < primcount; ++i, offset += stride) { + prim[i].mode = mode; + prim[i].indirect_offset = offset; + } + + check_buffers_are_unmapped(exec->array.inputs); + vbo->draw_prims(ctx, prim, primcount, + NULL, GL_TRUE, 0, 0, + NULL, + ctx->DrawIndirectBuffer); + + free(prim); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) + _mesa_flush(ctx); +} + +static void +vbo_validated_drawelementsindirect(struct gl_context *ctx, + GLenum mode, GLenum type, + const GLvoid *indirect) +{ + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + struct _mesa_index_buffer ib; + struct _mesa_prim prim[1]; + + vbo_bind_arrays(ctx); + + ib.count = 0; /* unknown */ + ib.type = type; + ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj; + ib.ptr = NULL; + + memset(prim, 0, sizeof(prim)); + prim[0].begin = 1; + prim[0].end = 1; + prim[0].mode = mode; + prim[0].indexed = 1; + prim[0].indirect_offset = (GLsizeiptr)indirect; + + check_buffers_are_unmapped(exec->array.inputs); + vbo->draw_prims(ctx, prim, 1, + &ib, GL_TRUE, 0, 0, + NULL, + ctx->DrawIndirectBuffer); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) + _mesa_flush(ctx); +} + +static void +vbo_validated_multidrawelementsindirect(struct gl_context *ctx, + GLenum mode, GLenum type, + const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + struct vbo_context *vbo = vbo_context(ctx); + struct vbo_exec_context *exec = &vbo->exec; + struct _mesa_index_buffer ib; + struct _mesa_prim *prim; + GLsizei i; + GLsizeiptr offset = (GLsizeiptr)indirect; + + if (primcount == 0) + return; + prim = calloc(1, primcount * sizeof(*prim)); + if (prim == NULL) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawElementsIndirect"); + return; + } + + vbo_bind_arrays(ctx); + + /* NOTE: ElementArrayBufferObj is guaranteed to be a VBO. */ + + ib.count = 0; /* unknown */ + ib.type = type; + ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj; + ib.ptr = NULL; + + memset(prim, 0, primcount * sizeof(*prim)); + prim[0].begin = 1; + prim[primcount - 1].end = 1; + for (i = 0; i < primcount; ++i, offset += stride) { + prim[i].mode = mode; + prim[i].indexed = 1; + prim[i].indirect_offset = offset; + } + + check_buffers_are_unmapped(exec->array.inputs); + vbo->draw_prims(ctx, prim, primcount, + &ib, GL_TRUE, 0, 0, + NULL, + ctx->DrawIndirectBuffer); + + free(prim); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) + _mesa_flush(ctx); +} + +/** + * Like [Multi]DrawArrays/Elements, but they take most arguments from + * a buffer object. + */ +static void GLAPIENTRY +vbo_exec_DrawArraysIndirect(GLenum mode, const GLvoid *indirect) +{ + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glDrawArraysIndirect(%s, %p)\n", + _mesa_lookup_enum_by_nr(mode), indirect); + + if (!_mesa_validate_DrawArraysIndirect(ctx, mode, indirect)) + return; + + vbo_validated_drawarraysindirect(ctx, mode, indirect); +} + +static void GLAPIENTRY +vbo_exec_DrawElementsIndirect(GLenum mode, GLenum type, + const GLvoid *indirect) +{ + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glDrawElementsIndirect(%s, %s, %p)\n", + _mesa_lookup_enum_by_nr(mode), + _mesa_lookup_enum_by_nr(type), indirect); + + if (!_mesa_validate_DrawElementsIndirect(ctx, mode, type, indirect)) + return; + + vbo_validated_drawelementsindirect(ctx, mode, type, indirect); +} + +static void GLAPIENTRY +vbo_exec_MultiDrawArraysIndirect(GLenum mode, + const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glMultiDrawArraysIndirect(%s, %p, %i, %i)\n", + _mesa_lookup_enum_by_nr(mode), indirect, primcount, stride); + + /* If <stride> is zero, the array elements are treated as tightly packed. */ + if (stride == 0) + stride = 4 * sizeof(GLuint); /* sizeof(DrawArraysIndirectCommand) */ + + if (!_mesa_validate_MultiDrawArraysIndirect(ctx, mode, + indirect, + primcount, stride)) + return; + + vbo_validated_multidrawarraysindirect(ctx, mode, + indirect, + primcount, stride); +} + +static void GLAPIENTRY +vbo_exec_MultiDrawElementsIndirect(GLenum mode, GLenum type, + const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_DRAW) + _mesa_debug(ctx, "glMultiDrawElementsIndirect(%s, %s, %p, %i, %i)\n", + _mesa_lookup_enum_by_nr(mode), + _mesa_lookup_enum_by_nr(type), indirect, primcount, stride); + + /* If <stride> is zero, the array elements are treated as tightly packed. */ + if (stride == 0) + stride = 5 * sizeof(GLuint); /* sizeof(DrawElementsIndirectCommand) */ + + if (!_mesa_validate_MultiDrawElementsIndirect(ctx, mode, type, + indirect, + primcount, stride)) + return; + + vbo_validated_multidrawelementsindirect(ctx, mode, type, + indirect, + primcount, stride); +} + /** * Plug in the immediate-mode vertex array drawing commands into the * givven vbo_exec_context object. @@ -1386,6 +1631,10 @@ vbo_exec_array_init( struct vbo_exec_context *exec ) vbo_exec_DrawTransformFeedbackInstanced; exec->vtxfmt.DrawTransformFeedbackStreamInstanced = vbo_exec_DrawTransformFeedbackStreamInstanced; + exec->vtxfmt.DrawArraysIndirect = vbo_exec_DrawArraysIndirect; + exec->vtxfmt.DrawElementsIndirect = vbo_exec_DrawElementsIndirect; + exec->vtxfmt.MultiDrawArraysIndirect = vbo_exec_MultiDrawArraysIndirect; + exec->vtxfmt.MultiDrawElementsIndirect = vbo_exec_MultiDrawElementsIndirect; } diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c index 7490717..37e3342 100644 --- a/src/mesa/vbo/vbo_save_api.c +++ b/src/mesa/vbo/vbo_save_api.c @@ -1151,6 +1151,55 @@ _save_DrawTransformFeedbackStreamInstanced(GLenum mode, GLuint name, static void GLAPIENTRY +_save_DrawArraysIndirect(GLenum mode, const GLvoid *indirect) +{ + GET_CURRENT_CONTEXT(ctx); + (void) mode; + (void) indirect; + _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glDrawArraysIndirect"); +} + + +static void GLAPIENTRY +_save_DrawElementsIndirect(GLenum mode, GLenum type, const GLvoid *indirect) +{ + GET_CURRENT_CONTEXT(ctx); + (void) mode; + (void) type; + (void) indirect; + _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glDrawElementsIndirect"); +} + + +static void GLAPIENTRY +_save_MultiDrawArraysIndirect(GLenum mode, const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + GET_CURRENT_CONTEXT(ctx); + (void) mode; + (void) indirect; + (void) primcount; + (void) stride; + _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glMultiDrawArraysIndirect"); +} + + +static void GLAPIENTRY +_save_MultiDrawElementsIndirect(GLenum mode, GLenum type, + const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + GET_CURRENT_CONTEXT(ctx); + (void) mode; + (void) type; + (void) indirect; + (void) primcount; + (void) stride; + _mesa_compile_error(ctx, GL_INVALID_OPERATION, "glMultiDrawElementsIndirect"); +} + + +static void GLAPIENTRY _save_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) { GET_CURRENT_CONTEXT(ctx); @@ -1506,6 +1555,10 @@ _save_vtxfmt_init(struct gl_context *ctx) vfmt->DrawTransformFeedbackInstanced = _save_DrawTransformFeedbackInstanced; vfmt->DrawTransformFeedbackStreamInstanced = _save_DrawTransformFeedbackStreamInstanced; + vfmt->DrawArraysIndirect = _save_DrawArraysIndirect; + vfmt->DrawElementsIndirect = _save_DrawElementsIndirect; + vfmt->MultiDrawArraysIndirect = _save_MultiDrawArraysIndirect; + vfmt->MultiDrawElementsIndirect = _save_MultiDrawElementsIndirect; } -- 1.7.3.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev