/**************************************************************************
*
- * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2003 VMware, Inc.
* Copyright 2009 VMware, Inc.
* All Rights Reserved.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
}
/* check element j of each enabled array */
- for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) {
- check_array_data(ctx, &arrayObj->VertexAttrib[k], k, j);
+ for (k = 0; k < Elements(arrayObj->_VertexAttrib); k++) {
+ check_array_data(ctx, &arrayObj->_VertexAttrib[k], k, j);
}
}
ctx->Driver.UnmapBuffer(ctx, ctx->Array.ArrayObj->ElementArrayBufferObj);
}
- for (k = 0; k < Elements(arrayObj->VertexAttrib); k++) {
- unmap_array_buffer(ctx, &arrayObj->VertexAttrib[k]);
+ for (k = 0; k < Elements(arrayObj->_VertexAttrib); k++) {
+ unmap_array_buffer(ctx, &arrayObj->_VertexAttrib[k]);
}
}
exec->array.inputs[i]->Size,
stride,
/*exec->array.inputs[i]->Enabled,*/
- arrayObj->VertexAttrib[VERT_ATTRIB_FF(i)].Enabled,
+ arrayObj->_VertexAttrib[VERT_ATTRIB_FF(i)].Enabled,
exec->array.inputs[i]->Ptr,
bufName);
{
struct vbo_context *vbo = vbo_context(ctx);
struct vbo_exec_context *exec = &vbo->exec;
- struct gl_client_array *vertexAttrib = ctx->Array.ArrayObj->VertexAttrib;
+ struct gl_client_array *vertexAttrib = ctx->Array.ArrayObj->_VertexAttrib;
const struct gl_client_array **inputs = &exec->array.inputs[0];
GLbitfield64 const_inputs = 0x0;
GLuint i;
break;
case VP_ARB:
- /* GL_ARB_vertex_program or GLSL vertex shader - Only the generic[0]
+ /* There are no shaders in OpenGL ES 1.x, so this code path should be
+ * impossible to reach. The meta code is careful to not use shaders in
+ * ES1.
+ */
+ assert(ctx->API != API_OPENGLES);
+
+ /* In the compatibility profile of desktop OpenGL, the generic[0]
* attribute array aliases and overrides the legacy position array.
- *
* Otherwise, legacy attributes available in the legacy slots,
* generic attributes in the generic slots and materials are not
* available as per-vertex attributes.
+ *
+ * In all other APIs, only the generic attributes exist, and none of the
+ * slots are considered "magic."
*/
- if (vertexAttrib[VERT_ATTRIB_GENERIC0].Enabled)
- inputs[0] = &vertexAttrib[VERT_ATTRIB_GENERIC0];
- else if (vertexAttrib[VERT_ATTRIB_POS].Enabled)
- inputs[0] = &vertexAttrib[VERT_ATTRIB_POS];
- else {
- inputs[0] = &vbo->currval[VBO_ATTRIB_POS];
- const_inputs |= VERT_BIT_POS;
- }
+ if (ctx->API == API_OPENGL_COMPAT) {
+ if (vertexAttrib[VERT_ATTRIB_GENERIC0].Enabled)
+ inputs[0] = &vertexAttrib[VERT_ATTRIB_GENERIC0];
+ else if (vertexAttrib[VERT_ATTRIB_POS].Enabled)
+ inputs[0] = &vertexAttrib[VERT_ATTRIB_POS];
+ else {
+ inputs[0] = &vbo->currval[VBO_ATTRIB_POS];
+ const_inputs |= VERT_BIT_POS;
+ }
- for (i = 1; i < VERT_ATTRIB_FF_MAX; i++) {
- if (vertexAttrib[VERT_ATTRIB_FF(i)].Enabled)
- inputs[i] = &vertexAttrib[VERT_ATTRIB_FF(i)];
- else {
- inputs[i] = &vbo->currval[VBO_ATTRIB_POS+i];
+ for (i = 1; i < VERT_ATTRIB_FF_MAX; i++) {
+ if (vertexAttrib[VERT_ATTRIB_FF(i)].Enabled)
+ inputs[i] = &vertexAttrib[VERT_ATTRIB_FF(i)];
+ else {
+ inputs[i] = &vbo->currval[VBO_ATTRIB_POS+i];
+ const_inputs |= VERT_BIT_FF(i);
+ }
+ }
+
+ for (i = 1; i < VERT_ATTRIB_GENERIC_MAX; i++) {
+ if (vertexAttrib[VERT_ATTRIB_GENERIC(i)].Enabled)
+ inputs[VERT_ATTRIB_GENERIC(i)] =
+ &vertexAttrib[VERT_ATTRIB_GENERIC(i)];
+ else {
+ inputs[VERT_ATTRIB_GENERIC(i)] =
+ &vbo->currval[VBO_ATTRIB_GENERIC0+i];
+ const_inputs |= VERT_BIT_GENERIC(i);
+ }
+ }
+
+ inputs[VERT_ATTRIB_GENERIC0] = inputs[0];
+ } else {
+ /* Other parts of the code assume that inputs[0] through
+ * inputs[VERT_ATTRIB_FF_MAX] will be non-NULL. However, in OpenGL
+ * ES 2.0+ or OpenGL core profile, none of these arrays should ever
+ * be enabled.
+ */
+ for (i = 0; i < VERT_ATTRIB_FF_MAX; i++) {
+ assert(!vertexAttrib[VERT_ATTRIB_FF(i)].Enabled);
+
+ inputs[i] = &vbo->currval[VBO_ATTRIB_POS+i];
const_inputs |= VERT_BIT_FF(i);
}
- }
- for (i = 1; i < VERT_ATTRIB_GENERIC_MAX; i++) {
- if (vertexAttrib[VERT_ATTRIB_GENERIC(i)].Enabled)
- inputs[VERT_ATTRIB_GENERIC(i)] = &vertexAttrib[VERT_ATTRIB_GENERIC(i)];
- else {
- inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->currval[VBO_ATTRIB_GENERIC0+i];
- const_inputs |= VERT_BIT_GENERIC(i);
+ for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; i++) {
+ if (vertexAttrib[VERT_ATTRIB_GENERIC(i)].Enabled)
+ inputs[VERT_ATTRIB_GENERIC(i)] =
+ &vertexAttrib[VERT_ATTRIB_GENERIC(i)];
+ else {
+ inputs[VERT_ATTRIB_GENERIC(i)] =
+ &vbo->currval[VBO_ATTRIB_GENERIC0+i];
+ const_inputs |= VERT_BIT_GENERIC(i);
+ }
}
}
- inputs[VERT_ATTRIB_GENERIC0] = inputs[0];
break;
}
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);
}
}
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) {
/* 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 {
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) {
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;
}
}
+ /* Draw primitives individually if one count is zero, so we can easily skip
+ * that primitive.
+ */
+ for (i = 0; i < primcount; i++) {
+ if (count[i] == 0) {
+ fallback = GL_TRUE;
+ break;
+ }
+ }
+
/* If the index buffer isn't in a VBO, then treating the application's
* subranges of the index buffer as one large index buffer may lead to
* us reading unmapped memory.
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
} else {
/* render one prim at a time */
for (i = 0; i < primcount; i++) {
+ if (count[i] == 0)
+ continue;
ib.count = count[i];
ib.type = type;
ib.obj = ctx->Array.ArrayObj->ElementArrayBufferObj;
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
static void GLAPIENTRY
vbo_exec_MultiDrawElements(GLenum mode,
const GLsizei *count, GLenum type,
- const GLvoid **indices,
+ const GLvoid * const *indices,
GLsizei primcount)
{
GET_CURRENT_CONTEXT(ctx);
return;
}
+ if (ctx->Driver.GetTransformFeedbackVertexCount &&
+ (ctx->Const.AlwaysUseGetTransformFeedbackVertexCount ||
+ (ctx->Const.PrimitiveRestartInSoftware &&
+ ctx->Array._PrimitiveRestart) ||
+ !vbo_all_varyings_in_vbos(exec->array.inputs))) {
+ GLsizei n = ctx->Driver.GetTransformFeedbackVertexCount(ctx, obj, stream);
+ vbo_draw_arrays(ctx, mode, 0, n, numInstances, 0);
+ return;
+ }
+
vbo_bind_arrays(ctx);
/* init most fields to zero */
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
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);
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.
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);