diff options
Diffstat (limited to 'mesalib/src')
26 files changed, 622 insertions, 24 deletions
diff --git a/mesalib/src/mapi/glapi/gen/ARB_draw_indirect.xml b/mesalib/src/mapi/glapi/gen/ARB_draw_indirect.xml new file mode 100644 index 000000000..7de03cd35 --- /dev/null +++ b/mesalib/src/mapi/glapi/gen/ARB_draw_indirect.xml @@ -0,0 +1,45 @@ +<?xml version="1.0"?> +<!DOCTYPE OpenGLAPI SYSTEM "gl_API.dtd"> + +<OpenGLAPI> + +<category name="GL_ARB_draw_indirect" number="87"> + + <enum name="DRAW_INDIRECT_BUFFER" value="0x8F3F"/> + <enum name="DRAW_INDIRECT_BUFFER_BINDING" value="0x8F43"/> + + <function name="DrawArraysIndirect" offset="assign" exec="dynamic"> + <param name="mode" type="GLenum"/> + <param name="indirect" type="const GLvoid *"/> + </function> + + <function name="DrawElementsIndirect" offset="assign" exec="dynamic"> + <param name="mode" type="GLenum"/> + <param name="type" type="GLenum"/> + <param name="indirect" type="const GLvoid *"/> + </function> + +</category> + + +<category name="GL_ARB_multi_draw_indirect" number="133"> + + <function name="MultiDrawArraysIndirect" offset="assign" exec="dynamic"> + <param name="mode" type="GLenum"/> + <param name="indirect" type="const GLvoid *"/> + <param name="primcount" type="GLsizei"/> + <param name="stride" type="GLsizei"/> + </function> + + <function name="MultiDrawElementsIndirect" offset="assign" exec="dynamic"> + <param name="mode" type="GLenum"/> + <param name="type" type="GLenum"/> + <param name="indirect" type="const GLvoid *"/> + <param name="primcount" type="GLsizei"/> + <param name="stride" type="GLsizei"/> + </function> + +</category> + + +</OpenGLAPI> diff --git a/mesalib/src/mapi/glapi/gen/Makefile.am b/mesalib/src/mapi/glapi/gen/Makefile.am index 476d943dd..7af769acf 100644 --- a/mesalib/src/mapi/glapi/gen/Makefile.am +++ b/mesalib/src/mapi/glapi/gen/Makefile.am @@ -98,6 +98,7 @@ API_XML = \ ARB_draw_buffers.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/mesalib/src/mapi/glapi/gen/gl_API.xml b/mesalib/src/mapi/glapi/gen/gl_API.xml index 45536793f..5c204f9a1 100755 --- a/mesalib/src/mapi/glapi/gen/gl_API.xml +++ b/mesalib/src/mapi/glapi/gen/gl_API.xml @@ -8241,6 +8241,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"/> @@ -8470,7 +8472,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/mesalib/src/mesa/main/api_validate.c b/mesalib/src/mesa/main/api_validate.c index f285c9748..96b178905 100644 --- a/mesalib/src/mesa/main/api_validate.c +++ b/mesalib/src/mesa/main/api_validate.c @@ -837,3 +837,195 @@ _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; + + + /* From the ARB_draw_indirect specification: + * "An INVALID_OPERATION error is generated [...] if <indirect> is no + * word aligned." + */ + 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)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s: no buffer bound to DRAW_INDIRECT_BUFFER", name); + return GL_FALSE; + } + + if (_mesa_bufferobj_mapped(ctx->DrawIndirectBuffer)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(DRAW_INDIRECT_BUFFER is mapped)", name); + return GL_FALSE; + } + + /* From the ARB_draw_indirect specification: + * "An INVALID_OPERATION error is generated if the commands source data + * beyond the end of the buffer object [...]" + */ + if (ctx->DrawIndirectBuffer->Size < end) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(DRAW_INDIRECT_BUFFER too small)", 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) +{ + + /* From the ARB_multi_draw_indirect specification: + * "INVALID_VALUE is generated by MultiDrawArraysIndirect or + * MultiDrawElementsIndirect if <primcount> is negative." + * + * "<primcount> must be positive, otherwise an INVALID_VALUE error will + * be generated." + */ + if (primcount < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(primcount < 0)", name); + return GL_FALSE; + } + + + /* From the ARB_multi_draw_indirect specification: + * "<stride> must be a multiple of four, otherwise an INVALID_VALUE + * error is generated." + */ + 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) +{ + const unsigned drawArraysNumParams = 4; + + FLUSH_CURRENT(ctx, 0); + + return valid_draw_indirect(ctx, mode, + indirect, drawArraysNumParams * sizeof(GLuint), + "glDrawArraysIndirect"); +} + +GLboolean +_mesa_validate_DrawElementsIndirect(struct gl_context *ctx, + GLenum mode, GLenum type, + const GLvoid *indirect) +{ + const unsigned drawElementsNumParams = 5; + + FLUSH_CURRENT(ctx, 0); + + return valid_draw_indirect_elements(ctx, mode, type, + indirect, drawElementsNumParams * sizeof(GLuint), + "glDrawElementsIndirect"); +} + +GLboolean +_mesa_validate_MultiDrawArraysIndirect(struct gl_context *ctx, + GLenum mode, + const GLvoid *indirect, + GLsizei primcount, GLsizei stride) +{ + GLsizeiptr size = 0; + const unsigned drawArraysNumParams = 4; + + FLUSH_CURRENT(ctx, 0); + + /* caller has converted stride==0 to drawArraysNumParams * sizeof(GLuint) */ + assert(stride != 0); + + if (!valid_draw_indirect_multi(ctx, primcount, stride, + "glMultiDrawArraysIndirect")) + return GL_FALSE; + + /* number of bytes of the indirect buffer which will be read */ + size = primcount + ? (primcount - 1) * stride + drawArraysNumParams * sizeof(GLuint) + : 0; + + 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; + const unsigned drawElementsNumParams = 5; + + FLUSH_CURRENT(ctx, 0); + + /* caller has converted stride==0 to drawElementsNumParams * sizeof(GLuint) */ + assert(stride != 0); + + if (!valid_draw_indirect_multi(ctx, primcount, stride, + "glMultiDrawElementsIndirect")) + return GL_FALSE; + + /* number of bytes of the indirect buffer which will be read */ + size = primcount + ? (primcount - 1) * stride + drawElementsNumParams * sizeof(GLuint) + : 0; + + if (!valid_draw_indirect_elements(ctx, mode, type, + indirect, size, + "glMultiDrawElementsIndirect")) + return GL_FALSE; + + return GL_TRUE; +} diff --git a/mesalib/src/mesa/main/api_validate.h b/mesalib/src/mesa/main/api_validate.h index f2b753ca9..8238df16c 100644 --- a/mesalib/src/mesa/main/api_validate.h +++ b/mesalib/src/mesa/main/api_validate.h @@ -87,5 +87,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/mesalib/src/mesa/main/bufferobj.c b/mesalib/src/mesa/main/bufferobj.c index 351934433..3127a8247 100644 --- a/mesalib/src/mesa/main/bufferobj.c +++ b/mesalib/src/mesa/main/bufferobj.c @@ -86,6 +86,12 @@ 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->API == API_OPENGL_CORE && + ctx->Extensions.ARB_draw_indirect) { + return &ctx->DrawIndirectBuffer; + } + break; case GL_TRANSFORM_FEEDBACK_BUFFER: if (ctx->Extensions.EXT_transform_feedback) { return &ctx->TransformFeedback.CurrentBuffer; @@ -626,6 +632,9 @@ _mesa_init_buffer_objects( struct gl_context *ctx ) _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, ctx->Shared->NullBufferObj); + _mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer, + ctx->Shared->NullBufferObj); + for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) { _mesa_reference_buffer_object(ctx, &ctx->UniformBufferBindings[i].BufferObject, @@ -875,6 +884,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/mesalib/src/mesa/main/extensions.c b/mesalib/src/mesa/main/extensions.c index 104618c23..42da9057c 100644 --- a/mesalib/src/mesa/main/extensions.c +++ b/mesalib/src/mesa/main/extensions.c @@ -92,6 +92,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/mesalib/src/mesa/main/get.c b/mesalib/src/mesa/main/get.c index eee855007..7f233409e 100644 --- a/mesalib/src/mesa/main/get.c +++ b/mesalib/src/mesa/main/get.c @@ -375,6 +375,7 @@ EXTRA_EXT(ARB_texture_buffer_range); EXTRA_EXT(ARB_texture_multisample); EXTRA_EXT(ARB_texture_gather); EXTRA_EXT(ARB_shader_atomic_counters); +EXTRA_EXT(ARB_draw_indirect); static const int extra_ARB_color_buffer_float_or_glcore[] = { @@ -913,6 +914,10 @@ find_custom_value(struct gl_context *ctx, const struct value_desc *d, union valu case GL_ATOMIC_COUNTER_BUFFER_BINDING: v->value_int = ctx->AtomicBuffer->Name; break; + /* GL_ARB_draw_indirect */ + case GL_DRAW_INDIRECT_BUFFER_BINDING: + v->value_int = ctx->DrawIndirectBuffer->Name; + break; } } diff --git a/mesalib/src/mesa/main/get_hash_params.py b/mesalib/src/mesa/main/get_hash_params.py index c961feeee..781b796ee 100644 --- a/mesalib/src/mesa/main/get_hash_params.py +++ b/mesalib/src/mesa/main/get_hash_params.py @@ -747,6 +747,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/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h index ecfb5e08f..b4b432f40 100644 --- a/mesalib/src/mesa/main/mtypes.h +++ b/mesalib/src/mesa/main/mtypes.h @@ -3326,6 +3326,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; @@ -3902,6 +3903,8 @@ struct gl_context struct gl_perf_monitor_state PerfMonitor; + 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/mesalib/src/mesa/state_tracker/st_cb_rasterpos.c b/mesalib/src/mesa/state_tracker/st_cb_rasterpos.c index 26a55909d..420dc5fc9 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_rasterpos.c +++ b/mesalib/src/mesa/state_tracker/st_cb_rasterpos.c @@ -254,7 +254,7 @@ st_RasterPos(struct gl_context *ctx, const GLfloat v[4]) * st_feedback_draw_vbo doesn't check for that flag. */ ctx->Array._DrawArrays = rs->arrays; st_feedback_draw_vbo(ctx, &rs->prim, 1, NULL, GL_TRUE, 0, 1, - NULL); + NULL, NULL); ctx->Array._DrawArrays = saved_arrays; /* restore draw's rasterization stage depending on rendermode */ diff --git a/mesalib/src/mesa/state_tracker/st_draw.c b/mesalib/src/mesa/state_tracker/st_draw.c index 51bb23807..ef0a60732 100644 --- a/mesalib/src/mesa/state_tracker/st_draw.c +++ b/mesalib/src/mesa/state_tracker/st_draw.c @@ -195,7 +195,8 @@ st_draw_vbo(struct gl_context *ctx, GLboolean index_bounds_valid, GLuint min_index, GLuint max_index, - struct gl_transform_feedback_object *tfb_vertcount) + struct gl_transform_feedback_object *tfb_vertcount, + struct gl_buffer_object *indirect) { struct st_context *st = st_context(ctx); struct pipe_index_buffer ibuffer = {0}; diff --git a/mesalib/src/mesa/state_tracker/st_draw.h b/mesalib/src/mesa/state_tracker/st_draw.h index 394473b20..9c4d6cbba 100644 --- a/mesalib/src/mesa/state_tracker/st_draw.h +++ b/mesalib/src/mesa/state_tracker/st_draw.h @@ -55,7 +55,8 @@ st_draw_vbo(struct gl_context *ctx, GLboolean index_bounds_valid, GLuint min_index, GLuint max_index, - struct gl_transform_feedback_object *tfb_vertcount); + struct gl_transform_feedback_object *tfb_vertcount, + struct gl_buffer_object *indirect); extern void st_feedback_draw_vbo(struct gl_context *ctx, @@ -65,7 +66,8 @@ st_feedback_draw_vbo(struct gl_context *ctx, GLboolean index_bounds_valid, GLuint min_index, GLuint max_index, - struct gl_transform_feedback_object *tfb_vertcount); + struct gl_transform_feedback_object *tfb_vertcount, + struct gl_buffer_object *indirect); /** * When drawing with VBOs, the addresses specified with diff --git a/mesalib/src/mesa/state_tracker/st_draw_feedback.c b/mesalib/src/mesa/state_tracker/st_draw_feedback.c index 1ac9585e7..f5566446f 100644 --- a/mesalib/src/mesa/state_tracker/st_draw_feedback.c +++ b/mesalib/src/mesa/state_tracker/st_draw_feedback.c @@ -116,7 +116,8 @@ st_feedback_draw_vbo(struct gl_context *ctx, GLboolean index_bounds_valid, GLuint min_index, GLuint max_index, - struct gl_transform_feedback_object *tfb_vertcount) + struct gl_transform_feedback_object *tfb_vertcount, + struct gl_buffer_object *indirect) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; diff --git a/mesalib/src/mesa/tnl/t_draw.c b/mesalib/src/mesa/tnl/t_draw.c index 637ac6f9c..d6b09005e 100644 --- a/mesalib/src/mesa/tnl/t_draw.c +++ b/mesalib/src/mesa/tnl/t_draw.c @@ -415,7 +415,8 @@ void _tnl_vbo_draw_prims(struct gl_context *ctx, GLboolean index_bounds_valid, GLuint min_index, GLuint max_index, - struct gl_transform_feedback_object *tfb_vertcount) + struct gl_transform_feedback_object *tfb_vertcount, + struct gl_buffer_object *indirect) { const struct gl_client_array **arrays = ctx->Array._DrawArrays; diff --git a/mesalib/src/mesa/tnl/tnl.h b/mesalib/src/mesa/tnl/tnl.h index 162b7abd7..86ef5057e 100644 --- a/mesalib/src/mesa/tnl/tnl.h +++ b/mesalib/src/mesa/tnl/tnl.h @@ -92,7 +92,8 @@ _tnl_vbo_draw_prims( struct gl_context *ctx, GLboolean index_bounds_valid, GLuint min_index, GLuint max_index, - struct gl_transform_feedback_object *tfb_vertcount ); + struct gl_transform_feedback_object *tfb_vertcount, + struct gl_buffer_object *indirect ); extern void _tnl_RasterPos(struct gl_context *ctx, const GLfloat vObj[4]); diff --git a/mesalib/src/mesa/vbo/vbo.h b/mesalib/src/mesa/vbo/vbo.h index c4472e9c2..6e1a4aa1a 100644 --- a/mesalib/src/mesa/vbo/vbo.h +++ b/mesalib/src/mesa/vbo/vbo.h @@ -46,13 +46,16 @@ struct _mesa_prim { GLuint end:1; GLuint weak:1; GLuint no_current_update:1; - GLuint pad:19; + GLuint is_indirect:1; + GLuint pad:18; GLuint start; GLuint count; GLint basevertex; GLuint num_instances; GLuint base_instance; + + GLsizeiptr indirect_offset; }; /* Would like to call this a "vbo_index_buffer", but this would be @@ -89,7 +92,8 @@ typedef void (*vbo_draw_func)( struct gl_context *ctx, GLboolean index_bounds_valid, GLuint min_index, GLuint max_index, - struct gl_transform_feedback_object *tfb_vertcount ); + struct gl_transform_feedback_object *tfb_vertcount, + struct gl_buffer_object *indirect ); @@ -182,7 +186,8 @@ void vbo_sw_primitive_restart(struct gl_context *ctx, const struct _mesa_prim *prim, GLuint nr_prims, - const struct _mesa_index_buffer *ib); + const struct _mesa_index_buffer *ib, + struct gl_buffer_object *indirect); void GLAPIENTRY _es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a); diff --git a/mesalib/src/mesa/vbo/vbo_exec_api.c b/mesalib/src/mesa/vbo/vbo_exec_api.c index 600398c58..c84d97f56 100644 --- a/mesalib/src/mesa/vbo/vbo_exec_api.c +++ b/mesalib/src/mesa/vbo/vbo_exec_api.c @@ -702,6 +702,7 @@ static void GLAPIENTRY vbo_exec_Begin( GLenum mode ) exec->vtx.prim[i].count = 0; exec->vtx.prim[i].num_instances = 1; exec->vtx.prim[i].base_instance = 0; + exec->vtx.prim[i].is_indirect = 0; ctx->Driver.CurrentExecPrimitive = mode; diff --git a/mesalib/src/mesa/vbo/vbo_exec_array.c b/mesalib/src/mesa/vbo/vbo_exec_array.c index d72382376..8152fa162 100644 --- a/mesalib/src/mesa/vbo/vbo_exec_array.c +++ b/mesalib/src/mesa/vbo/vbo_exec_array.c @@ -579,11 +579,11 @@ vbo_handle_primitive_restart(struct gl_context *ctx, ctx->Const.PrimitiveRestartInSoftware && ctx->Array._PrimitiveRestart) { /* Handle primitive restart in software */ - vbo_sw_primitive_restart(ctx, prim, nr_prims, ib); + vbo_sw_primitive_restart(ctx, prim, nr_prims, ib, NULL); } else { /* Call driver directly for draw_prims */ vbo->draw_prims(ctx, prim, nr_prims, ib, - index_bounds_valid, min_index, max_index, NULL); + index_bounds_valid, min_index, max_index, NULL, NULL); } } @@ -611,6 +611,7 @@ vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start, prim[0].mode = mode; prim[0].num_instances = numInstances; prim[0].base_instance = baseInstance; + prim[0].is_indirect = 0; /* Implement the primitive restart index */ if (ctx->Array.PrimitiveRestart && ctx->Array.RestartIndex < count) { @@ -648,7 +649,7 @@ vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start, /* draw one or two prims */ check_buffers_are_unmapped(exec->array.inputs); vbo->draw_prims(ctx, prim, primCount, NULL, - GL_TRUE, start, start + count - 1, NULL); + GL_TRUE, start, start + count - 1, NULL, NULL); } } else { @@ -659,7 +660,7 @@ vbo_draw_arrays(struct gl_context *ctx, GLenum mode, GLint start, check_buffers_are_unmapped(exec->array.inputs); vbo->draw_prims(ctx, prim, 1, NULL, GL_TRUE, start, start + count - 1, - NULL); + NULL, NULL); } if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { @@ -965,6 +966,7 @@ vbo_validated_drawrangeelements(struct gl_context *ctx, GLenum mode, prim[0].start = 0; prim[0].count = count; prim[0].indexed = 1; + prim[0].is_indirect = 0; prim[0].basevertex = basevertex; prim[0].num_instances = numInstances; prim[0].base_instance = baseInstance; @@ -1368,6 +1370,7 @@ vbo_validated_multidrawelements(struct gl_context *ctx, GLenum mode, prim[i].indexed = 1; prim[i].num_instances = 1; prim[i].base_instance = 0; + prim[i].is_indirect = 0; if (basevertex != NULL) prim[i].basevertex = basevertex[i]; else @@ -1397,6 +1400,7 @@ vbo_validated_multidrawelements(struct gl_context *ctx, GLenum mode, prim[0].indexed = 1; prim[0].num_instances = 1; prim[0].base_instance = 0; + prim[0].is_indirect = 0; if (basevertex != NULL) prim[0].basevertex = basevertex[i]; else @@ -1483,6 +1487,7 @@ vbo_draw_transform_feedback(struct gl_context *ctx, GLenum mode, prim[0].mode = mode; prim[0].num_instances = numInstances; prim[0].base_instance = 0; + prim[0].is_indirect = 0; /* Maybe we should do some primitive splitting for primitive restart * (like in DrawArrays), but we have no way to know how many vertices @@ -1490,7 +1495,7 @@ vbo_draw_transform_feedback(struct gl_context *ctx, GLenum mode, check_buffers_are_unmapped(exec->array.inputs); vbo->draw_prims(ctx, prim, 1, NULL, - GL_TRUE, 0, 0, obj); + GL_TRUE, 0, 0, obj, NULL); if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { _mesa_flush(ctx); @@ -1564,6 +1569,252 @@ 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].is_indirect = 1; + 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 defeat 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(primcount, sizeof(*prim)); + if (prim == NULL) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMultiDrawArraysIndirect"); + return; + } + + vbo_bind_arrays(ctx); + + 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; + prim[i].is_indirect = 1; + } + + 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; + prim[0].is_indirect = 1; + + 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(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; + + 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; + prim[i].is_indirect = 1; + } + + 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); +} /** * Initialize the dispatch table with the VBO functions for drawing. @@ -1597,6 +1848,13 @@ vbo_initialize_exec_dispatch(const struct gl_context *ctx, SET_DrawElementsInstancedBaseVertexBaseInstance(exec, vbo_exec_DrawElementsInstancedBaseVertexBaseInstance); } + if (ctx->API == API_OPENGL_CORE) { + SET_DrawArraysIndirect(exec, vbo_exec_DrawArraysIndirect); + SET_DrawElementsIndirect(exec, vbo_exec_DrawElementsIndirect); + SET_MultiDrawArraysIndirect(exec, vbo_exec_MultiDrawArraysIndirect); + SET_MultiDrawElementsIndirect(exec, vbo_exec_MultiDrawElementsIndirect); + } + if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) { SET_DrawArraysInstancedARB(exec, vbo_exec_DrawArraysInstanced); SET_DrawElementsInstancedARB(exec, vbo_exec_DrawElementsInstanced); diff --git a/mesalib/src/mesa/vbo/vbo_exec_draw.c b/mesalib/src/mesa/vbo/vbo_exec_draw.c index 1075bd5d4..a96502ffb 100644 --- a/mesalib/src/mesa/vbo/vbo_exec_draw.c +++ b/mesalib/src/mesa/vbo/vbo_exec_draw.c @@ -403,7 +403,7 @@ vbo_exec_vtx_flush(struct vbo_exec_context *exec, GLboolean keepUnmapped) GL_TRUE, 0, exec->vtx.vert_count - 1, - NULL); + NULL, NULL); /* If using a real VBO, get new storage -- unless asked not to. */ diff --git a/mesalib/src/mesa/vbo/vbo_primitive_restart.c b/mesalib/src/mesa/vbo/vbo_primitive_restart.c index 418f8829d..e0bd233ee 100644 --- a/mesalib/src/mesa/vbo/vbo_primitive_restart.c +++ b/mesalib/src/mesa/vbo/vbo_primitive_restart.c @@ -163,7 +163,8 @@ void vbo_sw_primitive_restart(struct gl_context *ctx, const struct _mesa_prim *prims, GLuint nr_prims, - const struct _mesa_index_buffer *ib) + const struct _mesa_index_buffer *ib, + struct gl_buffer_object *indirect) { GLuint prim_num; struct sub_primitive *sub_prims; @@ -179,6 +180,39 @@ vbo_sw_primitive_restart(struct gl_context *ctx, GLboolean map_ib = ib->obj->Name && !ib->obj->Pointer; void *ptr; + /* If there is an indirect buffer, map it and extract the draw params */ + if (indirect && prims[0].is_indirect) { + struct _mesa_prim new_prim = *prims; + struct _mesa_index_buffer new_ib = *ib; + const uint32_t *indirect_params; + if (!ctx->Driver.MapBufferRange(ctx, 0, indirect->Size, GL_MAP_READ_BIT, + indirect)) { + + /* something went wrong with mapping, give up */ + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "failed to map indirect buffer for sw primitive restart"); + return; + } + + assert(nr_prims == 1); + indirect_params = (const uint32_t *) ADD_POINTERS(indirect->Pointer, + new_prim.indirect_offset); + + new_prim.is_indirect = 0; + new_prim.count = indirect_params[0]; + new_prim.num_instances = indirect_params[1]; + new_prim.start = indirect_params[2]; + new_prim.basevertex = indirect_params[3]; + new_prim.base_instance = indirect_params[4]; + + new_ib.count = new_prim.count; + + prims = &new_prim; + ib = &new_ib; + + ctx->Driver.UnmapBuffer(ctx, indirect); + } + /* Find the sub-primitives. These are regions in the index buffer which * are split based on the primitive restart index value. */ @@ -214,11 +248,11 @@ vbo_sw_primitive_restart(struct gl_context *ctx, (temp_prim.count == sub_prim->count)) { draw_prims_func(ctx, &temp_prim, 1, ib, GL_TRUE, sub_prim->min_index, sub_prim->max_index, - NULL); + NULL, NULL); } else { draw_prims_func(ctx, &temp_prim, 1, ib, GL_FALSE, -1, -1, - NULL); + NULL, NULL); } } if (sub_end_index >= end_index) { diff --git a/mesalib/src/mesa/vbo/vbo_rebase.c b/mesalib/src/mesa/vbo/vbo_rebase.c index e8258727b..f63c47375 100644 --- a/mesalib/src/mesa/vbo/vbo_rebase.c +++ b/mesalib/src/mesa/vbo/vbo_rebase.c @@ -237,7 +237,7 @@ void vbo_rebase_prims( struct gl_context *ctx, GL_TRUE, 0, max_index - min_index, - NULL ); + NULL, NULL ); ctx->Array._DrawArrays = saved_arrays; ctx->NewDriverState |= ctx->DriverFlags.NewArray; diff --git a/mesalib/src/mesa/vbo/vbo_save_api.c b/mesalib/src/mesa/vbo/vbo_save_api.c index 411c00604..d16405efc 100644 --- a/mesalib/src/mesa/vbo/vbo_save_api.c +++ b/mesalib/src/mesa/vbo/vbo_save_api.c @@ -531,6 +531,7 @@ _save_wrap_buffers(struct gl_context *ctx) save->prim[0].count = 0; save->prim[0].num_instances = 1; save->prim[0].base_instance = 0; + save->prim[0].is_indirect = 0; save->prim_count = 1; } @@ -986,6 +987,7 @@ vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode) save->prim[i].count = 0; save->prim[i].num_instances = 1; save->prim[i].base_instance = 0; + save->prim[i].is_indirect = 0; if (save->out_of_memory) { _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop); diff --git a/mesalib/src/mesa/vbo/vbo_save_draw.c b/mesalib/src/mesa/vbo/vbo_save_draw.c index b4c917630..e961c1d5c 100644 --- a/mesalib/src/mesa/vbo/vbo_save_draw.c +++ b/mesalib/src/mesa/vbo/vbo_save_draw.c @@ -313,7 +313,7 @@ vbo_save_playback_vertex_list(struct gl_context *ctx, void *data) GL_TRUE, 0, /* Node is a VBO, so this is ok */ node->count - 1, - NULL); + NULL, NULL); } } diff --git a/mesalib/src/mesa/vbo/vbo_split_copy.c b/mesalib/src/mesa/vbo/vbo_split_copy.c index 2175c8ac7..9e391a3ed 100644 --- a/mesalib/src/mesa/vbo/vbo_split_copy.c +++ b/mesalib/src/mesa/vbo/vbo_split_copy.c @@ -201,7 +201,7 @@ flush( struct copy_context *copy ) GL_TRUE, 0, copy->dstbuf_nr - 1, - NULL ); + NULL, NULL ); ctx->Array._DrawArrays = saved_arrays; ctx->NewDriverState |= ctx->DriverFlags.NewArray; diff --git a/mesalib/src/mesa/vbo/vbo_split_inplace.c b/mesalib/src/mesa/vbo/vbo_split_inplace.c index d04429707..de00fc86e 100644 --- a/mesalib/src/mesa/vbo/vbo_split_inplace.c +++ b/mesalib/src/mesa/vbo/vbo_split_inplace.c @@ -94,7 +94,7 @@ static void flush_vertex( struct split_context *split ) !split->ib, split->min_index, split->max_index, - NULL); + NULL, NULL); ctx->Array._DrawArrays = saved_arrays; ctx->NewDriverState |= ctx->DriverFlags.NewArray; |