#include "main/glheader.h"
#include "main/context.h"
#include "main/state.h"
-#include "main/api_validate.h"
+#include "main/draw_validate.h"
#include "main/dispatch.h"
#include "main/varray.h"
#include "main/bufferobj.h"
#include "main/macros.h"
#include "main/transformfeedback.h"
-#include "vbo_private.h"
+typedef struct {
+ GLuint count;
+ GLuint primCount;
+ GLuint first;
+ GLuint baseInstance;
+} DrawArraysIndirectCommand;
+
+typedef struct {
+ GLuint count;
+ GLuint primCount;
+ GLuint firstIndex;
+ GLint baseVertex;
+ GLuint baseInstance;
+} DrawElementsIndirectCommand;
/**
}
-/**
- * Examine the enabled vertex arrays to set the exec->array.inputs[] values.
- * These will point to the arrays to actually use for drawing. Some will
- * be user-provided arrays, other will be zero-stride const-valued arrays.
- */
-static void
-vbo_bind_arrays(struct gl_context *ctx)
-{
- struct vbo_context *vbo = vbo_context(ctx);
- struct vbo_exec_context *exec = &vbo->exec;
-
- _mesa_set_drawing_arrays(ctx, vbo->draw_arrays.inputs);
-
- if (exec->array.recalculate_inputs) {
- /* Finally update the inputs array */
- _vbo_update_inputs(ctx, &vbo->draw_arrays);
- ctx->NewDriverState |= ctx->DriverFlags.NewArray;
- exec->array.recalculate_inputs = GL_FALSE;
-
- assert(ctx->NewState == 0);
- }
-}
-
-
/**
* Helper function called by the other DrawArrays() functions below.
* This is where we handle primitive restart for drawing non-indexed
if (skip_validated_draw(ctx))
return;
- vbo_bind_arrays(ctx);
-
/* OpenGL 4.5 says that primitive restart is ignored with non-indexed
* draws.
*/
_mesa_debug(ctx, "glDrawArrays(%s, %d, %d)\n",
_mesa_enum_to_string(mode), start, count);
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ FLUSH_FOR_DRAW(ctx);
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
_mesa_debug(ctx, "glDrawArraysInstanced(%s, %d, %d, %d)\n",
_mesa_enum_to_string(mode), start, count, numInstances);
+ FLUSH_FOR_DRAW(ctx);
if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
-
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
_mesa_enum_to_string(mode), first, count,
numInstances, baseInstance);
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ FLUSH_FOR_DRAW(ctx);
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
"glMultiDrawArrays(%s, %p, %p, %d)\n",
_mesa_enum_to_string(mode), first, count, primcount);
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ FLUSH_FOR_DRAW(ctx);
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
if (skip_draw_elements(ctx, count, indices))
return;
- vbo_bind_arrays(ctx);
-
ib.count = count;
ib.index_size = sizeof_ib_type(type);
ib.obj = ctx->Array.VAO->IndexBufferObj;
_mesa_enum_to_string(mode), start, end, count,
_mesa_enum_to_string(type), indices, basevertex);
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ FLUSH_FOR_DRAW(ctx);
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
_mesa_enum_to_string(mode), count,
_mesa_enum_to_string(type), indices);
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ FLUSH_FOR_DRAW(ctx);
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
_mesa_enum_to_string(mode), count,
_mesa_enum_to_string(type), indices);
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ FLUSH_FOR_DRAW(ctx);
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
_mesa_enum_to_string(mode), count,
_mesa_enum_to_string(type), indices);
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ FLUSH_FOR_DRAW(ctx);
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
_mesa_enum_to_string(type), indices,
numInstances, basevertex);
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ FLUSH_FOR_DRAW(ctx);
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
_mesa_enum_to_string(type), indices,
numInstances, baseInstance);
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ FLUSH_FOR_DRAW(ctx);
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
_mesa_enum_to_string(type), indices,
numInstances, basevertex, baseInstance);
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ FLUSH_FOR_DRAW(ctx);
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
return;
}
- vbo_bind_arrays(ctx);
-
min_index_ptr = (uintptr_t) indices[0];
max_index_ptr = 0;
for (i = 0; i < primcount; i++) {
{
GET_CURRENT_CONTEXT(ctx);
+ FLUSH_FOR_DRAW(ctx);
+
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (!_mesa_validate_MultiDrawElements(ctx, mode, count, type, indices,
{
GET_CURRENT_CONTEXT(ctx);
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ FLUSH_FOR_DRAW(ctx);
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
{
struct _mesa_prim prim;
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ FLUSH_FOR_DRAW(ctx);
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
if (skip_validated_draw(ctx))
return;
- vbo_bind_arrays(ctx);
-
/* init most fields to zero */
memset(&prim, 0, sizeof(prim));
prim.begin = 1;
vbo_validated_drawarraysindirect(struct gl_context *ctx,
GLenum mode, const GLvoid *indirect)
{
- vbo_bind_arrays(ctx);
-
ctx->Driver.DrawIndirect(ctx, mode,
ctx->DrawIndirectBuffer, (GLsizeiptr) indirect,
1 /* draw_count */ , 16 /* stride */ ,
if (primcount == 0)
return;
- vbo_bind_arrays(ctx);
-
ctx->Driver.DrawIndirect(ctx, mode, ctx->DrawIndirectBuffer, offset,
primcount, stride, NULL, 0, NULL);
{
struct _mesa_index_buffer ib;
- vbo_bind_arrays(ctx);
-
ib.count = 0; /* unknown */
ib.index_size = sizeof_ib_type(type);
ib.obj = ctx->Array.VAO->IndexBufferObj;
if (primcount == 0)
return;
- vbo_bind_arrays(ctx);
-
/* NOTE: IndexBufferObj is guaranteed to be a VBO. */
ib.count = 0; /* unknown */
_mesa_debug(ctx, "glDrawArraysIndirect(%s, %p)\n",
_mesa_enum_to_string(mode), indirect);
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ /* From the ARB_draw_indirect spec:
+ *
+ * "Initially zero is bound to DRAW_INDIRECT_BUFFER. In the
+ * compatibility profile, this indicates that DrawArraysIndirect and
+ * DrawElementsIndirect are to source their arguments directly from the
+ * pointer passed as their <indirect> parameters."
+ */
+ if (ctx->API == API_OPENGL_COMPAT &&
+ !_mesa_is_bufferobj(ctx->DrawIndirectBuffer)) {
+ DrawArraysIndirectCommand *cmd = (DrawArraysIndirectCommand *) indirect;
+
+ vbo_exec_DrawArraysInstancedBaseInstance(mode, cmd->first, cmd->count,
+ cmd->primCount,
+ cmd->baseInstance);
+ return;
+ }
+
+ FLUSH_FOR_DRAW(ctx);
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
_mesa_enum_to_string(mode),
_mesa_enum_to_string(type), indirect);
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ /* From the ARB_draw_indirect spec:
+ *
+ * "Initially zero is bound to DRAW_INDIRECT_BUFFER. In the
+ * compatibility profile, this indicates that DrawArraysIndirect and
+ * DrawElementsIndirect are to source their arguments directly from the
+ * pointer passed as their <indirect> parameters."
+ */
+ if (ctx->API == API_OPENGL_COMPAT &&
+ !_mesa_is_bufferobj(ctx->DrawIndirectBuffer)) {
+ /*
+ * 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.VAO->IndexBufferObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glDrawElementsIndirect(no buffer bound "
+ "to GL_ELEMENT_ARRAY_BUFFER)");
+ } else {
+ DrawElementsIndirectCommand *cmd =
+ (DrawElementsIndirectCommand *) indirect;
+
+ /* Convert offset to pointer */
+ void *offset = (void *)
+ ((cmd->firstIndex * _mesa_sizeof_type(type)) & 0xffffffffUL);
+
+ vbo_exec_DrawElementsInstancedBaseVertexBaseInstance(mode, cmd->count,
+ type, offset,
+ cmd->primCount,
+ cmd->baseVertex,
+ cmd->baseInstance);
+ }
+ return;
+ }
+
+ FLUSH_FOR_DRAW(ctx);
+
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
/* If <stride> is zero, the array elements are treated as tightly packed. */
if (stride == 0)
- stride = 4 * sizeof(GLuint); /* sizeof(DrawArraysIndirectCommand) */
+ stride = sizeof(DrawArraysIndirectCommand);
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ /* From the ARB_draw_indirect spec:
+ *
+ * "Initially zero is bound to DRAW_INDIRECT_BUFFER. In the
+ * compatibility profile, this indicates that DrawArraysIndirect and
+ * DrawElementsIndirect are to source their arguments directly from the
+ * pointer passed as their <indirect> parameters."
+ */
+ if (ctx->API == API_OPENGL_COMPAT &&
+ !_mesa_is_bufferobj(ctx->DrawIndirectBuffer)) {
+
+ if (!_mesa_valid_draw_indirect_multi(ctx, primcount, stride,
+ "glMultiDrawArraysIndirect"))
+ return;
+
+ const ubyte *ptr = (const ubyte *) indirect;
+ for (unsigned i = 0; i < primcount; i++) {
+ DrawArraysIndirectCommand *cmd = (DrawArraysIndirectCommand *) ptr;
+ vbo_exec_DrawArraysInstancedBaseInstance(mode, cmd->first,
+ cmd->count, cmd->primCount,
+ cmd->baseInstance);
+
+ if (stride == 0) {
+ ptr += sizeof(DrawArraysIndirectCommand);
+ } else {
+ ptr += stride;
+ }
+ }
+
+ return;
+ }
+ FLUSH_FOR_DRAW(ctx);
+
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
/* If <stride> is zero, the array elements are treated as tightly packed. */
if (stride == 0)
- stride = 5 * sizeof(GLuint); /* sizeof(DrawElementsIndirectCommand) */
+ stride = sizeof(DrawElementsIndirectCommand);
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ /* From the ARB_draw_indirect spec:
+ *
+ * "Initially zero is bound to DRAW_INDIRECT_BUFFER. In the
+ * compatibility profile, this indicates that DrawArraysIndirect and
+ * DrawElementsIndirect are to source their arguments directly from the
+ * pointer passed as their <indirect> parameters."
+ */
+ if (ctx->API == API_OPENGL_COMPAT &&
+ !_mesa_is_bufferobj(ctx->DrawIndirectBuffer)) {
+ /*
+ * 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.VAO->IndexBufferObj)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glMultiDrawElementsIndirect(no buffer bound "
+ "to GL_ELEMENT_ARRAY_BUFFER)");
+
+ return;
+ }
+
+ if (!_mesa_valid_draw_indirect_multi(ctx, primcount, stride,
+ "glMultiDrawArraysIndirect"))
+ return;
+
+ const ubyte *ptr = (const ubyte *) indirect;
+ for (unsigned i = 0; i < primcount; i++) {
+ vbo_exec_DrawElementsIndirect(mode, type, ptr);
+
+ if (stride == 0) {
+ ptr += sizeof(DrawElementsIndirectCommand);
+ } else {
+ ptr += stride;
+ }
+ }
+
+ return;
+ }
+
+ FLUSH_FOR_DRAW(ctx);
+
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
if (maxdrawcount == 0)
return;
- vbo_bind_arrays(ctx);
-
ctx->Driver.DrawIndirect(ctx, mode,
ctx->DrawIndirectBuffer, offset,
maxdrawcount, stride,
if (maxdrawcount == 0)
return;
- vbo_bind_arrays(ctx);
-
/* NOTE: IndexBufferObj is guaranteed to be a VBO. */
ib.count = 0; /* unknown */
if (stride == 0)
stride = 4 * sizeof(GLuint); /* sizeof(DrawArraysIndirectCommand) */
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ FLUSH_FOR_DRAW(ctx);
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
if (stride == 0)
stride = 5 * sizeof(GLuint); /* sizeof(DrawElementsIndirectCommand) */
- if (_mesa_is_no_error_enabled(ctx)) {
- FLUSH_CURRENT(ctx, 0);
+ FLUSH_FOR_DRAW(ctx);
+ if (_mesa_is_no_error_enabled(ctx)) {
_mesa_set_draw_vao(ctx, ctx->Array.VAO, enabled_filter(ctx));
if (ctx->NewState)
vbo_exec_DrawElementsInstancedBaseVertexBaseInstance);
}
- if (ctx->API == API_OPENGL_CORE || _mesa_is_gles31(ctx)) {
+ if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles31(ctx)) {
SET_DrawArraysIndirect(exec, vbo_exec_DrawArraysIndirect);
SET_DrawElementsIndirect(exec, vbo_exec_DrawElementsIndirect);
}
- if (ctx->API == API_OPENGL_CORE) {
- SET_MultiDrawArraysIndirect(exec, vbo_exec_MultiDrawArraysIndirect);
- SET_MultiDrawElementsIndirect(exec, vbo_exec_MultiDrawElementsIndirect);
- SET_MultiDrawArraysIndirectCountARB(exec,
- vbo_exec_MultiDrawArraysIndirectCount);
- SET_MultiDrawElementsIndirectCountARB(exec,
- vbo_exec_MultiDrawElementsIndirectCount);
- }
-
if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) {
SET_DrawArraysInstancedARB(exec, vbo_exec_DrawArraysInstanced);
SET_DrawElementsInstancedARB(exec, vbo_exec_DrawElementsInstanced);
vbo_exec_DrawTransformFeedbackInstanced);
SET_DrawTransformFeedbackStreamInstanced(exec,
vbo_exec_DrawTransformFeedbackStreamInstanced);
+ SET_MultiDrawArraysIndirect(exec, vbo_exec_MultiDrawArraysIndirect);
+ SET_MultiDrawElementsIndirect(exec, vbo_exec_MultiDrawElementsIndirect);
+ SET_MultiDrawArraysIndirectCountARB(exec,
+ vbo_exec_MultiDrawArraysIndirectCount);
+ SET_MultiDrawElementsIndirectCountARB(exec,
+ vbo_exec_MultiDrawElementsIndirectCount);
}
}