#include "st_context.h"
#include "st_atom.h"
#include "st_cb_bufferobjects.h"
+#include "st_cb_xformfb.h"
#include "st_draw.h"
#include "st_program.h"
#include "util/u_format.h"
#include "util/u_prim.h"
#include "util/u_draw_quad.h"
+#include "util/u_upload_mgr.h"
#include "draw/draw_context.h"
#include "cso_cache/cso_context.h"
PIPE_FORMAT_R32G32B32A32_USCALED
};
+static GLuint uint_types_int[4] = {
+ PIPE_FORMAT_R32_UINT,
+ PIPE_FORMAT_R32G32_UINT,
+ PIPE_FORMAT_R32G32B32_UINT,
+ PIPE_FORMAT_R32G32B32A32_UINT
+};
+
static GLuint int_types_norm[4] = {
PIPE_FORMAT_R32_SNORM,
PIPE_FORMAT_R32G32_SNORM,
PIPE_FORMAT_R32G32B32A32_SSCALED
};
+static GLuint int_types_int[4] = {
+ PIPE_FORMAT_R32_SINT,
+ PIPE_FORMAT_R32G32_SINT,
+ PIPE_FORMAT_R32G32B32_SINT,
+ PIPE_FORMAT_R32G32B32A32_SINT
+};
+
static GLuint ushort_types_norm[4] = {
PIPE_FORMAT_R16_UNORM,
PIPE_FORMAT_R16G16_UNORM,
PIPE_FORMAT_R16G16B16A16_USCALED
};
+static GLuint ushort_types_int[4] = {
+ PIPE_FORMAT_R16_UINT,
+ PIPE_FORMAT_R16G16_UINT,
+ PIPE_FORMAT_R16G16B16_UINT,
+ PIPE_FORMAT_R16G16B16A16_UINT
+};
+
static GLuint short_types_norm[4] = {
PIPE_FORMAT_R16_SNORM,
PIPE_FORMAT_R16G16_SNORM,
PIPE_FORMAT_R16G16B16A16_SSCALED
};
+static GLuint short_types_int[4] = {
+ PIPE_FORMAT_R16_SINT,
+ PIPE_FORMAT_R16G16_SINT,
+ PIPE_FORMAT_R16G16B16_SINT,
+ PIPE_FORMAT_R16G16B16A16_SINT
+};
+
static GLuint ubyte_types_norm[4] = {
PIPE_FORMAT_R8_UNORM,
PIPE_FORMAT_R8G8_UNORM,
PIPE_FORMAT_R8G8B8A8_USCALED
};
+static GLuint ubyte_types_int[4] = {
+ PIPE_FORMAT_R8_UINT,
+ PIPE_FORMAT_R8G8_UINT,
+ PIPE_FORMAT_R8G8B8_UINT,
+ PIPE_FORMAT_R8G8B8A8_UINT
+};
+
static GLuint byte_types_norm[4] = {
PIPE_FORMAT_R8_SNORM,
PIPE_FORMAT_R8G8_SNORM,
PIPE_FORMAT_R8G8B8A8_SSCALED
};
+static GLuint byte_types_int[4] = {
+ PIPE_FORMAT_R8_SINT,
+ PIPE_FORMAT_R8G8_SINT,
+ PIPE_FORMAT_R8G8B8_SINT,
+ PIPE_FORMAT_R8G8B8A8_SINT
+};
+
static GLuint fixed_types[4] = {
PIPE_FORMAT_R32_FIXED,
PIPE_FORMAT_R32G32_FIXED,
*/
enum pipe_format
st_pipe_vertex_format(GLenum type, GLuint size, GLenum format,
- GLboolean normalized)
+ GLboolean normalized, GLboolean integer)
{
assert((type >= GL_BYTE && type <= GL_DOUBLE) ||
type == GL_FIXED || type == GL_HALF_FLOAT ||
if (type == GL_INT_2_10_10_10_REV ||
type == GL_UNSIGNED_INT_2_10_10_10_REV) {
assert(size == 4);
+ assert(!integer);
if (format == GL_BGRA) {
if (type == GL_INT_2_10_10_10_REV) {
return PIPE_FORMAT_B8G8R8A8_UNORM;
}
- if (normalized) {
+ if (integer) {
+ switch (type) {
+ case GL_INT: return int_types_int[size-1];
+ case GL_SHORT: return short_types_int[size-1];
+ case GL_BYTE: return byte_types_int[size-1];
+ case GL_UNSIGNED_INT: return uint_types_int[size-1];
+ case GL_UNSIGNED_SHORT: return ushort_types_int[size-1];
+ case GL_UNSIGNED_BYTE: return ubyte_types_int[size-1];
+ default: assert(0); return 0;
+ }
+ }
+ else if (normalized) {
switch (type) {
case GL_DOUBLE: return double_types[size-1];
case GL_FLOAT: return float_types[size-1];
if (abs(array->Ptr - firstPtr) > firstStride)
return GL_FALSE; /* arrays start too far apart */
- if ((!bufObj || !_mesa_is_bufferobj(bufObj)) != userSpaceBuffer)
+ if ((!_mesa_is_bufferobj(bufObj)) != userSpaceBuffer)
return GL_FALSE; /* mix of VBO and user-space arrays */
}
}
const struct st_vp_variant *vpv,
const struct gl_client_array **arrays,
struct pipe_vertex_buffer *vbuffer,
- struct pipe_vertex_element velements[],
- unsigned max_index,
- unsigned num_instances)
+ struct pipe_vertex_element velements[])
{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
GLuint attr;
const GLubyte *low_addr = NULL;
GLboolean usingVBO; /* all arrays in a VBO? */
struct gl_buffer_object *bufobj;
- GLuint user_buffer_size = 0;
- GLuint vertex_size = 0; /* bytes per vertex, in bytes */
GLsizei stride;
/* Find the lowest address of the arrays we're drawing,
}
/* are the arrays in user space? */
- usingVBO = bufobj && _mesa_is_bufferobj(bufobj);
+ usingVBO = _mesa_is_bufferobj(bufobj);
for (attr = 0; attr < vpv->num_inputs; attr++) {
const GLuint mesaAttr = vp->index_to_input[attr];
velements[attr].src_format = st_pipe_vertex_format(array->Type,
array->Size,
array->Format,
- array->Normalized);
+ array->Normalized,
+ array->Integer);
assert(velements[attr].src_format);
-
- if (!usingVBO) {
- /* how many bytes referenced by this attribute array? */
- uint divisor = array->InstanceDivisor;
- uint last_index = divisor ? num_instances / divisor : max_index;
- uint bytes = src_offset + stride * last_index + element_size;
-
- user_buffer_size = MAX2(user_buffer_size, bytes);
-
- /* update vertex size */
- vertex_size = MAX2(vertex_size, src_offset + element_size);
- }
}
/*
if (vpv->num_inputs == 0) {
/* just defensive coding here */
vbuffer->buffer = NULL;
+ vbuffer->user_buffer = NULL;
vbuffer->buffer_offset = 0;
vbuffer->stride = 0;
- st->num_user_attribs = 0;
}
else if (usingVBO) {
/* all interleaved arrays in a VBO */
struct st_buffer_object *stobj = st_buffer_object(bufobj);
- if (!stobj) {
- /* probably out of memory */
+ if (!stobj || !stobj->buffer) {
+ /* probably out of memory (or zero-sized buffer) */
return GL_FALSE;
}
- vbuffer->buffer = NULL;
- pipe_resource_reference(&vbuffer->buffer, stobj->buffer);
+ vbuffer->buffer = stobj->buffer;
+ vbuffer->user_buffer = NULL;
vbuffer->buffer_offset = pointer_to_offset(low_addr);
vbuffer->stride = stride;
- st->num_user_attribs = 0;
}
else {
/* all interleaved arrays in user memory */
- vbuffer->buffer = pipe_user_buffer_create(pipe->screen,
- (void*) low_addr,
- user_buffer_size,
- PIPE_BIND_VERTEX_BUFFER);
+ vbuffer->buffer = NULL;
+ vbuffer->user_buffer = low_addr;
vbuffer->buffer_offset = 0;
vbuffer->stride = stride;
-
- /* Track user vertex buffers. */
- pipe_resource_reference(&st->user_attrib[0].buffer, vbuffer->buffer);
- st->user_attrib[0].element_size = vertex_size;
- st->user_attrib[0].stride = stride;
- st->num_user_attribs = 1;
}
return GL_TRUE;
const struct st_vp_variant *vpv,
const struct gl_client_array **arrays,
struct pipe_vertex_buffer vbuffer[],
- struct pipe_vertex_element velements[],
- unsigned max_index,
- unsigned num_instances)
+ struct pipe_vertex_element velements[])
{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
GLuint attr;
for (attr = 0; attr < vpv->num_inputs; attr++) {
const GLuint mesaAttr = vp->index_to_input[attr];
const struct gl_client_array *array = arrays[mesaAttr];
struct gl_buffer_object *bufobj = array->BufferObj;
- GLuint element_size = array->_ElementSize;
GLsizei stride = array->StrideB;
- assert(element_size == array->Size * _mesa_sizeof_type(array->Type));
+ assert(array->_ElementSize == array->Size * _mesa_sizeof_type(array->Type));
- if (bufobj && _mesa_is_bufferobj(bufobj)) {
+ if (_mesa_is_bufferobj(bufobj)) {
/* Attribute data is in a VBO.
* Recall that for VBOs, the gl_client_array->Ptr field is
* really an offset from the start of the VBO, not a pointer.
struct st_buffer_object *stobj = st_buffer_object(bufobj);
if (!stobj || !stobj->buffer) {
- /* probably ran out of memory */
+ /* probably out of memory (or zero-sized buffer) */
return GL_FALSE;
}
- vbuffer[attr].buffer = NULL;
- pipe_resource_reference(&vbuffer[attr].buffer, stobj->buffer);
+ vbuffer[attr].buffer = stobj->buffer;
+ vbuffer[attr].user_buffer = NULL;
vbuffer[attr].buffer_offset = pointer_to_offset(array->Ptr);
}
else {
/* wrap user data */
- uint bytes;
void *ptr;
if (array->Ptr) {
- uint divisor = array->InstanceDivisor;
- uint last_index = divisor ? num_instances / divisor : max_index;
-
- bytes = stride * last_index + element_size;
-
ptr = (void *) array->Ptr;
}
else {
/* no array, use ctx->Current.Attrib[] value */
- bytes = element_size = sizeof(ctx->Current.Attrib[0]);
ptr = (void *) ctx->Current.Attrib[mesaAttr];
stride = 0;
}
assert(ptr);
- assert(bytes);
-
- vbuffer[attr].buffer =
- pipe_user_buffer_create(pipe->screen, ptr, bytes,
- PIPE_BIND_VERTEX_BUFFER);
+ vbuffer[attr].buffer = NULL;
+ vbuffer[attr].user_buffer = ptr;
vbuffer[attr].buffer_offset = 0;
-
- /* Track user vertex buffers. */
- pipe_resource_reference(&st->user_attrib[attr].buffer, vbuffer[attr].buffer);
- st->user_attrib[attr].element_size = element_size;
- st->user_attrib[attr].stride = stride;
- st->num_user_attribs = MAX2(st->num_user_attribs, attr + 1);
-
- if (!vbuffer[attr].buffer) {
- /* probably ran out of memory */
- return GL_FALSE;
- }
}
/* common-case setup */
velements[attr].src_format = st_pipe_vertex_format(array->Type,
array->Size,
array->Format,
- array->Normalized);
+ array->Normalized,
+ array->Integer);
assert(velements[attr].src_format);
}
static void
-setup_index_buffer(struct gl_context *ctx,
+setup_index_buffer(struct st_context *st,
const struct _mesa_index_buffer *ib,
struct pipe_index_buffer *ibuffer)
{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
+ struct gl_buffer_object *bufobj = ib->obj;
- memset(ibuffer, 0, sizeof(*ibuffer));
- if (ib) {
- struct gl_buffer_object *bufobj = ib->obj;
-
- switch (ib->type) {
- case GL_UNSIGNED_INT:
- ibuffer->index_size = 4;
- break;
- case GL_UNSIGNED_SHORT:
- ibuffer->index_size = 2;
- break;
- case GL_UNSIGNED_BYTE:
- ibuffer->index_size = 1;
- break;
- default:
- assert(0);
- return;
- }
+ ibuffer->index_size = vbo_sizeof_ib_type(ib->type);
- /* get/create the index buffer object */
- if (bufobj && _mesa_is_bufferobj(bufobj)) {
- /* elements/indexes are in a real VBO */
- struct st_buffer_object *stobj = st_buffer_object(bufobj);
- pipe_resource_reference(&ibuffer->buffer, stobj->buffer);
- ibuffer->offset = pointer_to_offset(ib->ptr);
- }
- else {
- /* element/indicies are in user space memory */
- ibuffer->buffer =
- pipe_user_buffer_create(pipe->screen, (void *) ib->ptr,
- ib->count * ibuffer->index_size,
- PIPE_BIND_INDEX_BUFFER);
- }
+ /* get/create the index buffer object */
+ if (_mesa_is_bufferobj(bufobj)) {
+ /* indices are in a real VBO */
+ ibuffer->buffer = st_buffer_object(bufobj)->buffer;
+ ibuffer->offset = pointer_to_offset(ib->ptr);
+ }
+ else if (st->indexbuf_uploader) {
+ u_upload_data(st->indexbuf_uploader, 0, ib->count * ibuffer->index_size,
+ ib->ptr, &ibuffer->offset, &ibuffer->buffer);
+ u_upload_unmap(st->indexbuf_uploader);
}
+ else {
+ /* indices are in user space memory */
+ ibuffer->user_buffer = ib->ptr;
+ }
+
+ cso_set_index_buffer(st->cso_context, ibuffer);
}
}
}
-/** Helper code for primitive restart fallback */
-#define DO_DRAW(pipe, cur_start, cur_count) \
- do { \
- info.start = cur_start; \
- info.count = cur_count; \
- if (u_trim_pipe_prim(info.mode, &info.count)) { \
- if (transfer) \
- pipe_buffer_unmap(pipe, transfer); \
- pipe->draw_vbo(pipe, &info); \
- if (transfer) { \
- ptr = pipe_buffer_map(pipe, ibuffer->buffer, PIPE_TRANSFER_READ, &transfer); \
- assert(ptr != NULL); \
- ptr = ADD_POINTERS(ptr, ibuffer->offset); \
- } \
- } \
- } while(0)
-
-/** More helper code for primitive restart fallback */
-#define PRIM_RESTART_LOOP(elements) \
- do { \
- for (i = start; i < end; i++) { \
- if (elements[i] == info.restart_index) { \
- if (cur_count > 0) { \
- /* draw elts up to prev pos */ \
- DO_DRAW(pipe, cur_start, cur_count); \
- } \
- /* begin new prim at next elt */ \
- cur_start = i + 1; \
- cur_count = 0; \
- } \
- else { \
- cur_count++; \
+
+/*
+ * Notes on primitive restart:
+ * The code below is used when the gallium driver does not support primitive
+ * restart itself. We map the index buffer, find the restart indexes, unmap
+ * the index buffer then draw the sub-primitives delineated by the restarts.
+ * A couple possible optimizations:
+ * 1. Save the list of sub-primitive (start, count) values in a list attached
+ * to the index buffer for re-use in subsequent draws. The list would be
+ * invalidated when the contents of the buffer changed.
+ * 2. If drawing triangle strips or quad strips, create a new index buffer
+ * that uses duplicated vertices to render the disjoint strips as one
+ * long strip. We'd have to be careful to avoid using too much memory
+ * for this.
+ * Finally, some apps might perform better if they don't use primitive restart
+ * at all rather than this fallback path. Set MESA_EXTENSION_OVERRIDE to
+ * "-GL_NV_primitive_restart" to test that.
+ */
+
+
+struct sub_primitive
+{
+ unsigned start, count;
+};
+
+
+/**
+ * Scan the elements array to find restart indexes. Return a list
+ * of primitive (start,count) pairs to indicate how to draw the sub-
+ * primitives delineated by the restart index.
+ */
+static struct sub_primitive *
+find_sub_primitives(const void *elements, unsigned element_size,
+ unsigned start, unsigned end, unsigned restart_index,
+ unsigned *num_sub_prims)
+{
+ const unsigned max_prims = end - start;
+ struct sub_primitive *sub_prims;
+ unsigned i, cur_start, cur_count, num;
+
+ sub_prims = (struct sub_primitive *)
+ malloc(max_prims * sizeof(struct sub_primitive));
+
+ if (!sub_prims) {
+ *num_sub_prims = 0;
+ return NULL;
+ }
+
+ cur_start = start;
+ cur_count = 0;
+ num = 0;
+
+#define SCAN_ELEMENTS(TYPE) \
+ for (i = start; i < end; i++) { \
+ if (((const TYPE *) elements)[i] == restart_index) { \
+ if (cur_count > 0) { \
+ assert(num < max_prims); \
+ sub_prims[num].start = cur_start; \
+ sub_prims[num].count = cur_count; \
+ num++; \
} \
+ cur_start = i + 1; \
+ cur_count = 0; \
} \
- if (cur_count > 0) { \
- DO_DRAW(pipe, cur_start, cur_count); \
+ else { \
+ cur_count++; \
} \
- } while (0)
+ } \
+ if (cur_count > 0) { \
+ assert(num < max_prims); \
+ sub_prims[num].start = cur_start; \
+ sub_prims[num].count = cur_count; \
+ num++; \
+ }
+
+ switch (element_size) {
+ case 1:
+ SCAN_ELEMENTS(ubyte);
+ break;
+ case 2:
+ SCAN_ELEMENTS(ushort);
+ break;
+ case 4:
+ SCAN_ELEMENTS(uint);
+ break;
+ default:
+ assert(0 && "bad index_size in find_sub_primitives()");
+ }
+
+#undef SCAN_ELEMENTS
+
+ *num_sub_prims = num;
+
+ return sub_prims;
+}
+
+/**
+ * For gallium drivers that don't support the primitive restart
+ * feature, handle it here by breaking up the indexed primitive into
+ * sub-primitives.
+ */
static void
-handle_fallback_primitive_restart(struct pipe_context *pipe,
+handle_fallback_primitive_restart(struct cso_context *cso,
+ struct pipe_context *pipe,
const struct _mesa_index_buffer *ib,
struct pipe_index_buffer *ibuffer,
struct pipe_draw_info *orig_info)
{
const unsigned start = orig_info->start;
const unsigned count = orig_info->count;
- const unsigned end = start + count;
struct pipe_draw_info info = *orig_info;
struct pipe_transfer *transfer = NULL;
- unsigned instance, i, cur_start, cur_count;
- const void *ptr;
-
- info.primitive_restart = FALSE;
+ unsigned instance, i;
+ const void *ptr = NULL;
+ struct sub_primitive *sub_prims;
+ unsigned num_sub_prims;
- if (!info.indexed) {
- /* Splitting the draw arrays call is handled by the VBO module */
- if (u_trim_pipe_prim(info.mode, &info.count))
- pipe->draw_vbo(pipe, &info);
+ assert(info.indexed);
+ assert(ibuffer->buffer || ibuffer->user_buffer);
+ assert(ib);
+ if (!ibuffer->buffer || !ibuffer->user_buffer || !ib)
return;
- }
- /* info.indexed == TRUE */
- assert(ibuffer);
- assert(ibuffer->buffer);
+ info.primitive_restart = FALSE;
+ info.instance_count = 1;
- if (ib) {
- struct gl_buffer_object *bufobj = ib->obj;
- if (bufobj && bufobj->Name) {
- ptr = NULL;
- }
- else {
- ptr = ib->ptr;
- }
- } else {
- ptr = NULL;
+ if (_mesa_is_bufferobj(ib->obj)) {
+ ptr = pipe_buffer_map_range(pipe, ibuffer->buffer,
+ start * ibuffer->index_size, /* start */
+ count * ibuffer->index_size, /* length */
+ PIPE_TRANSFER_READ, &transfer);
+ if (!ptr)
+ return;
+
+ ptr = (uint8_t*)ptr + (ibuffer->offset - start * ibuffer->index_size);
+ }
+ else {
+ ptr = ib->ptr;
+ if (!ptr)
+ return;
}
- if (!ptr)
- ptr = pipe_buffer_map(pipe, ibuffer->buffer, PIPE_TRANSFER_READ, &transfer);
+ sub_prims = find_sub_primitives(ptr, ibuffer->index_size,
+ 0, count, orig_info->restart_index,
+ &num_sub_prims);
- if (!ptr)
- return;
- ptr = ADD_POINTERS(ptr, ibuffer->offset);
+ if (transfer)
+ pipe_buffer_unmap(pipe, transfer);
- /* Need to loop over instances as well to preserve draw order */
+ /* Now draw the sub primitives.
+ * Need to loop over instances as well to preserve draw order.
+ */
for (instance = 0; instance < orig_info->instance_count; instance++) {
info.start_instance = instance + orig_info->start_instance;
- info.instance_count = 1;
- cur_start = start;
- cur_count = 0;
-
- switch (ibuffer->index_size) {
- case 1:
- {
- const ubyte *elt_ub = (const ubyte *)ptr;
- PRIM_RESTART_LOOP(elt_ub);
+ for (i = 0; i < num_sub_prims; i++) {
+ info.start = sub_prims[i].start;
+ info.count = sub_prims[i].count;
+ if (u_trim_pipe_prim(info.mode, &info.count)) {
+ cso_draw_vbo(cso, &info);
}
- break;
- case 2:
- {
- const ushort *elt_us = (const ushort *)ptr;
- PRIM_RESTART_LOOP(elt_us);
- }
- break;
- case 4:
- {
- const uint *elt_ui = (const uint *)ptr;
- PRIM_RESTART_LOOP(elt_ui);
- }
- break;
- default:
- assert(0 && "bad index_size in handle_fallback_primitive_restart()");
}
}
- if (transfer)
- pipe_buffer_unmap(pipe, transfer);
+ if (sub_prims)
+ free(sub_prims);
}
*/
static GLboolean
st_validate_varrays(struct gl_context *ctx,
- const struct gl_client_array **arrays,
- unsigned max_index,
- unsigned num_instances)
+ const struct gl_client_array **arrays)
{
struct st_context *st = st_context(ctx);
const struct st_vertex_program *vp;
struct pipe_vertex_buffer vbuffer[PIPE_MAX_SHADER_INPUTS];
struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS];
unsigned num_vbuffers, num_velements;
- GLuint attr;
- unsigned i;
/* must get these after state validation! */
vp = st->vp;
memset(velements, 0, sizeof(struct pipe_vertex_element) * vpv->num_inputs);
- /* Unreference any user vertex buffers. */
- for (i = 0; i < st->num_user_attribs; i++) {
- pipe_resource_reference(&st->user_attrib[i].buffer, NULL);
- }
- st->num_user_attribs = 0;
-
/*
* Setup the vbuffer[] and velements[] arrays.
*/
if (is_interleaved_arrays(vp, vpv, arrays)) {
- if (!setup_interleaved_attribs(ctx, vp, vpv, arrays, vbuffer, velements,
- max_index, num_instances)) {
+ if (!setup_interleaved_attribs(ctx, vp, vpv, arrays, vbuffer,
+ velements)) {
return GL_FALSE;
}
}
else {
if (!setup_non_interleaved_attribs(ctx, vp, vpv, arrays,
- vbuffer, velements, max_index,
- num_instances)) {
+ vbuffer, velements)) {
return GL_FALSE;
}
cso_set_vertex_buffers(st->cso_context, num_vbuffers, vbuffer);
cso_set_vertex_elements(st->cso_context, num_velements, velements);
- /* unreference buffers (frees wrapped user-space buffer objects)
- * This is OK, because the pipe driver should reference buffers by itself
- * in set_vertex_buffers. */
- for (attr = 0; attr < num_vbuffers; attr++) {
- pipe_resource_reference(&vbuffer[attr].buffer, NULL);
- assert(!vbuffer[attr].buffer);
- }
-
return GL_TRUE;
}
*/
void
st_draw_vbo(struct gl_context *ctx,
- const struct gl_client_array **arrays,
const struct _mesa_prim *prims,
GLuint nr_prims,
const struct _mesa_index_buffer *ib,
GLboolean index_bounds_valid,
GLuint min_index,
- GLuint max_index)
+ GLuint max_index,
+ struct gl_transform_feedback_object *tfb_vertcount)
{
struct st_context *st = st_context(ctx);
struct pipe_context *pipe = st->pipe;
- struct pipe_index_buffer ibuffer;
+ struct pipe_index_buffer ibuffer = {0};
struct pipe_draw_info info;
- unsigned i, num_instances = 1;
- GLboolean new_array =
- st->dirty.st &&
- (st->dirty.mesa & (_NEW_ARRAY | _NEW_PROGRAM | _NEW_BUFFER_OBJECT)) != 0;
+ const struct gl_client_array **arrays = ctx->Array._DrawArrays;
+ unsigned i;
+ GLboolean new_array;
/* Mesa core state should have been validated already */
assert(ctx->NewState == 0x0);
- if (ib) {
- /* Gallium probably doesn't want this in some cases. */
- if (!index_bounds_valid)
- if (!all_varyings_in_vbos(arrays))
- vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index);
+ /* Get Mesa driver state. */
+ st->dirty.st |= ctx->NewDriverState;
+ ctx->NewDriverState = 0;
- for (i = 0; i < nr_prims; i++) {
- num_instances = MAX2(num_instances, prims[i].num_instances);
- }
- }
- else {
- /* Get min/max index for non-indexed drawing. */
- min_index = ~0;
- max_index = 0;
-
- for (i = 0; i < nr_prims; i++) {
- min_index = MIN2(min_index, prims[i].start);
- max_index = MAX2(max_index, prims[i].start + prims[i].count - 1);
- num_instances = MAX2(num_instances, prims[i].num_instances);
- }
- }
+ new_array =
+ (st->dirty.st & (ST_NEW_VERTEX_ARRAYS | ST_NEW_VERTEX_PROGRAM)) ||
+ (st->dirty.mesa & (_NEW_PROGRAM | _NEW_BUFFER_OBJECT)) != 0;
/* Validate state. */
if (st->dirty.st) {
GLboolean vertDataEdgeFlags;
- /* sanity check for pointer arithmetic below */
- assert(sizeof(arrays[0]->Ptr[0]) == 1);
-
vertDataEdgeFlags = arrays[VERT_ATTRIB_EDGEFLAG]->BufferObj &&
arrays[VERT_ATTRIB_EDGEFLAG]->BufferObj->Name;
if (vertDataEdgeFlags != st->vertdata_edgeflags) {
st_validate_state(st);
if (new_array) {
- if (!st_validate_varrays(ctx, arrays, max_index, num_instances)) {
+ if (!st_validate_varrays(ctx, arrays)) {
/* probably out of memory, no-op the draw call */
return;
}
#endif
}
- /* Notify the driver that the content of user buffers may have been
- * changed. */
- assert(max_index >= min_index);
- if (!new_array && st->num_user_attribs) {
- for (i = 0; i < st->num_user_attribs; i++) {
- if (st->user_attrib[i].buffer) {
- unsigned element_size = st->user_attrib[i].element_size;
- unsigned stride = st->user_attrib[i].stride;
- unsigned min_offset = min_index * stride;
- unsigned max_offset = max_index * stride + element_size;
-
- assert(max_offset > min_offset);
-
- pipe->redefine_user_buffer(pipe, st->user_attrib[i].buffer,
- min_offset,
- max_offset - min_offset);
- }
- }
- }
-
- setup_index_buffer(ctx, ib, &ibuffer);
- pipe->set_index_buffer(pipe, &ibuffer);
-
util_draw_init_info(&info);
if (ib) {
+ /* Get index bounds for user buffers. */
+ if (!index_bounds_valid)
+ if (!all_varyings_in_vbos(arrays))
+ vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index,
+ nr_prims);
+
+ setup_index_buffer(st, ib, &ibuffer);
+
info.indexed = TRUE;
if (min_index != ~0 && max_index != ~0) {
info.min_index = min_index;
info.max_index = max_index;
}
- }
- info.primitive_restart = ctx->Array.PrimitiveRestart;
- info.restart_index = ctx->Array.RestartIndex;
+ /* The VBO module handles restart for the non-indexed GLDrawArrays
+ * so we only set these fields for indexed drawing:
+ */
+ info.primitive_restart = ctx->Array.PrimitiveRestart;
+ info.restart_index = ctx->Array.RestartIndex;
+ }
+ else {
+ /* Transform feedback drawing is always non-indexed. */
+ /* Set info.count_from_stream_output. */
+ if (tfb_vertcount) {
+ st_transform_feedback_draw_init(tfb_vertcount, &info);
+ }
+ }
/* do actual drawing */
for (i = 0; i < nr_prims; i++) {
info.max_index = info.start + info.count - 1;
}
- if (info.primitive_restart) {
- /*
- * Handle primitive restart for drivers that doesn't support it.
- *
- * The VBO module handles restart inside of draw_arrays for us,
- * but we should still remove the primitive_restart flag on the
- * info struct, the fallback function does this for us. Just
- * remove the flag for all drivers in this case as well.
- */
- if (st->sw_primitive_restart || !info.indexed)
- handle_fallback_primitive_restart(pipe, ib, &ibuffer, &info);
- else
+ if (info.count_from_stream_output) {
+ cso_draw_vbo(st->cso_context, &info);
+ }
+ else if (info.primitive_restart) {
+ if (st->sw_primitive_restart) {
+ /* Handle primitive restart for drivers that doesn't support it */
+ handle_fallback_primitive_restart(st->cso_context, pipe, ib,
+ &ibuffer, &info);
+ }
+ else {
/* don't trim, restarts might be inside index list */
- pipe->draw_vbo(pipe, &info);
+ cso_draw_vbo(st->cso_context, &info);
+ }
}
else if (u_trim_pipe_prim(info.mode, &info.count))
- pipe->draw_vbo(pipe, &info);
+ cso_draw_vbo(st->cso_context, &info);
}
- pipe_resource_reference(&ibuffer.buffer, NULL);
+ if (ib && st->indexbuf_uploader && !_mesa_is_bufferobj(ib->obj)) {
+ pipe_resource_reference(&ibuffer.buffer, NULL);
+ }
}