From: Mathias Fröhlich Date: Sun, 25 Mar 2018 17:16:54 +0000 (+0200) Subject: vbo: Move vbo_split into the tnl module. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=6e9f00e3fc6f3b1331031f0995254c768d38ea81;p=mesa.git vbo: Move vbo_split into the tnl module. Move the files, adapt to the naming scheme in tnl, update callers and build system. Reviewed-by: Brian Paul Signed-off-by: Mathias Fröhlich --- diff --git a/src/mesa/Makefile.sources b/src/mesa/Makefile.sources index 0446078136d..92565ef8f5e 100644 --- a/src/mesa/Makefile.sources +++ b/src/mesa/Makefile.sources @@ -372,6 +372,10 @@ TNL_FILES = \ 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 \ @@ -411,11 +415,7 @@ VBO_FILES = \ 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 \ diff --git a/src/mesa/drivers/dri/nouveau/nouveau_vbo_t.c b/src/mesa/drivers/dri/nouveau/nouveau_vbo_t.c index 4533069692c..79b444cf55f 100644 --- a/src/mesa/drivers/dri/nouveau/nouveau_vbo_t.c +++ b/src/mesa/drivers/dri/nouveau/nouveau_vbo_t.c @@ -277,8 +277,8 @@ vbo_maybe_split(struct gl_context *ctx, const struct gl_vertex_array *arrays, .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; } diff --git a/src/mesa/meson.build b/src/mesa/meson.build index b74d1693771..d2d058bfa3c 100644 --- a/src/mesa/meson.build +++ b/src/mesa/meson.build @@ -343,10 +343,6 @@ files_libmesa_common = files( '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', ) @@ -366,6 +362,10 @@ files_libmesa_classic = files( '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', diff --git a/src/mesa/tnl/t_draw.c b/src/mesa/tnl/t_draw.c index a0fd58432a1..a83b98eede1 100644 --- a/src/mesa/tnl/t_draw.c +++ b/src/mesa/tnl/t_draw.c @@ -486,10 +486,10 @@ void _tnl_draw_prims(struct gl_context *ctx, /* 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 diff --git a/src/mesa/tnl/t_rebase.c b/src/mesa/tnl/t_rebase.c index 19e759f44be..d28512423c3 100644 --- a/src/mesa/tnl/t_rebase.c +++ b/src/mesa/tnl/t_rebase.c @@ -51,6 +51,7 @@ #include "main/glheader.h" #include "main/imports.h" #include "main/mtypes.h" +#include "vbo/vbo.h" #include "t_rebase.h" @@ -108,7 +109,7 @@ void t_rebase_prims( struct gl_context *ctx, 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]; diff --git a/src/mesa/tnl/t_rebase.h b/src/mesa/tnl/t_rebase.h index 16a3a2b5a33..ce2e8b0590e 100644 --- a/src/mesa/tnl/t_rebase.h +++ b/src/mesa/tnl/t_rebase.h @@ -25,7 +25,7 @@ #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, @@ -34,6 +34,6 @@ void t_rebase_prims( struct gl_context *ctx, const struct _mesa_index_buffer *ib, GLuint min_index, GLuint max_index, - vbo_draw_func draw ); + tnl_draw_func draw ); #endif diff --git a/src/mesa/tnl/t_split.c b/src/mesa/tnl/t_split.c new file mode 100644 index 00000000000..b98bd404d52 --- /dev/null +++ b/src/mesa/tnl/t_split.c @@ -0,0 +1,160 @@ + +/* + * 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 + */ + +/* 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); + } + } +} + diff --git a/src/mesa/tnl/t_split.h b/src/mesa/tnl/t_split.h new file mode 100644 index 00000000000..ced7d30bdf1 --- /dev/null +++ b/src/mesa/tnl/t_split.h @@ -0,0 +1,74 @@ +/* + * 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 diff --git a/src/mesa/tnl/t_split_copy.c b/src/mesa/tnl/t_split_copy.c new file mode 100644 index 00000000000..f76a470b5ff --- /dev/null +++ b/src/mesa/tnl/t_split_copy.c @@ -0,0 +1,638 @@ + +/* + * 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 + */ + +/* Split indexed primitives with per-vertex copying. + */ + +#include + +#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(©); + } +} diff --git a/src/mesa/tnl/t_split_inplace.c b/src/mesa/tnl/t_split_inplace.c new file mode 100644 index 00000000000..15a09861c73 --- /dev/null +++ b/src/mesa/tnl/t_split_inplace.c @@ -0,0 +1,298 @@ + +/* + * 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 + */ + + +#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); +} + + diff --git a/src/mesa/tnl/tnl.h b/src/mesa/tnl/tnl.h index e79c4f62048..45052a3a89c 100644 --- a/src/mesa/tnl/tnl.h +++ b/src/mesa/tnl/tnl.h @@ -108,4 +108,84 @@ _tnl_RasterPos(struct gl_context *ctx, const GLfloat vObj[4]); 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 diff --git a/src/mesa/vbo/vbo.h b/src/mesa/vbo/vbo.h index 37aa59d3061..9b150662915 100644 --- a/src/mesa/vbo/vbo.h +++ b/src/mesa/vbo/vbo.h @@ -119,75 +119,6 @@ void 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, @@ -198,18 +129,6 @@ _vbo_draw_indirect(struct gl_context *ctx, GLuint mode, 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); diff --git a/src/mesa/vbo/vbo_split.c b/src/mesa/vbo/vbo_split.c deleted file mode 100644 index ffe1d67489a..00000000000 --- a/src/mesa/vbo/vbo_split.c +++ /dev/null @@ -1,160 +0,0 @@ - -/* - * 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 - */ - -/* 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); - } - } -} - diff --git a/src/mesa/vbo/vbo_split.h b/src/mesa/vbo/vbo_split.h deleted file mode 100644 index fea2b48aecc..00000000000 --- a/src/mesa/vbo/vbo_split.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 diff --git a/src/mesa/vbo/vbo_split_copy.c b/src/mesa/vbo/vbo_split_copy.c deleted file mode 100644 index 2aab670de1e..00000000000 --- a/src/mesa/vbo/vbo_split_copy.c +++ /dev/null @@ -1,637 +0,0 @@ - -/* - * 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 - */ - -/* Split indexed primitives with per-vertex copying. - */ - -#include - -#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(©); - } -} diff --git a/src/mesa/vbo/vbo_split_inplace.c b/src/mesa/vbo/vbo_split_inplace.c deleted file mode 100644 index b63c05c75f0..00000000000 --- a/src/mesa/vbo/vbo_split_inplace.c +++ /dev/null @@ -1,295 +0,0 @@ - -/* - * 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 - */ - - -#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); -} - -