tnl/t_pipeline.h \
tnl/t_rebase.c \
tnl/t_rebase.h \
+ tnl/t_split.c \
+ tnl/t_split_copy.c \
+ tnl/t_split.h \
+ tnl/t_split_inplace.c \
tnl/t_vb_cliptmp.h \
tnl/t_vb_fog.c \
tnl/t_vb_light.c \
vbo/vbo_save.c \
vbo/vbo_save_draw.c \
vbo/vbo_save.h \
- vbo/vbo_save_loopback.c \
- vbo/vbo_split.c \
- vbo/vbo_split_copy.c \
- vbo/vbo_split.h \
- vbo/vbo_split_inplace.c
+ vbo/vbo_save_loopback.c
STATETRACKER_FILES = \
state_tracker/st_atifs_to_tgsi.c \
.max_vb_size = ~0,
};
- vbo_split_prims(ctx, arrays, prims, nr_prims, ib, min_index,
- max_index, TAG(vbo_render_prims), &limits);
+ _tnl_split_prims(ctx, arrays, prims, nr_prims, ib, min_index,
+ max_index, TAG(vbo_render_prims), &limits);
return GL_TRUE;
}
'vbo/vbo_save_draw.c',
'vbo/vbo_save.h',
'vbo/vbo_save_loopback.c',
- 'vbo/vbo_split.c',
- 'vbo/vbo_split_copy.c',
- 'vbo/vbo_split.h',
- 'vbo/vbo_split_inplace.c',
'x86/common_x86.c',
)
'tnl/t_pipeline.c',
'tnl/t_pipeline.h',
'tnl/t_rebase.c',
+ 'tnl/t_split.c',
+ 'tnl/t_split_copy.c',
+ 'tnl/t_split.h',
+ 'tnl/t_split_inplace.c',
'tnl/t_vb_cliptmp.h',
'tnl/t_vb_fog.c',
'tnl/t_vb_light.c',
/* This will split the buffers one way or another and
* recursively call back into this function.
*/
- vbo_split_prims( ctx, arrays, prim, nr_prims, ib,
- 0, max_index + prim->basevertex,
- _tnl_draw_prims,
- &limits );
+ _tnl_split_prims( ctx, arrays, prim, nr_prims, ib,
+ 0, max_index + prim->basevertex,
+ _tnl_draw_prims,
+ &limits );
}
else {
/* May need to map a vertex buffer object for every attribute plus
#include "main/glheader.h"
#include "main/imports.h"
#include "main/mtypes.h"
+#include "vbo/vbo.h"
#include "t_rebase.h"
const struct _mesa_index_buffer *ib,
GLuint min_index,
GLuint max_index,
- vbo_draw_func draw )
+ tnl_draw_func draw )
{
struct gl_array_attributes tmp_attribs[VERT_ATTRIB_MAX];
struct gl_vertex_array tmp_arrays[VERT_ATTRIB_MAX];
#ifndef _T_REBASE_H_
#define _T_REBASE_H_
-#include "vbo/vbo.h"
+#include "tnl.h"
void t_rebase_prims( struct gl_context *ctx,
const struct gl_vertex_array *arrays,
const struct _mesa_index_buffer *ib,
GLuint min_index,
GLuint max_index,
- vbo_draw_func draw );
+ tnl_draw_func draw );
#endif
--- /dev/null
+
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ * Keith Whitwell <keithw@vmware.com>
+ */
+
+/* Deal with hardware and/or swtnl maximums:
+ * - maximum number of vertices in buffer
+ * - maximum number of elements (maybe zero)
+ *
+ * The maximums may vary with opengl state (eg if a larger hardware
+ * vertex is required in this state, the maximum number of vertices
+ * may be smaller than in another state).
+ *
+ * We want buffer splitting to be a convenience function for the code
+ * actually drawing the primitives rather than a system-wide maximum,
+ * otherwise it is hard to avoid pessimism.
+ *
+ * For instance, if a driver has no hardware limits on vertex buffer
+ * dimensions, it would not ordinarily want to split vbos. But if
+ * there is an unexpected fallback, eg memory manager fails to upload
+ * textures, it will want to pass the drawing commands onto swtnl,
+ * which does have limitations. A convenience function allows swtnl
+ * to split the drawing and vbos internally without imposing its
+ * limitations on drivers which want to use it as a fallback path.
+ */
+
+#include "main/glheader.h"
+#include "main/mtypes.h"
+#include "vbo/vbo.h"
+
+#include "t_split.h"
+
+
+/* True if a primitive can be split without copying of vertices, false
+ * otherwise.
+ */
+GLboolean
+_tnl_split_prim_inplace(GLenum mode, GLuint *first, GLuint *incr)
+{
+ switch (mode) {
+ case GL_POINTS:
+ *first = 1;
+ *incr = 1;
+ return GL_TRUE;
+ case GL_LINES:
+ *first = 2;
+ *incr = 2;
+ return GL_TRUE;
+ case GL_LINE_STRIP:
+ *first = 2;
+ *incr = 1;
+ return GL_TRUE;
+ case GL_TRIANGLES:
+ *first = 3;
+ *incr = 3;
+ return GL_TRUE;
+ case GL_TRIANGLE_STRIP:
+ *first = 3;
+ *incr = 1;
+ return GL_TRUE;
+ case GL_QUADS:
+ *first = 4;
+ *incr = 4;
+ return GL_TRUE;
+ case GL_QUAD_STRIP:
+ *first = 4;
+ *incr = 2;
+ return GL_TRUE;
+ default:
+ *first = 0;
+ *incr = 1; /* so that count % incr works */
+ return GL_FALSE;
+ }
+}
+
+
+
+void
+_tnl_split_prims(struct gl_context *ctx,
+ const struct gl_vertex_array arrays[],
+ const struct _mesa_prim *prim,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ GLuint min_index,
+ GLuint max_index,
+ tnl_draw_func draw,
+ const struct split_limits *limits)
+{
+ if (ib) {
+ if (limits->max_indices == 0) {
+ /* Could traverse the indices, re-emitting vertices in turn.
+ * But it's hard to see why this case would be needed - for
+ * software tnl, it is better to convert to non-indexed
+ * rendering after transformation is complete. Are there any devices
+ * with hardware tnl that cannot do indexed rendering?
+ *
+ * For now, this path is disabled.
+ */
+ assert(0);
+ }
+ else if (max_index - min_index >= limits->max_verts) {
+ /* The vertex buffers are too large for hardware (or the
+ * swtnl module). Traverse the indices, re-emitting vertices
+ * in turn. Use a vertex cache to preserve some of the
+ * sharing from the original index list.
+ */
+ _tnl_split_copy(ctx, arrays, prim, nr_prims, ib, draw, limits);
+ }
+ else if (ib->count > limits->max_indices) {
+ /* The index buffer is too large for hardware. Try to split
+ * on whole-primitive boundaries, otherwise try to split the
+ * individual primitives.
+ */
+ _tnl_split_inplace(ctx, arrays, prim, nr_prims, ib,
+ min_index, max_index, draw, limits);
+ }
+ else {
+ /* Why were we called? */
+ assert(0);
+ }
+ }
+ else {
+ if (max_index - min_index >= limits->max_verts) {
+ /* The vertex buffer is too large for hardware (or the swtnl
+ * module). Try to split on whole-primitive boundaries,
+ * otherwise try to split the individual primitives.
+ */
+ _tnl_split_inplace(ctx, arrays, prim, nr_prims, ib,
+ min_index, max_index, draw, limits);
+ }
+ else {
+ /* Why were we called? */
+ assert(0);
+ }
+ }
+}
+
--- /dev/null
+/*
+ * mesa 3-D graphics library
+ *
+ * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+/**
+ * \brief VBO builder module datatypes and definitions.
+ * \author Keith Whitwell
+ */
+
+
+/**
+ * \mainpage The TNL splitter
+ *
+ * This is the private data used internally to the _tnl_split_prims()
+ * helper function. Nobody outside the _tnl_split* files needs to
+ * include or know about this structure.
+ */
+
+
+#ifndef _TNL_SPLIT_H
+#define _TNL_SPLIT_H
+
+#include "tnl.h"
+
+
+/* True if a primitive can be split without copying of vertices, false
+ * otherwise.
+ */
+GLboolean
+_tnl_split_prim_inplace(GLenum mode, GLuint *first, GLuint *incr);
+
+void
+_tnl_split_inplace(struct gl_context *ctx,
+ const struct gl_vertex_array arrays[],
+ const struct _mesa_prim *prim,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ GLuint min_index,
+ GLuint max_index,
+ tnl_draw_func draw,
+ const struct split_limits *limits);
+
+/* Requires ib != NULL:
+ */
+void
+_tnl_split_copy(struct gl_context *ctx,
+ const struct gl_vertex_array arrays[],
+ const struct _mesa_prim *prim,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ tnl_draw_func draw,
+ const struct split_limits *limits);
+
+#endif
--- /dev/null
+
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ * Keith Whitwell <keithw@vmware.com>
+ */
+
+/* Split indexed primitives with per-vertex copying.
+ */
+
+#include <stdio.h>
+
+#include "main/glheader.h"
+#include "main/bufferobj.h"
+#include "main/imports.h"
+#include "main/glformats.h"
+#include "main/macros.h"
+#include "main/mtypes.h"
+#include "main/varray.h"
+#include "vbo/vbo.h"
+
+#include "t_split.h"
+#include "tnl.h"
+
+
+#define ELT_TABLE_SIZE 16
+
+/**
+ * Used for vertex-level splitting of indexed buffers. Note that
+ * non-indexed primitives may be converted to indexed in some cases
+ * (eg loops, fans) in order to use this splitting path.
+ */
+struct copy_context {
+ struct gl_context *ctx;
+ const struct gl_vertex_array *array;
+ const struct _mesa_prim *prim;
+ GLuint nr_prims;
+ const struct _mesa_index_buffer *ib;
+ tnl_draw_func draw;
+
+ const struct split_limits *limits;
+
+ struct {
+ GLuint attr;
+ GLuint size;
+ const struct gl_vertex_array *array;
+ const GLubyte *src_ptr;
+
+ struct gl_vertex_buffer_binding dstbinding;
+ struct gl_array_attributes dstattribs;
+
+ } varying[VERT_ATTRIB_MAX];
+ GLuint nr_varying;
+
+ struct gl_vertex_array dstarray[VERT_ATTRIB_MAX];
+ struct _mesa_index_buffer dstib;
+
+ GLuint *translated_elt_buf;
+ const GLuint *srcelt;
+
+ /** A baby hash table to avoid re-emitting (some) duplicate
+ * vertices when splitting indexed primitives.
+ */
+ struct {
+ GLuint in;
+ GLuint out;
+ } vert_cache[ELT_TABLE_SIZE];
+
+ GLuint vertex_size;
+ GLubyte *dstbuf;
+ GLubyte *dstptr; /**< dstptr == dstbuf + dstelt_max * vertsize */
+ GLuint dstbuf_size; /**< in vertices */
+ GLuint dstbuf_nr; /**< count of emitted vertices, also the largest value
+ * in dstelt. Our MaxIndex.
+ */
+
+ GLuint *dstelt;
+ GLuint dstelt_nr;
+ GLuint dstelt_size;
+
+#define MAX_PRIM 32
+ struct _mesa_prim dstprim[MAX_PRIM];
+ GLuint dstprim_nr;
+};
+
+
+static GLuint
+attr_size(const struct gl_array_attributes *attrib)
+{
+ return attrib->Size * _mesa_sizeof_type(attrib->Type);
+}
+
+
+/**
+ * Starts returning true slightly before the buffer fills, to ensure
+ * that there is sufficient room for any remaining vertices to finish
+ * off the prim:
+ */
+static GLboolean
+check_flush(struct copy_context *copy)
+{
+ GLenum mode = copy->dstprim[copy->dstprim_nr].mode;
+
+ if (GL_TRIANGLE_STRIP == mode &&
+ copy->dstelt_nr & 1) { /* see bug9962 */
+ return GL_FALSE;
+ }
+
+ if (copy->dstbuf_nr + 4 > copy->dstbuf_size)
+ return GL_TRUE;
+
+ if (copy->dstelt_nr + 4 > copy->dstelt_size)
+ return GL_TRUE;
+
+ return GL_FALSE;
+}
+
+
+/**
+ * Dump the parameters/info for a vbo->draw() call.
+ */
+static void
+dump_draw_info(struct gl_context *ctx,
+ const struct gl_vertex_array *arrays,
+ const struct _mesa_prim *prims,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ GLuint min_index,
+ GLuint max_index)
+{
+ GLuint i, j;
+
+ printf("VBO Draw:\n");
+ for (i = 0; i < nr_prims; i++) {
+ printf("Prim %u of %u\n", i, nr_prims);
+ printf(" Prim mode 0x%x\n", prims[i].mode);
+ printf(" IB: %p\n", (void*) ib);
+ for (j = 0; j < VERT_ATTRIB_MAX; j++) {
+ const struct gl_vertex_array *array = &arrays[j];
+ const struct gl_vertex_buffer_binding *binding
+ = array->BufferBinding;
+ const struct gl_array_attributes *attrib = array->VertexAttrib;
+ const GLubyte *ptr = _mesa_vertex_attrib_address(attrib, binding);
+ printf(" array %d at %p:\n", j, (void*) &arrays[j]);
+ printf(" ptr %p, size %d, type 0x%x, stride %d\n",
+ ptr, attrib->Size, attrib->Type, binding->Stride);
+ if (0) {
+ GLint k = prims[i].start + prims[i].count - 1;
+ GLfloat *last = (GLfloat *) (ptr + binding->Stride * k);
+ printf(" last: %f %f %f\n",
+ last[0], last[1], last[2]);
+ }
+ }
+ }
+}
+
+
+static void
+flush(struct copy_context *copy)
+{
+ struct gl_context *ctx = copy->ctx;
+ GLuint i;
+
+ /* Set some counters:
+ */
+ copy->dstib.count = copy->dstelt_nr;
+
+#if 0
+ dump_draw_info(copy->ctx,
+ copy->dstarray,
+ copy->dstprim,
+ copy->dstprim_nr,
+ ©->dstib,
+ 0,
+ copy->dstbuf_nr);
+#else
+ (void) dump_draw_info;
+#endif
+
+ copy->draw(ctx,
+ copy->dstarray,
+ copy->dstprim,
+ copy->dstprim_nr,
+ ©->dstib,
+ GL_TRUE,
+ 0,
+ copy->dstbuf_nr - 1,
+ NULL, 0, NULL);
+
+ /* Reset all pointers:
+ */
+ copy->dstprim_nr = 0;
+ copy->dstelt_nr = 0;
+ copy->dstbuf_nr = 0;
+ copy->dstptr = copy->dstbuf;
+
+ /* Clear the vertex cache:
+ */
+ for (i = 0; i < ELT_TABLE_SIZE; i++)
+ copy->vert_cache[i].in = ~0;
+}
+
+
+/**
+ * Called at begin of each primitive during replay.
+ */
+static void
+begin(struct copy_context *copy, GLenum mode, GLboolean begin_flag)
+{
+ struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr];
+
+ prim->mode = mode;
+ prim->begin = begin_flag;
+ prim->num_instances = 1;
+}
+
+
+/**
+ * Use a hashtable to attempt to identify recently-emitted vertices
+ * and avoid re-emitting them.
+ */
+static GLuint
+elt(struct copy_context *copy, GLuint elt_idx)
+{
+ GLuint elt = copy->srcelt[elt_idx] + copy->prim->basevertex;
+ GLuint slot = elt & (ELT_TABLE_SIZE-1);
+
+ /* Look up the incoming element in the vertex cache. Re-emit if
+ * necessary.
+ */
+ if (copy->vert_cache[slot].in != elt) {
+ GLubyte *csr = copy->dstptr;
+ GLuint i;
+
+ for (i = 0; i < copy->nr_varying; i++) {
+ const struct gl_vertex_array *srcarray = copy->varying[i].array;
+ const struct gl_vertex_buffer_binding* srcbinding
+ = srcarray->BufferBinding;
+ const GLubyte *srcptr
+ = copy->varying[i].src_ptr + elt * srcbinding->Stride;
+
+ memcpy(csr, srcptr, copy->varying[i].size);
+ csr += copy->varying[i].size;
+
+#ifdef NAN_CHECK
+ if (srcarray->Type == GL_FLOAT) {
+ GLuint k;
+ GLfloat *f = (GLfloat *) srcptr;
+ for (k = 0; k < srcarray->Size; k++) {
+ assert(!IS_INF_OR_NAN(f[k]));
+ assert(f[k] <= 1.0e20 && f[k] >= -1.0e20);
+ }
+ }
+#endif
+
+ if (0) {
+ const GLuint *f = (const GLuint *)srcptr;
+ GLuint j;
+ printf(" varying %d: ", i);
+ for (j = 0; j < copy->varying[i].size / 4; j++)
+ printf("%x ", f[j]);
+ printf("\n");
+ }
+ }
+
+ copy->vert_cache[slot].in = elt;
+ copy->vert_cache[slot].out = copy->dstbuf_nr++;
+ copy->dstptr += copy->vertex_size;
+
+ assert(csr == copy->dstptr);
+ assert(copy->dstptr == (copy->dstbuf +
+ copy->dstbuf_nr * copy->vertex_size));
+ }
+
+ copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
+ return check_flush(copy);
+}
+
+
+/**
+ * Called at end of each primitive during replay.
+ */
+static void
+end(struct copy_context *copy, GLboolean end_flag)
+{
+ struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr];
+
+ prim->end = end_flag;
+ prim->count = copy->dstelt_nr - prim->start;
+
+ if (++copy->dstprim_nr == MAX_PRIM || check_flush(copy)) {
+ flush(copy);
+ }
+}
+
+
+static void
+replay_elts(struct copy_context *copy)
+{
+ GLuint i, j, k;
+ GLboolean split;
+
+ for (i = 0; i < copy->nr_prims; i++) {
+ const struct _mesa_prim *prim = ©->prim[i];
+ const GLuint start = prim->start;
+ GLuint first, incr;
+
+ switch (prim->mode) {
+ case GL_LINE_LOOP:
+ /* Convert to linestrip and emit the final vertex explicitly,
+ * but only in the resultant strip that requires it.
+ */
+ j = 0;
+ while (j != prim->count) {
+ begin(copy, GL_LINE_STRIP, prim->begin && j == 0);
+
+ for (split = GL_FALSE; j != prim->count && !split; j++)
+ split = elt(copy, start + j);
+
+ if (j == prim->count) {
+ /* Done, emit final line. Split doesn't matter as
+ * it is always raised a bit early so we can emit
+ * the last verts if necessary!
+ */
+ if (prim->end)
+ (void)elt(copy, start + 0);
+
+ end(copy, prim->end);
+ }
+ else {
+ /* Wrap
+ */
+ assert(split);
+ end(copy, 0);
+ j--;
+ }
+ }
+ break;
+
+ case GL_TRIANGLE_FAN:
+ case GL_POLYGON:
+ j = 2;
+ while (j != prim->count) {
+ begin(copy, prim->mode, prim->begin && j == 0);
+
+ split = elt(copy, start+0);
+ assert(!split);
+
+ split = elt(copy, start+j-1);
+ assert(!split);
+
+ for (; j != prim->count && !split; j++)
+ split = elt(copy, start+j);
+
+ end(copy, prim->end && j == prim->count);
+
+ if (j != prim->count) {
+ /* Wrapped the primitive, need to repeat some vertices:
+ */
+ j -= 1;
+ }
+ }
+ break;
+
+ default:
+ (void)_tnl_split_prim_inplace(prim->mode, &first, &incr);
+
+ j = 0;
+ while (j != prim->count) {
+
+ begin(copy, prim->mode, prim->begin && j == 0);
+
+ split = 0;
+ for (k = 0; k < first; k++, j++)
+ split |= elt(copy, start+j);
+
+ assert(!split);
+
+ for (; j != prim->count && !split;)
+ for (k = 0; k < incr; k++, j++)
+ split |= elt(copy, start+j);
+
+ end(copy, prim->end && j == prim->count);
+
+ if (j != prim->count) {
+ /* Wrapped the primitive, need to repeat some vertices:
+ */
+ assert(j > first - incr);
+ j -= (first - incr);
+ }
+ }
+ break;
+ }
+ }
+
+ if (copy->dstprim_nr)
+ flush(copy);
+}
+
+
+static void
+replay_init(struct copy_context *copy)
+{
+ struct gl_context *ctx = copy->ctx;
+ GLuint i;
+ GLuint offset;
+ const GLvoid *srcptr;
+
+ /* Make a list of varying attributes and their vbo's. Also
+ * calculate vertex size.
+ */
+ copy->vertex_size = 0;
+ for (i = 0; i < VERT_ATTRIB_MAX; i++) {
+ const struct gl_vertex_array *array = ©->array[i];
+ const struct gl_vertex_buffer_binding *binding = array->BufferBinding;
+
+ if (binding->Stride == 0) {
+ _mesa_copy_vertex_array(©->dstarray[i], array);
+ }
+ else {
+ const struct gl_array_attributes *attrib = array->VertexAttrib;
+ struct gl_buffer_object *vbo = binding->BufferObj;
+ const GLubyte *ptr = _mesa_vertex_attrib_address(attrib, binding);
+ GLuint j = copy->nr_varying++;
+
+ copy->varying[j].attr = i;
+ copy->varying[j].array = ©->array[i];
+ copy->varying[j].size = attr_size(attrib);
+ copy->vertex_size += attr_size(attrib);
+
+ if (_mesa_is_bufferobj(vbo) &&
+ !_mesa_bufferobj_mapped(vbo, MAP_INTERNAL))
+ ctx->Driver.MapBufferRange(ctx, 0, vbo->Size, GL_MAP_READ_BIT, vbo,
+ MAP_INTERNAL);
+
+ copy->varying[j].src_ptr =
+ ADD_POINTERS(vbo->Mappings[MAP_INTERNAL].Pointer, ptr);
+
+ copy->dstarray[i].VertexAttrib = ©->varying[j].dstattribs;
+ copy->dstarray[i].BufferBinding = ©->varying[j].dstbinding;
+ }
+ }
+
+ /* There must always be an index buffer. Currently require the
+ * caller convert non-indexed prims to indexed. Could alternately
+ * do it internally.
+ */
+ if (_mesa_is_bufferobj(copy->ib->obj) &&
+ !_mesa_bufferobj_mapped(copy->ib->obj, MAP_INTERNAL))
+ ctx->Driver.MapBufferRange(ctx, 0, copy->ib->obj->Size, GL_MAP_READ_BIT,
+ copy->ib->obj, MAP_INTERNAL);
+
+ srcptr = (const GLubyte *)
+ ADD_POINTERS(copy->ib->obj->Mappings[MAP_INTERNAL].Pointer,
+ copy->ib->ptr);
+
+ switch (copy->ib->index_size) {
+ case 1:
+ copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
+ copy->srcelt = copy->translated_elt_buf;
+
+ for (i = 0; i < copy->ib->count; i++)
+ copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i];
+ break;
+
+ case 2:
+ copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
+ copy->srcelt = copy->translated_elt_buf;
+
+ for (i = 0; i < copy->ib->count; i++)
+ copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i];
+ break;
+
+ case 4:
+ copy->translated_elt_buf = NULL;
+ copy->srcelt = (const GLuint *)srcptr;
+ break;
+ }
+
+ /* Figure out the maximum allowed vertex buffer size:
+ */
+ if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) {
+ copy->dstbuf_size = copy->limits->max_verts;
+ }
+ else {
+ copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size;
+ }
+
+ /* Allocate an output vertex buffer:
+ *
+ * XXX: This should be a VBO!
+ */
+ copy->dstbuf = malloc(copy->dstbuf_size * copy->vertex_size);
+ copy->dstptr = copy->dstbuf;
+
+ /* Setup new vertex arrays to point into the output buffer:
+ */
+ for (offset = 0, i = 0; i < copy->nr_varying; i++) {
+ const struct gl_vertex_array *src = copy->varying[i].array;
+ const struct gl_array_attributes *srcattr = src->VertexAttrib;
+ struct gl_vertex_array *dst = ©->dstarray[i];
+ struct gl_vertex_buffer_binding *dstbind = ©->varying[i].dstbinding;
+ struct gl_array_attributes *dstattr = ©->varying[i].dstattribs;
+
+ dstattr->Size = srcattr->Size;
+ dstattr->Type = srcattr->Type;
+ dstattr->Format = GL_RGBA;
+ dstbind->Stride = copy->vertex_size;
+ dstattr->Ptr = copy->dstbuf + offset;
+ dstattr->Normalized = srcattr->Normalized;
+ dstattr->Integer = srcattr->Integer;
+ dstattr->Doubles = srcattr->Doubles;
+ dstbind->BufferObj = ctx->Shared->NullBufferObj;
+ dstattr->_ElementSize = srcattr->_ElementSize;
+ dst->BufferBinding = dstbind;
+ dst->VertexAttrib = dstattr;
+
+ offset += copy->varying[i].size;
+ }
+
+ /* Allocate an output element list:
+ */
+ copy->dstelt_size = MIN2(65536, copy->ib->count * 2 + 3);
+ copy->dstelt_size = MIN2(copy->dstelt_size, copy->limits->max_indices);
+ copy->dstelt = malloc(sizeof(GLuint) * copy->dstelt_size);
+ copy->dstelt_nr = 0;
+
+ /* Setup the new index buffer to point to the allocated element
+ * list:
+ */
+ copy->dstib.count = 0; /* duplicates dstelt_nr */
+ copy->dstib.index_size = 4;
+ copy->dstib.obj = ctx->Shared->NullBufferObj;
+ copy->dstib.ptr = copy->dstelt;
+}
+
+
+/**
+ * Free up everything allocated during split/replay.
+ */
+static void
+replay_finish(struct copy_context *copy)
+{
+ struct gl_context *ctx = copy->ctx;
+ GLuint i;
+
+ /* Free our vertex and index buffers */
+ free(copy->translated_elt_buf);
+ free(copy->dstbuf);
+ free(copy->dstelt);
+
+ /* Unmap VBO's */
+ for (i = 0; i < copy->nr_varying; i++) {
+ struct gl_buffer_object *vbo =
+ copy->varying[i].array->BufferBinding->BufferObj;
+ if (_mesa_is_bufferobj(vbo) && _mesa_bufferobj_mapped(vbo, MAP_INTERNAL))
+ ctx->Driver.UnmapBuffer(ctx, vbo, MAP_INTERNAL);
+ }
+
+ /* Unmap index buffer */
+ if (_mesa_is_bufferobj(copy->ib->obj) &&
+ _mesa_bufferobj_mapped(copy->ib->obj, MAP_INTERNAL)) {
+ ctx->Driver.UnmapBuffer(ctx, copy->ib->obj, MAP_INTERNAL);
+ }
+}
+
+
+/**
+ * Split VBO into smaller pieces, draw the pieces.
+ */
+void
+_tnl_split_copy(struct gl_context *ctx,
+ const struct gl_vertex_array *arrays,
+ const struct _mesa_prim *prim,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ tnl_draw_func draw,
+ const struct split_limits *limits)
+{
+ struct copy_context copy;
+ GLuint i, this_nr_prims;
+
+ for (i = 0; i < nr_prims;) {
+ /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices
+ * will rebase the elements to the basevertex, and we'll only
+ * emit strings of prims with the same basevertex in one draw call.
+ */
+ for (this_nr_prims = 1; i + this_nr_prims < nr_prims;
+ this_nr_prims++) {
+ if (prim[i].basevertex != prim[i + this_nr_prims].basevertex)
+ break;
+ }
+
+ memset(©, 0, sizeof(copy));
+
+ /* Require indexed primitives:
+ */
+ assert(ib);
+
+ copy.ctx = ctx;
+ copy.array = arrays;
+ copy.prim = &prim[i];
+ copy.nr_prims = this_nr_prims;
+ copy.ib = ib;
+ copy.draw = draw;
+ copy.limits = limits;
+
+ /* Clear the vertex cache:
+ */
+ for (i = 0; i < ELT_TABLE_SIZE; i++)
+ copy.vert_cache[i].in = ~0;
+
+ replay_init(©);
+ replay_elts(©);
+ replay_finish(©);
+ }
+}
--- /dev/null
+
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ * Keith Whitwell <keithw@vmware.com>
+ */
+
+
+#include "main/mtypes.h"
+#include "main/macros.h"
+#include "main/enums.h"
+#include "vbo/vbo.h"
+
+#include "t_split.h"
+
+
+#define MAX_PRIM 32
+
+/* Used for splitting without copying. No attempt is made to handle
+ * too large indexed vertex buffers: In general you need to copy to do
+ * that.
+ */
+struct split_context {
+ struct gl_context *ctx;
+ const struct gl_vertex_array *array;
+ const struct _mesa_prim *prim;
+ GLuint nr_prims;
+ const struct _mesa_index_buffer *ib;
+ GLuint min_index;
+ GLuint max_index;
+ tnl_draw_func draw;
+
+ const struct split_limits *limits;
+ GLuint limit;
+
+ struct _mesa_prim dstprim[MAX_PRIM];
+ GLuint dstprim_nr;
+};
+
+
+
+
+static void
+flush_vertex( struct split_context *split)
+{
+ struct gl_context *ctx = split->ctx;
+ struct _mesa_index_buffer ib;
+ GLuint i;
+
+ if (!split->dstprim_nr)
+ return;
+
+ if (split->ib) {
+ ib = *split->ib;
+
+ ib.count = split->max_index - split->min_index + 1;
+ ib.ptr = (const void *)((const char *)ib.ptr +
+ split->min_index * ib.index_size);
+
+ /* Rebase the primitives to save index buffer entries. */
+ for (i = 0; i < split->dstprim_nr; i++)
+ split->dstprim[i].start -= split->min_index;
+ }
+
+ assert(split->max_index >= split->min_index);
+
+ split->draw(ctx,
+ split->array,
+ split->dstprim,
+ split->dstprim_nr,
+ split->ib ? &ib : NULL,
+ !split->ib,
+ split->min_index,
+ split->max_index,
+ NULL, 0, NULL);
+
+ split->dstprim_nr = 0;
+ split->min_index = ~0;
+ split->max_index = 0;
+}
+
+
+static struct _mesa_prim *
+next_outprim(struct split_context *split)
+{
+ if (split->dstprim_nr == MAX_PRIM-1) {
+ flush_vertex(split);
+ }
+
+ {
+ struct _mesa_prim *prim = &split->dstprim[split->dstprim_nr++];
+ memset(prim, 0, sizeof(*prim));
+ return prim;
+ }
+}
+
+
+static void
+update_index_bounds(struct split_context *split,
+ const struct _mesa_prim *prim)
+{
+ split->min_index = MIN2(split->min_index, prim->start);
+ split->max_index = MAX2(split->max_index, prim->start + prim->count - 1);
+}
+
+
+/* Return the maximum amount of vertices that can be emitted for a
+ * primitive starting at 'prim->start', depending on the previous
+ * index bounds.
+ */
+static GLuint
+get_max_vertices(struct split_context *split,
+ const struct _mesa_prim *prim)
+{
+ if ((prim->start > split->min_index &&
+ prim->start - split->min_index >= split->limit) ||
+ (prim->start < split->max_index &&
+ split->max_index - prim->start >= split->limit))
+ /* "prim" starts too far away from the old range. */
+ return 0;
+
+ return MIN2(split->min_index, prim->start) + split->limit - prim->start;
+}
+
+
+/* Break large primitives into smaller ones. If not possible, convert
+ * the primitive to indexed and pass to split_elts().
+ */
+static void
+split_prims(struct split_context *split)
+{
+ GLuint i;
+
+ for (i = 0; i < split->nr_prims; i++) {
+ const struct _mesa_prim *prim = &split->prim[i];
+ GLuint first, incr;
+ GLboolean split_inplace =
+ _tnl_split_prim_inplace(prim->mode, &first, &incr);
+ GLuint available = get_max_vertices(split, prim);
+ GLuint count = prim->count - (prim->count - first) % incr;
+
+ if (prim->count < first)
+ continue;
+
+ if ((available < count && !split_inplace) ||
+ (available < first && split_inplace)) {
+ flush_vertex(split);
+ available = get_max_vertices(split, prim);
+ }
+
+ if (available >= count) {
+ struct _mesa_prim *outprim = next_outprim(split);
+
+ *outprim = *prim;
+ update_index_bounds(split, outprim);
+ }
+ else if (split_inplace) {
+ GLuint j, nr;
+
+ for (j = 0 ; j < count ;) {
+ GLuint remaining = count - j;
+ struct _mesa_prim *outprim = next_outprim(split);
+
+ nr = MIN2(available, remaining);
+ nr -= (nr - first) % incr;
+
+ outprim->mode = prim->mode;
+ outprim->begin = (j == 0 && prim->begin);
+ outprim->end = (nr == remaining && prim->end);
+ outprim->start = prim->start + j;
+ outprim->count = nr;
+ outprim->num_instances = prim->num_instances;
+ outprim->base_instance = prim->base_instance;
+
+ update_index_bounds(split, outprim);
+
+ if (nr == remaining) {
+ /* Finished */
+ j += nr;
+ }
+ else {
+ /* Wrapped the primitive */
+ j += nr - (first - incr);
+ flush_vertex(split);
+ available = get_max_vertices(split, prim);
+ }
+ }
+ }
+ else if (split->ib == NULL) {
+ /* XXX: could at least send the first max_verts off from the
+ * inplace buffers.
+ */
+
+ /* else convert to indexed primitive and pass to split_elts,
+ * which will do the necessary copying and turn it back into a
+ * vertex primitive for rendering...
+ */
+ struct _mesa_index_buffer ib;
+ struct _mesa_prim tmpprim;
+ GLuint *elts = malloc(count * sizeof(GLuint));
+ GLuint j;
+
+ for (j = 0; j < count; j++)
+ elts[j] = prim->start + j;
+
+ ib.count = count;
+ ib.index_size = 4;
+ ib.obj = split->ctx->Shared->NullBufferObj;
+ ib.ptr = elts;
+
+ tmpprim = *prim;
+ tmpprim.indexed = 1;
+ tmpprim.start = 0;
+ tmpprim.count = count;
+ tmpprim.num_instances = 1;
+ tmpprim.base_instance = 0;
+
+ flush_vertex(split);
+
+ _tnl_split_copy(split->ctx,
+ split->array,
+ &tmpprim, 1,
+ &ib,
+ split->draw,
+ split->limits);
+
+ free(elts);
+ }
+ else {
+ flush_vertex(split);
+
+ _tnl_split_copy(split->ctx,
+ split->array,
+ prim, 1,
+ split->ib,
+ split->draw,
+ split->limits);
+ }
+ }
+
+ flush_vertex(split);
+}
+
+
+void
+_tnl_split_inplace(struct gl_context *ctx,
+ const struct gl_vertex_array *arrays,
+ const struct _mesa_prim *prim,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ GLuint min_index,
+ GLuint max_index,
+ tnl_draw_func draw,
+ const struct split_limits *limits)
+{
+ struct split_context split;
+
+ memset(&split, 0, sizeof(split));
+
+ split.ctx = ctx;
+ split.array = arrays;
+ split.prim = prim;
+ split.nr_prims = nr_prims;
+ split.ib = ib;
+
+ /* Empty interval, makes calculations simpler. */
+ split.min_index = ~0;
+ split.max_index = 0;
+
+ split.draw = draw;
+ split.limits = limits;
+ split.limit = ib ? limits->max_indices : limits->max_verts;
+
+ split_prims(&split);
+}
+
+
extern void
_tnl_validate_shine_tables( struct gl_context *ctx );
+
+
+/**
+ * For indirect array drawing:
+ *
+ * typedef struct {
+ * GLuint count;
+ * GLuint primCount;
+ * GLuint first;
+ * GLuint baseInstance; // in GL 4.2 and later, must be zero otherwise
+ * } DrawArraysIndirectCommand;
+ *
+ * For indirect indexed drawing:
+ *
+ * typedef struct {
+ * GLuint count;
+ * GLuint primCount;
+ * GLuint firstIndex;
+ * GLint baseVertex;
+ * GLuint baseInstance; // in GL 4.2 and later, must be zero otherwise
+ * } DrawElementsIndirectCommand;
+ */
+
+
+/**
+ * Draw a number of primitives.
+ * \param prims array [nr_prims] describing what to draw (prim type,
+ * vertex count, first index, instance count, etc).
+ * \param arrays array of vertex arrays for draw
+ * \param ib index buffer for indexed drawing, NULL for array drawing
+ * \param index_bounds_valid are min_index and max_index valid?
+ * \param min_index lowest vertex index used
+ * \param max_index highest vertex index used
+ * \param tfb_vertcount if non-null, indicates which transform feedback
+ * object has the vertex count.
+ * \param tfb_stream If called via DrawTransformFeedbackStream, specifies the
+ * vertex stream buffer from which to get the vertex count.
+ * \param indirect If any prims are indirect, this specifies the buffer
+ * to find the "DrawArrays/ElementsIndirectCommand" data.
+ * This may be deprecated in the future
+ */
+typedef void (*tnl_draw_func)(struct gl_context *ctx,
+ const struct gl_vertex_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,
+ struct gl_transform_feedback_object *tfb_vertcount,
+ unsigned tfb_stream,
+ struct gl_buffer_object *indirect);
+
+
+/* Utility function to cope with various constraints on tnl modules or
+ * hardware. This can be used to split an incoming set of arrays and
+ * primitives against the following constraints:
+ * - Maximum number of indices in index buffer.
+ * - Maximum number of vertices referenced by index buffer.
+ * - Maximum hardware vertex buffer size.
+ */
+struct split_limits
+{
+ GLuint max_verts;
+ GLuint max_indices;
+ GLuint max_vb_size; /* bytes */
+};
+
+void
+_tnl_split_prims(struct gl_context *ctx,
+ const struct gl_vertex_array *arrays,
+ const struct _mesa_prim *prim,
+ GLuint nr_prims,
+ const struct _mesa_index_buffer *ib,
+ GLuint min_index,
+ GLuint max_index,
+ tnl_draw_func draw,
+ const struct split_limits *limits);
+
+
#endif
vbo_save_EndCallList(struct gl_context *ctx);
-/**
- * For indirect array drawing:
- *
- * typedef struct {
- * GLuint count;
- * GLuint primCount;
- * GLuint first;
- * GLuint baseInstance; // in GL 4.2 and later, must be zero otherwise
- * } DrawArraysIndirectCommand;
- *
- * For indirect indexed drawing:
- *
- * typedef struct {
- * GLuint count;
- * GLuint primCount;
- * GLuint firstIndex;
- * GLint baseVertex;
- * GLuint baseInstance; // in GL 4.2 and later, must be zero otherwise
- * } DrawElementsIndirectCommand;
- */
-
-
-/**
- * Draw a number of primitives.
- * \param prims array [nr_prims] describing what to draw (prim type,
- * vertex count, first index, instance count, etc).
- * \param arrays array of vertex arrays for draw
- * \param ib index buffer for indexed drawing, NULL for array drawing
- * \param index_bounds_valid are min_index and max_index valid?
- * \param min_index lowest vertex index used
- * \param max_index highest vertex index used
- * \param tfb_vertcount if non-null, indicates which transform feedback
- * object has the vertex count.
- * \param tfb_stream If called via DrawTransformFeedbackStream, specifies the
- * vertex stream buffer from which to get the vertex count.
- * \param indirect If any prims are indirect, this specifies the buffer
- * to find the "DrawArrays/ElementsIndirectCommand" data.
- * This may be deprecated in the future
- */
-typedef void (*vbo_draw_func)(struct gl_context *ctx,
- const struct gl_vertex_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,
- struct gl_transform_feedback_object *tfb_vertcount,
- unsigned tfb_stream,
- struct gl_buffer_object *indirect);
-
-
-
-
-/* Utility function to cope with various constraints on tnl modules or
- * hardware. This can be used to split an incoming set of arrays and
- * primitives against the following constraints:
- * - Maximum number of indices in index buffer.
- * - Maximum number of vertices referenced by index buffer.
- * - Maximum hardware vertex buffer size.
- */
-struct split_limits
-{
- GLuint max_verts;
- GLuint max_indices;
- GLuint max_vb_size; /* bytes */
-};
-
-
void
_vbo_draw_indirect(struct gl_context *ctx, GLuint mode,
struct gl_buffer_object *indirect_data,
const struct _mesa_index_buffer *ib);
-void
-vbo_split_prims(struct gl_context *ctx,
- const struct gl_vertex_array *arrays,
- const struct _mesa_prim *prim,
- GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
- GLuint min_index,
- GLuint max_index,
- vbo_draw_func draw,
- const struct split_limits *limits);
-
-
void
vbo_delete_minmax_cache(struct gl_buffer_object *bufferObj);
+++ /dev/null
-
-/*
- * Mesa 3-D graphics library
- *
- * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * 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 NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS 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.
- *
- * Authors:
- * Keith Whitwell <keithw@vmware.com>
- */
-
-/* Deal with hardware and/or swtnl maximums:
- * - maximum number of vertices in buffer
- * - maximum number of elements (maybe zero)
- *
- * The maximums may vary with opengl state (eg if a larger hardware
- * vertex is required in this state, the maximum number of vertices
- * may be smaller than in another state).
- *
- * We want buffer splitting to be a convenience function for the code
- * actually drawing the primitives rather than a system-wide maximum,
- * otherwise it is hard to avoid pessimism.
- *
- * For instance, if a driver has no hardware limits on vertex buffer
- * dimensions, it would not ordinarily want to split vbos. But if
- * there is an unexpected fallback, eg memory manager fails to upload
- * textures, it will want to pass the drawing commands onto swtnl,
- * which does have limitations. A convenience function allows swtnl
- * to split the drawing and vbos internally without imposing its
- * limitations on drivers which want to use it as a fallback path.
- */
-
-#include "main/glheader.h"
-#include "main/mtypes.h"
-
-#include "vbo_split.h"
-#include "vbo.h"
-
-
-/* True if a primitive can be split without copying of vertices, false
- * otherwise.
- */
-GLboolean
-split_prim_inplace(GLenum mode, GLuint *first, GLuint *incr)
-{
- switch (mode) {
- case GL_POINTS:
- *first = 1;
- *incr = 1;
- return GL_TRUE;
- case GL_LINES:
- *first = 2;
- *incr = 2;
- return GL_TRUE;
- case GL_LINE_STRIP:
- *first = 2;
- *incr = 1;
- return GL_TRUE;
- case GL_TRIANGLES:
- *first = 3;
- *incr = 3;
- return GL_TRUE;
- case GL_TRIANGLE_STRIP:
- *first = 3;
- *incr = 1;
- return GL_TRUE;
- case GL_QUADS:
- *first = 4;
- *incr = 4;
- return GL_TRUE;
- case GL_QUAD_STRIP:
- *first = 4;
- *incr = 2;
- return GL_TRUE;
- default:
- *first = 0;
- *incr = 1; /* so that count % incr works */
- return GL_FALSE;
- }
-}
-
-
-
-void
-vbo_split_prims(struct gl_context *ctx,
- const struct gl_vertex_array arrays[],
- const struct _mesa_prim *prim,
- GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
- GLuint min_index,
- GLuint max_index,
- vbo_draw_func draw,
- const struct split_limits *limits)
-{
- if (ib) {
- if (limits->max_indices == 0) {
- /* Could traverse the indices, re-emitting vertices in turn.
- * But it's hard to see why this case would be needed - for
- * software tnl, it is better to convert to non-indexed
- * rendering after transformation is complete. Are there any devices
- * with hardware tnl that cannot do indexed rendering?
- *
- * For now, this path is disabled.
- */
- assert(0);
- }
- else if (max_index - min_index >= limits->max_verts) {
- /* The vertex buffers are too large for hardware (or the
- * swtnl module). Traverse the indices, re-emitting vertices
- * in turn. Use a vertex cache to preserve some of the
- * sharing from the original index list.
- */
- vbo_split_copy(ctx, arrays, prim, nr_prims, ib, draw, limits);
- }
- else if (ib->count > limits->max_indices) {
- /* The index buffer is too large for hardware. Try to split
- * on whole-primitive boundaries, otherwise try to split the
- * individual primitives.
- */
- vbo_split_inplace(ctx, arrays, prim, nr_prims, ib,
- min_index, max_index, draw, limits);
- }
- else {
- /* Why were we called? */
- assert(0);
- }
- }
- else {
- if (max_index - min_index >= limits->max_verts) {
- /* The vertex buffer is too large for hardware (or the swtnl
- * module). Try to split on whole-primitive boundaries,
- * otherwise try to split the individual primitives.
- */
- vbo_split_inplace(ctx, arrays, prim, nr_prims, ib,
- min_index, max_index, draw, limits);
- }
- else {
- /* Why were we called? */
- assert(0);
- }
- }
-}
-
+++ /dev/null
-/*
- * mesa 3-D graphics library
- *
- * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * 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 NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS 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.
- */
-
-/**
- * \brief VBO builder module datatypes and definitions.
- * \author Keith Whitwell
- */
-
-
-/**
- * \mainpage The VBO splitter
- *
- * This is the private data used internally to the vbo_split_prims()
- * helper function. Nobody outside the vbo_split* files needs to
- * include or know about this structure.
- */
-
-
-#ifndef _VBO_SPLIT_H
-#define _VBO_SPLIT_H
-
-#include "vbo.h"
-
-
-/* True if a primitive can be split without copying of vertices, false
- * otherwise.
- */
-GLboolean
-split_prim_inplace(GLenum mode, GLuint *first, GLuint *incr);
-
-void
-vbo_split_inplace(struct gl_context *ctx,
- const struct gl_vertex_array arrays[],
- const struct _mesa_prim *prim,
- GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
- GLuint min_index,
- GLuint max_index,
- vbo_draw_func draw,
- const struct split_limits *limits);
-
-/* Requires ib != NULL:
- */
-void
-vbo_split_copy(struct gl_context *ctx,
- const struct gl_vertex_array arrays[],
- const struct _mesa_prim *prim,
- GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
- vbo_draw_func draw,
- const struct split_limits *limits);
-
-#endif
+++ /dev/null
-
-/*
- * Mesa 3-D graphics library
- *
- * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * 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 NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS 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.
- *
- * Authors:
- * Keith Whitwell <keithw@vmware.com>
- */
-
-/* Split indexed primitives with per-vertex copying.
- */
-
-#include <stdio.h>
-
-#include "main/glheader.h"
-#include "main/bufferobj.h"
-#include "main/imports.h"
-#include "main/glformats.h"
-#include "main/macros.h"
-#include "main/mtypes.h"
-#include "main/varray.h"
-
-#include "vbo_split.h"
-#include "vbo.h"
-
-
-#define ELT_TABLE_SIZE 16
-
-/**
- * Used for vertex-level splitting of indexed buffers. Note that
- * non-indexed primitives may be converted to indexed in some cases
- * (eg loops, fans) in order to use this splitting path.
- */
-struct copy_context {
- struct gl_context *ctx;
- const struct gl_vertex_array *array;
- const struct _mesa_prim *prim;
- GLuint nr_prims;
- const struct _mesa_index_buffer *ib;
- vbo_draw_func draw;
-
- const struct split_limits *limits;
-
- struct {
- GLuint attr;
- GLuint size;
- const struct gl_vertex_array *array;
- const GLubyte *src_ptr;
-
- struct gl_vertex_buffer_binding dstbinding;
- struct gl_array_attributes dstattribs;
-
- } varying[VERT_ATTRIB_MAX];
- GLuint nr_varying;
-
- struct gl_vertex_array dstarray[VERT_ATTRIB_MAX];
- struct _mesa_index_buffer dstib;
-
- GLuint *translated_elt_buf;
- const GLuint *srcelt;
-
- /** A baby hash table to avoid re-emitting (some) duplicate
- * vertices when splitting indexed primitives.
- */
- struct {
- GLuint in;
- GLuint out;
- } vert_cache[ELT_TABLE_SIZE];
-
- GLuint vertex_size;
- GLubyte *dstbuf;
- GLubyte *dstptr; /**< dstptr == dstbuf + dstelt_max * vertsize */
- GLuint dstbuf_size; /**< in vertices */
- GLuint dstbuf_nr; /**< count of emitted vertices, also the largest value
- * in dstelt. Our MaxIndex.
- */
-
- GLuint *dstelt;
- GLuint dstelt_nr;
- GLuint dstelt_size;
-
-#define MAX_PRIM 32
- struct _mesa_prim dstprim[MAX_PRIM];
- GLuint dstprim_nr;
-};
-
-
-static GLuint
-attr_size(const struct gl_array_attributes *attrib)
-{
- return attrib->Size * _mesa_sizeof_type(attrib->Type);
-}
-
-
-/**
- * Starts returning true slightly before the buffer fills, to ensure
- * that there is sufficient room for any remaining vertices to finish
- * off the prim:
- */
-static GLboolean
-check_flush(struct copy_context *copy)
-{
- GLenum mode = copy->dstprim[copy->dstprim_nr].mode;
-
- if (GL_TRIANGLE_STRIP == mode &&
- copy->dstelt_nr & 1) { /* see bug9962 */
- return GL_FALSE;
- }
-
- if (copy->dstbuf_nr + 4 > copy->dstbuf_size)
- return GL_TRUE;
-
- if (copy->dstelt_nr + 4 > copy->dstelt_size)
- return GL_TRUE;
-
- return GL_FALSE;
-}
-
-
-/**
- * Dump the parameters/info for a vbo->draw() call.
- */
-static void
-dump_draw_info(struct gl_context *ctx,
- const struct gl_vertex_array *arrays,
- const struct _mesa_prim *prims,
- GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
- GLuint min_index,
- GLuint max_index)
-{
- GLuint i, j;
-
- printf("VBO Draw:\n");
- for (i = 0; i < nr_prims; i++) {
- printf("Prim %u of %u\n", i, nr_prims);
- printf(" Prim mode 0x%x\n", prims[i].mode);
- printf(" IB: %p\n", (void*) ib);
- for (j = 0; j < VERT_ATTRIB_MAX; j++) {
- const struct gl_vertex_array *array = &arrays[j];
- const struct gl_vertex_buffer_binding *binding
- = array->BufferBinding;
- const struct gl_array_attributes *attrib = array->VertexAttrib;
- const GLubyte *ptr = _mesa_vertex_attrib_address(attrib, binding);
- printf(" array %d at %p:\n", j, (void*) &arrays[j]);
- printf(" ptr %p, size %d, type 0x%x, stride %d\n",
- ptr, attrib->Size, attrib->Type, binding->Stride);
- if (0) {
- GLint k = prims[i].start + prims[i].count - 1;
- GLfloat *last = (GLfloat *) (ptr + binding->Stride * k);
- printf(" last: %f %f %f\n",
- last[0], last[1], last[2]);
- }
- }
- }
-}
-
-
-static void
-flush(struct copy_context *copy)
-{
- struct gl_context *ctx = copy->ctx;
- GLuint i;
-
- /* Set some counters:
- */
- copy->dstib.count = copy->dstelt_nr;
-
-#if 0
- dump_draw_info(copy->ctx,
- copy->dstarray,
- copy->dstprim,
- copy->dstprim_nr,
- ©->dstib,
- 0,
- copy->dstbuf_nr);
-#else
- (void) dump_draw_info;
-#endif
-
- copy->draw(ctx,
- copy->dstarray,
- copy->dstprim,
- copy->dstprim_nr,
- ©->dstib,
- GL_TRUE,
- 0,
- copy->dstbuf_nr - 1,
- NULL, 0, NULL);
-
- /* Reset all pointers:
- */
- copy->dstprim_nr = 0;
- copy->dstelt_nr = 0;
- copy->dstbuf_nr = 0;
- copy->dstptr = copy->dstbuf;
-
- /* Clear the vertex cache:
- */
- for (i = 0; i < ELT_TABLE_SIZE; i++)
- copy->vert_cache[i].in = ~0;
-}
-
-
-/**
- * Called at begin of each primitive during replay.
- */
-static void
-begin(struct copy_context *copy, GLenum mode, GLboolean begin_flag)
-{
- struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr];
-
- prim->mode = mode;
- prim->begin = begin_flag;
- prim->num_instances = 1;
-}
-
-
-/**
- * Use a hashtable to attempt to identify recently-emitted vertices
- * and avoid re-emitting them.
- */
-static GLuint
-elt(struct copy_context *copy, GLuint elt_idx)
-{
- GLuint elt = copy->srcelt[elt_idx] + copy->prim->basevertex;
- GLuint slot = elt & (ELT_TABLE_SIZE-1);
-
- /* Look up the incoming element in the vertex cache. Re-emit if
- * necessary.
- */
- if (copy->vert_cache[slot].in != elt) {
- GLubyte *csr = copy->dstptr;
- GLuint i;
-
- for (i = 0; i < copy->nr_varying; i++) {
- const struct gl_vertex_array *srcarray = copy->varying[i].array;
- const struct gl_vertex_buffer_binding* srcbinding
- = srcarray->BufferBinding;
- const GLubyte *srcptr
- = copy->varying[i].src_ptr + elt * srcbinding->Stride;
-
- memcpy(csr, srcptr, copy->varying[i].size);
- csr += copy->varying[i].size;
-
-#ifdef NAN_CHECK
- if (srcarray->Type == GL_FLOAT) {
- GLuint k;
- GLfloat *f = (GLfloat *) srcptr;
- for (k = 0; k < srcarray->Size; k++) {
- assert(!IS_INF_OR_NAN(f[k]));
- assert(f[k] <= 1.0e20 && f[k] >= -1.0e20);
- }
- }
-#endif
-
- if (0) {
- const GLuint *f = (const GLuint *)srcptr;
- GLuint j;
- printf(" varying %d: ", i);
- for (j = 0; j < copy->varying[i].size / 4; j++)
- printf("%x ", f[j]);
- printf("\n");
- }
- }
-
- copy->vert_cache[slot].in = elt;
- copy->vert_cache[slot].out = copy->dstbuf_nr++;
- copy->dstptr += copy->vertex_size;
-
- assert(csr == copy->dstptr);
- assert(copy->dstptr == (copy->dstbuf +
- copy->dstbuf_nr * copy->vertex_size));
- }
-
- copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
- return check_flush(copy);
-}
-
-
-/**
- * Called at end of each primitive during replay.
- */
-static void
-end(struct copy_context *copy, GLboolean end_flag)
-{
- struct _mesa_prim *prim = ©->dstprim[copy->dstprim_nr];
-
- prim->end = end_flag;
- prim->count = copy->dstelt_nr - prim->start;
-
- if (++copy->dstprim_nr == MAX_PRIM || check_flush(copy)) {
- flush(copy);
- }
-}
-
-
-static void
-replay_elts(struct copy_context *copy)
-{
- GLuint i, j, k;
- GLboolean split;
-
- for (i = 0; i < copy->nr_prims; i++) {
- const struct _mesa_prim *prim = ©->prim[i];
- const GLuint start = prim->start;
- GLuint first, incr;
-
- switch (prim->mode) {
- case GL_LINE_LOOP:
- /* Convert to linestrip and emit the final vertex explicitly,
- * but only in the resultant strip that requires it.
- */
- j = 0;
- while (j != prim->count) {
- begin(copy, GL_LINE_STRIP, prim->begin && j == 0);
-
- for (split = GL_FALSE; j != prim->count && !split; j++)
- split = elt(copy, start + j);
-
- if (j == prim->count) {
- /* Done, emit final line. Split doesn't matter as
- * it is always raised a bit early so we can emit
- * the last verts if necessary!
- */
- if (prim->end)
- (void)elt(copy, start + 0);
-
- end(copy, prim->end);
- }
- else {
- /* Wrap
- */
- assert(split);
- end(copy, 0);
- j--;
- }
- }
- break;
-
- case GL_TRIANGLE_FAN:
- case GL_POLYGON:
- j = 2;
- while (j != prim->count) {
- begin(copy, prim->mode, prim->begin && j == 0);
-
- split = elt(copy, start+0);
- assert(!split);
-
- split = elt(copy, start+j-1);
- assert(!split);
-
- for (; j != prim->count && !split; j++)
- split = elt(copy, start+j);
-
- end(copy, prim->end && j == prim->count);
-
- if (j != prim->count) {
- /* Wrapped the primitive, need to repeat some vertices:
- */
- j -= 1;
- }
- }
- break;
-
- default:
- (void)split_prim_inplace(prim->mode, &first, &incr);
-
- j = 0;
- while (j != prim->count) {
-
- begin(copy, prim->mode, prim->begin && j == 0);
-
- split = 0;
- for (k = 0; k < first; k++, j++)
- split |= elt(copy, start+j);
-
- assert(!split);
-
- for (; j != prim->count && !split;)
- for (k = 0; k < incr; k++, j++)
- split |= elt(copy, start+j);
-
- end(copy, prim->end && j == prim->count);
-
- if (j != prim->count) {
- /* Wrapped the primitive, need to repeat some vertices:
- */
- assert(j > first - incr);
- j -= (first - incr);
- }
- }
- break;
- }
- }
-
- if (copy->dstprim_nr)
- flush(copy);
-}
-
-
-static void
-replay_init(struct copy_context *copy)
-{
- struct gl_context *ctx = copy->ctx;
- GLuint i;
- GLuint offset;
- const GLvoid *srcptr;
-
- /* Make a list of varying attributes and their vbo's. Also
- * calculate vertex size.
- */
- copy->vertex_size = 0;
- for (i = 0; i < VERT_ATTRIB_MAX; i++) {
- const struct gl_vertex_array *array = ©->array[i];
- const struct gl_vertex_buffer_binding *binding = array->BufferBinding;
-
- if (binding->Stride == 0) {
- _mesa_copy_vertex_array(©->dstarray[i], array);
- }
- else {
- const struct gl_array_attributes *attrib = array->VertexAttrib;
- struct gl_buffer_object *vbo = binding->BufferObj;
- const GLubyte *ptr = _mesa_vertex_attrib_address(attrib, binding);
- GLuint j = copy->nr_varying++;
-
- copy->varying[j].attr = i;
- copy->varying[j].array = ©->array[i];
- copy->varying[j].size = attr_size(attrib);
- copy->vertex_size += attr_size(attrib);
-
- if (_mesa_is_bufferobj(vbo) &&
- !_mesa_bufferobj_mapped(vbo, MAP_INTERNAL))
- ctx->Driver.MapBufferRange(ctx, 0, vbo->Size, GL_MAP_READ_BIT, vbo,
- MAP_INTERNAL);
-
- copy->varying[j].src_ptr =
- ADD_POINTERS(vbo->Mappings[MAP_INTERNAL].Pointer, ptr);
-
- copy->dstarray[i].VertexAttrib = ©->varying[j].dstattribs;
- copy->dstarray[i].BufferBinding = ©->varying[j].dstbinding;
- }
- }
-
- /* There must always be an index buffer. Currently require the
- * caller convert non-indexed prims to indexed. Could alternately
- * do it internally.
- */
- if (_mesa_is_bufferobj(copy->ib->obj) &&
- !_mesa_bufferobj_mapped(copy->ib->obj, MAP_INTERNAL))
- ctx->Driver.MapBufferRange(ctx, 0, copy->ib->obj->Size, GL_MAP_READ_BIT,
- copy->ib->obj, MAP_INTERNAL);
-
- srcptr = (const GLubyte *)
- ADD_POINTERS(copy->ib->obj->Mappings[MAP_INTERNAL].Pointer,
- copy->ib->ptr);
-
- switch (copy->ib->index_size) {
- case 1:
- copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
- copy->srcelt = copy->translated_elt_buf;
-
- for (i = 0; i < copy->ib->count; i++)
- copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i];
- break;
-
- case 2:
- copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
- copy->srcelt = copy->translated_elt_buf;
-
- for (i = 0; i < copy->ib->count; i++)
- copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i];
- break;
-
- case 4:
- copy->translated_elt_buf = NULL;
- copy->srcelt = (const GLuint *)srcptr;
- break;
- }
-
- /* Figure out the maximum allowed vertex buffer size:
- */
- if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) {
- copy->dstbuf_size = copy->limits->max_verts;
- }
- else {
- copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size;
- }
-
- /* Allocate an output vertex buffer:
- *
- * XXX: This should be a VBO!
- */
- copy->dstbuf = malloc(copy->dstbuf_size * copy->vertex_size);
- copy->dstptr = copy->dstbuf;
-
- /* Setup new vertex arrays to point into the output buffer:
- */
- for (offset = 0, i = 0; i < copy->nr_varying; i++) {
- const struct gl_vertex_array *src = copy->varying[i].array;
- const struct gl_array_attributes *srcattr = src->VertexAttrib;
- struct gl_vertex_array *dst = ©->dstarray[i];
- struct gl_vertex_buffer_binding *dstbind = ©->varying[i].dstbinding;
- struct gl_array_attributes *dstattr = ©->varying[i].dstattribs;
-
- dstattr->Size = srcattr->Size;
- dstattr->Type = srcattr->Type;
- dstattr->Format = GL_RGBA;
- dstbind->Stride = copy->vertex_size;
- dstattr->Ptr = copy->dstbuf + offset;
- dstattr->Normalized = srcattr->Normalized;
- dstattr->Integer = srcattr->Integer;
- dstattr->Doubles = srcattr->Doubles;
- dstbind->BufferObj = ctx->Shared->NullBufferObj;
- dstattr->_ElementSize = srcattr->_ElementSize;
- dst->BufferBinding = dstbind;
- dst->VertexAttrib = dstattr;
-
- offset += copy->varying[i].size;
- }
-
- /* Allocate an output element list:
- */
- copy->dstelt_size = MIN2(65536, copy->ib->count * 2 + 3);
- copy->dstelt_size = MIN2(copy->dstelt_size, copy->limits->max_indices);
- copy->dstelt = malloc(sizeof(GLuint) * copy->dstelt_size);
- copy->dstelt_nr = 0;
-
- /* Setup the new index buffer to point to the allocated element
- * list:
- */
- copy->dstib.count = 0; /* duplicates dstelt_nr */
- copy->dstib.index_size = 4;
- copy->dstib.obj = ctx->Shared->NullBufferObj;
- copy->dstib.ptr = copy->dstelt;
-}
-
-
-/**
- * Free up everything allocated during split/replay.
- */
-static void
-replay_finish(struct copy_context *copy)
-{
- struct gl_context *ctx = copy->ctx;
- GLuint i;
-
- /* Free our vertex and index buffers */
- free(copy->translated_elt_buf);
- free(copy->dstbuf);
- free(copy->dstelt);
-
- /* Unmap VBO's */
- for (i = 0; i < copy->nr_varying; i++) {
- struct gl_buffer_object *vbo =
- copy->varying[i].array->BufferBinding->BufferObj;
- if (_mesa_is_bufferobj(vbo) && _mesa_bufferobj_mapped(vbo, MAP_INTERNAL))
- ctx->Driver.UnmapBuffer(ctx, vbo, MAP_INTERNAL);
- }
-
- /* Unmap index buffer */
- if (_mesa_is_bufferobj(copy->ib->obj) &&
- _mesa_bufferobj_mapped(copy->ib->obj, MAP_INTERNAL)) {
- ctx->Driver.UnmapBuffer(ctx, copy->ib->obj, MAP_INTERNAL);
- }
-}
-
-
-/**
- * Split VBO into smaller pieces, draw the pieces.
- */
-void
-vbo_split_copy(struct gl_context *ctx,
- const struct gl_vertex_array *arrays,
- const struct _mesa_prim *prim,
- GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
- vbo_draw_func draw,
- const struct split_limits *limits)
-{
- struct copy_context copy;
- GLuint i, this_nr_prims;
-
- for (i = 0; i < nr_prims;) {
- /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices
- * will rebase the elements to the basevertex, and we'll only
- * emit strings of prims with the same basevertex in one draw call.
- */
- for (this_nr_prims = 1; i + this_nr_prims < nr_prims;
- this_nr_prims++) {
- if (prim[i].basevertex != prim[i + this_nr_prims].basevertex)
- break;
- }
-
- memset(©, 0, sizeof(copy));
-
- /* Require indexed primitives:
- */
- assert(ib);
-
- copy.ctx = ctx;
- copy.array = arrays;
- copy.prim = &prim[i];
- copy.nr_prims = this_nr_prims;
- copy.ib = ib;
- copy.draw = draw;
- copy.limits = limits;
-
- /* Clear the vertex cache:
- */
- for (i = 0; i < ELT_TABLE_SIZE; i++)
- copy.vert_cache[i].in = ~0;
-
- replay_init(©);
- replay_elts(©);
- replay_finish(©);
- }
-}
+++ /dev/null
-
-/*
- * Mesa 3-D graphics library
- *
- * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * 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 NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS 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.
- *
- * Authors:
- * Keith Whitwell <keithw@vmware.com>
- */
-
-
-#include "main/mtypes.h"
-#include "main/macros.h"
-#include "main/enums.h"
-#include "vbo_split.h"
-
-
-#define MAX_PRIM 32
-
-/* Used for splitting without copying. No attempt is made to handle
- * too large indexed vertex buffers: In general you need to copy to do
- * that.
- */
-struct split_context {
- struct gl_context *ctx;
- const struct gl_vertex_array *array;
- const struct _mesa_prim *prim;
- GLuint nr_prims;
- const struct _mesa_index_buffer *ib;
- GLuint min_index;
- GLuint max_index;
- vbo_draw_func draw;
-
- const struct split_limits *limits;
- GLuint limit;
-
- struct _mesa_prim dstprim[MAX_PRIM];
- GLuint dstprim_nr;
-};
-
-
-
-
-static void
-flush_vertex( struct split_context *split)
-{
- struct gl_context *ctx = split->ctx;
- struct _mesa_index_buffer ib;
- GLuint i;
-
- if (!split->dstprim_nr)
- return;
-
- if (split->ib) {
- ib = *split->ib;
-
- ib.count = split->max_index - split->min_index + 1;
- ib.ptr = (const void *)((const char *)ib.ptr +
- split->min_index * ib.index_size);
-
- /* Rebase the primitives to save index buffer entries. */
- for (i = 0; i < split->dstprim_nr; i++)
- split->dstprim[i].start -= split->min_index;
- }
-
- assert(split->max_index >= split->min_index);
-
- split->draw(ctx,
- split->array,
- split->dstprim,
- split->dstprim_nr,
- split->ib ? &ib : NULL,
- !split->ib,
- split->min_index,
- split->max_index,
- NULL, 0, NULL);
-
- split->dstprim_nr = 0;
- split->min_index = ~0;
- split->max_index = 0;
-}
-
-
-static struct _mesa_prim *
-next_outprim(struct split_context *split)
-{
- if (split->dstprim_nr == MAX_PRIM-1) {
- flush_vertex(split);
- }
-
- {
- struct _mesa_prim *prim = &split->dstprim[split->dstprim_nr++];
- memset(prim, 0, sizeof(*prim));
- return prim;
- }
-}
-
-
-static void
-update_index_bounds(struct split_context *split,
- const struct _mesa_prim *prim)
-{
- split->min_index = MIN2(split->min_index, prim->start);
- split->max_index = MAX2(split->max_index, prim->start + prim->count - 1);
-}
-
-
-/* Return the maximum amount of vertices that can be emitted for a
- * primitive starting at 'prim->start', depending on the previous
- * index bounds.
- */
-static GLuint
-get_max_vertices(struct split_context *split,
- const struct _mesa_prim *prim)
-{
- if ((prim->start > split->min_index &&
- prim->start - split->min_index >= split->limit) ||
- (prim->start < split->max_index &&
- split->max_index - prim->start >= split->limit))
- /* "prim" starts too far away from the old range. */
- return 0;
-
- return MIN2(split->min_index, prim->start) + split->limit - prim->start;
-}
-
-
-/* Break large primitives into smaller ones. If not possible, convert
- * the primitive to indexed and pass to split_elts().
- */
-static void
-split_prims(struct split_context *split)
-{
- GLuint i;
-
- for (i = 0; i < split->nr_prims; i++) {
- const struct _mesa_prim *prim = &split->prim[i];
- GLuint first, incr;
- GLboolean split_inplace = split_prim_inplace(prim->mode, &first, &incr);
- GLuint available = get_max_vertices(split, prim);
- GLuint count = prim->count - (prim->count - first) % incr;
-
- if (prim->count < first)
- continue;
-
- if ((available < count && !split_inplace) ||
- (available < first && split_inplace)) {
- flush_vertex(split);
- available = get_max_vertices(split, prim);
- }
-
- if (available >= count) {
- struct _mesa_prim *outprim = next_outprim(split);
-
- *outprim = *prim;
- update_index_bounds(split, outprim);
- }
- else if (split_inplace) {
- GLuint j, nr;
-
- for (j = 0 ; j < count ;) {
- GLuint remaining = count - j;
- struct _mesa_prim *outprim = next_outprim(split);
-
- nr = MIN2(available, remaining);
- nr -= (nr - first) % incr;
-
- outprim->mode = prim->mode;
- outprim->begin = (j == 0 && prim->begin);
- outprim->end = (nr == remaining && prim->end);
- outprim->start = prim->start + j;
- outprim->count = nr;
- outprim->num_instances = prim->num_instances;
- outprim->base_instance = prim->base_instance;
-
- update_index_bounds(split, outprim);
-
- if (nr == remaining) {
- /* Finished */
- j += nr;
- }
- else {
- /* Wrapped the primitive */
- j += nr - (first - incr);
- flush_vertex(split);
- available = get_max_vertices(split, prim);
- }
- }
- }
- else if (split->ib == NULL) {
- /* XXX: could at least send the first max_verts off from the
- * inplace buffers.
- */
-
- /* else convert to indexed primitive and pass to split_elts,
- * which will do the necessary copying and turn it back into a
- * vertex primitive for rendering...
- */
- struct _mesa_index_buffer ib;
- struct _mesa_prim tmpprim;
- GLuint *elts = malloc(count * sizeof(GLuint));
- GLuint j;
-
- for (j = 0; j < count; j++)
- elts[j] = prim->start + j;
-
- ib.count = count;
- ib.index_size = 4;
- ib.obj = split->ctx->Shared->NullBufferObj;
- ib.ptr = elts;
-
- tmpprim = *prim;
- tmpprim.indexed = 1;
- tmpprim.start = 0;
- tmpprim.count = count;
- tmpprim.num_instances = 1;
- tmpprim.base_instance = 0;
-
- flush_vertex(split);
-
- vbo_split_copy(split->ctx,
- split->array,
- &tmpprim, 1,
- &ib,
- split->draw,
- split->limits);
-
- free(elts);
- }
- else {
- flush_vertex(split);
-
- vbo_split_copy(split->ctx,
- split->array,
- prim, 1,
- split->ib,
- split->draw,
- split->limits);
- }
- }
-
- flush_vertex(split);
-}
-
-
-void
-vbo_split_inplace(struct gl_context *ctx,
- const struct gl_vertex_array *arrays,
- const struct _mesa_prim *prim,
- GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
- GLuint min_index,
- GLuint max_index,
- vbo_draw_func draw,
- const struct split_limits *limits)
-{
- struct split_context split;
-
- memset(&split, 0, sizeof(split));
-
- split.ctx = ctx;
- split.array = arrays;
- split.prim = prim;
- split.nr_prims = nr_prims;
- split.ib = ib;
-
- /* Empty interval, makes calculations simpler. */
- split.min_index = ~0;
- split.max_index = 0;
-
- split.draw = draw;
- split.limits = limits;
- split.limit = ib ? limits->max_indices : limits->max_verts;
-
- split_prims(&split);
-}
-
-