101e04c3fSmrg
201e04c3fSmrg/*
301e04c3fSmrg * Mesa 3-D graphics library
401e04c3fSmrg *
501e04c3fSmrg * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
601e04c3fSmrg *
701e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
801e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
901e04c3fSmrg * to deal in the Software without restriction, including without limitation
1001e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1101e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
1201e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1301e04c3fSmrg *
1401e04c3fSmrg * The above copyright notice and this permission notice shall be included
1501e04c3fSmrg * in all copies or substantial portions of the Software.
1601e04c3fSmrg *
1701e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1801e04c3fSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1901e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2001e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
2101e04c3fSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2201e04c3fSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2301e04c3fSmrg * OTHER DEALINGS IN THE SOFTWARE.
2401e04c3fSmrg *
2501e04c3fSmrg * Authors:
2601e04c3fSmrg *    Keith Whitwell <keithw@vmware.com>
2701e04c3fSmrg */
2801e04c3fSmrg
2901e04c3fSmrg/* Split indexed primitives with per-vertex copying.
3001e04c3fSmrg */
3101e04c3fSmrg
3201e04c3fSmrg#include <stdio.h>
3301e04c3fSmrg
3401e04c3fSmrg#include "main/glheader.h"
3501e04c3fSmrg#include "main/bufferobj.h"
367ec681f3Smrg
3701e04c3fSmrg#include "main/glformats.h"
3801e04c3fSmrg#include "main/macros.h"
3901e04c3fSmrg#include "main/mtypes.h"
4001e04c3fSmrg#include "main/varray.h"
4101e04c3fSmrg#include "vbo/vbo.h"
4201e04c3fSmrg
4301e04c3fSmrg#include "t_split.h"
4401e04c3fSmrg#include "tnl.h"
4501e04c3fSmrg
4601e04c3fSmrg
4701e04c3fSmrg#define ELT_TABLE_SIZE 16
4801e04c3fSmrg
4901e04c3fSmrg/**
5001e04c3fSmrg * Used for vertex-level splitting of indexed buffers.  Note that
5101e04c3fSmrg * non-indexed primitives may be converted to indexed in some cases
5201e04c3fSmrg * (eg loops, fans) in order to use this splitting path.
5301e04c3fSmrg */
5401e04c3fSmrgstruct copy_context {
5501e04c3fSmrg   struct gl_context *ctx;
5601e04c3fSmrg   const struct tnl_vertex_array *array;
5701e04c3fSmrg   const struct _mesa_prim *prim;
5801e04c3fSmrg   GLuint nr_prims;
5901e04c3fSmrg   const struct _mesa_index_buffer *ib;
6001e04c3fSmrg   tnl_draw_func draw;
6101e04c3fSmrg
6201e04c3fSmrg   const struct split_limits *limits;
6301e04c3fSmrg
6401e04c3fSmrg   struct {
6501e04c3fSmrg      GLuint attr;
6601e04c3fSmrg      GLuint size;
6701e04c3fSmrg      const struct tnl_vertex_array *array;
6801e04c3fSmrg      const GLubyte *src_ptr;
6901e04c3fSmrg
7001e04c3fSmrg      struct gl_vertex_buffer_binding dstbinding;
7101e04c3fSmrg      struct gl_array_attributes dstattribs;
7201e04c3fSmrg
7301e04c3fSmrg   } varying[VERT_ATTRIB_MAX];
7401e04c3fSmrg   GLuint nr_varying;
7501e04c3fSmrg
7601e04c3fSmrg   struct tnl_vertex_array dstarray[VERT_ATTRIB_MAX];
7701e04c3fSmrg   struct _mesa_index_buffer dstib;
7801e04c3fSmrg
7901e04c3fSmrg   GLuint *translated_elt_buf;
8001e04c3fSmrg   const GLuint *srcelt;
8101e04c3fSmrg
8201e04c3fSmrg   /** A baby hash table to avoid re-emitting (some) duplicate
8301e04c3fSmrg    * vertices when splitting indexed primitives.
8401e04c3fSmrg    */
8501e04c3fSmrg   struct {
8601e04c3fSmrg      GLuint in;
8701e04c3fSmrg      GLuint out;
8801e04c3fSmrg   } vert_cache[ELT_TABLE_SIZE];
8901e04c3fSmrg
9001e04c3fSmrg   GLuint vertex_size;
9101e04c3fSmrg   GLubyte *dstbuf;
9201e04c3fSmrg   GLubyte *dstptr;     /**< dstptr == dstbuf + dstelt_max * vertsize */
9301e04c3fSmrg   GLuint dstbuf_size;  /**< in vertices */
9401e04c3fSmrg   GLuint dstbuf_nr;    /**< count of emitted vertices, also the largest value
9501e04c3fSmrg                         * in dstelt.  Our MaxIndex.
9601e04c3fSmrg                         */
9701e04c3fSmrg
9801e04c3fSmrg   GLuint *dstelt;
9901e04c3fSmrg   GLuint dstelt_nr;
10001e04c3fSmrg   GLuint dstelt_size;
10101e04c3fSmrg
10201e04c3fSmrg#define MAX_PRIM 32
10301e04c3fSmrg   struct _mesa_prim dstprim[MAX_PRIM];
10401e04c3fSmrg   GLuint dstprim_nr;
10501e04c3fSmrg};
10601e04c3fSmrg
10701e04c3fSmrg
10801e04c3fSmrg/**
10901e04c3fSmrg * Shallow copy one vertex array to another.
11001e04c3fSmrg */
11101e04c3fSmrgstatic inline void
11201e04c3fSmrgcopy_vertex_array(struct tnl_vertex_array *dst,
11301e04c3fSmrg                  const struct tnl_vertex_array *src)
11401e04c3fSmrg{
11501e04c3fSmrg   dst->VertexAttrib = src->VertexAttrib;
11601e04c3fSmrg   dst->BufferBinding = src->BufferBinding;
11701e04c3fSmrg}
11801e04c3fSmrg
11901e04c3fSmrg
12001e04c3fSmrg/**
12101e04c3fSmrg * Starts returning true slightly before the buffer fills, to ensure
12201e04c3fSmrg * that there is sufficient room for any remaining vertices to finish
12301e04c3fSmrg * off the prim:
12401e04c3fSmrg */
12501e04c3fSmrgstatic GLboolean
12601e04c3fSmrgcheck_flush(struct copy_context *copy)
12701e04c3fSmrg{
12801e04c3fSmrg   GLenum mode = copy->dstprim[copy->dstprim_nr].mode;
12901e04c3fSmrg
13001e04c3fSmrg   if (GL_TRIANGLE_STRIP == mode &&
13101e04c3fSmrg       copy->dstelt_nr & 1) { /* see bug9962 */
13201e04c3fSmrg       return GL_FALSE;
13301e04c3fSmrg   }
13401e04c3fSmrg
13501e04c3fSmrg   if (copy->dstbuf_nr + 4 > copy->dstbuf_size)
13601e04c3fSmrg      return GL_TRUE;
13701e04c3fSmrg
13801e04c3fSmrg   if (copy->dstelt_nr + 4 > copy->dstelt_size)
13901e04c3fSmrg      return GL_TRUE;
14001e04c3fSmrg
14101e04c3fSmrg   return GL_FALSE;
14201e04c3fSmrg}
14301e04c3fSmrg
14401e04c3fSmrg
14501e04c3fSmrg/**
14601e04c3fSmrg * Dump the parameters/info for a vbo->draw() call.
14701e04c3fSmrg */
14801e04c3fSmrgstatic void
1497ec681f3Smrgdump_draw_info(const struct tnl_vertex_array *arrays,
15001e04c3fSmrg               const struct _mesa_prim *prims,
15101e04c3fSmrg               GLuint nr_prims,
1527ec681f3Smrg               const struct _mesa_index_buffer *ib)
15301e04c3fSmrg{
15401e04c3fSmrg   GLuint i, j;
15501e04c3fSmrg
15601e04c3fSmrg   printf("VBO Draw:\n");
15701e04c3fSmrg   for (i = 0; i < nr_prims; i++) {
15801e04c3fSmrg      printf("Prim %u of %u\n", i, nr_prims);
15901e04c3fSmrg      printf("  Prim mode 0x%x\n", prims[i].mode);
16001e04c3fSmrg      printf("  IB: %p\n", (void*) ib);
16101e04c3fSmrg      for (j = 0; j < VERT_ATTRIB_MAX; j++) {
16201e04c3fSmrg         const struct tnl_vertex_array *array = &arrays[j];
16301e04c3fSmrg         const struct gl_vertex_buffer_binding *binding
16401e04c3fSmrg            = array->BufferBinding;
16501e04c3fSmrg         const struct gl_array_attributes *attrib = array->VertexAttrib;
16601e04c3fSmrg         const GLubyte *ptr = _mesa_vertex_attrib_address(attrib, binding);
16701e04c3fSmrg         printf("    array %d at %p:\n", j, (void*) &arrays[j]);
16801e04c3fSmrg         printf("      ptr %p, size %d, type 0x%x, stride %d\n",
169b9abf16eSmaya                ptr, attrib->Format.Size, attrib->Format.Type, binding->Stride);
17001e04c3fSmrg         if (0) {
17101e04c3fSmrg            GLint k = prims[i].start + prims[i].count - 1;
17201e04c3fSmrg            GLfloat *last = (GLfloat *) (ptr + binding->Stride * k);
17301e04c3fSmrg            printf("        last: %f %f %f\n",
17401e04c3fSmrg                   last[0], last[1], last[2]);
17501e04c3fSmrg         }
17601e04c3fSmrg      }
17701e04c3fSmrg   }
17801e04c3fSmrg}
17901e04c3fSmrg
18001e04c3fSmrg
18101e04c3fSmrgstatic void
18201e04c3fSmrgflush(struct copy_context *copy)
18301e04c3fSmrg{
18401e04c3fSmrg   struct gl_context *ctx = copy->ctx;
18501e04c3fSmrg   GLuint i;
18601e04c3fSmrg
18701e04c3fSmrg   /* Set some counters:
18801e04c3fSmrg    */
18901e04c3fSmrg   copy->dstib.count = copy->dstelt_nr;
19001e04c3fSmrg
19101e04c3fSmrg#if 0
1927ec681f3Smrg   dump_draw_info(copy->dstarray,
19301e04c3fSmrg                  copy->dstprim,
19401e04c3fSmrg                  copy->dstprim_nr,
1957ec681f3Smrg                  &copy->dstib);
19601e04c3fSmrg#else
19701e04c3fSmrg   (void) dump_draw_info;
19801e04c3fSmrg#endif
19901e04c3fSmrg
20001e04c3fSmrg   copy->draw(ctx,
20101e04c3fSmrg              copy->dstarray,
20201e04c3fSmrg              copy->dstprim,
20301e04c3fSmrg              copy->dstprim_nr,
20401e04c3fSmrg              &copy->dstib,
20501e04c3fSmrg              GL_TRUE,
20601e04c3fSmrg              0,
20701e04c3fSmrg              copy->dstbuf_nr - 1,
2087ec681f3Smrg              1,
2097ec681f3Smrg              0);
21001e04c3fSmrg
21101e04c3fSmrg   /* Reset all pointers:
21201e04c3fSmrg    */
21301e04c3fSmrg   copy->dstprim_nr = 0;
21401e04c3fSmrg   copy->dstelt_nr = 0;
21501e04c3fSmrg   copy->dstbuf_nr = 0;
21601e04c3fSmrg   copy->dstptr = copy->dstbuf;
21701e04c3fSmrg
21801e04c3fSmrg   /* Clear the vertex cache:
21901e04c3fSmrg    */
22001e04c3fSmrg   for (i = 0; i < ELT_TABLE_SIZE; i++)
22101e04c3fSmrg      copy->vert_cache[i].in = ~0;
22201e04c3fSmrg}
22301e04c3fSmrg
22401e04c3fSmrg
22501e04c3fSmrg/**
22601e04c3fSmrg * Called at begin of each primitive during replay.
22701e04c3fSmrg */
22801e04c3fSmrgstatic void
22901e04c3fSmrgbegin(struct copy_context *copy, GLenum mode, GLboolean begin_flag)
23001e04c3fSmrg{
23101e04c3fSmrg   struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
23201e04c3fSmrg
23301e04c3fSmrg   prim->mode = mode;
23401e04c3fSmrg   prim->begin = begin_flag;
23501e04c3fSmrg}
23601e04c3fSmrg
23701e04c3fSmrg
23801e04c3fSmrg/**
23901e04c3fSmrg * Use a hashtable to attempt to identify recently-emitted vertices
24001e04c3fSmrg * and avoid re-emitting them.
24101e04c3fSmrg */
24201e04c3fSmrgstatic GLuint
24301e04c3fSmrgelt(struct copy_context *copy, GLuint elt_idx)
24401e04c3fSmrg{
24501e04c3fSmrg   GLuint elt = copy->srcelt[elt_idx] + copy->prim->basevertex;
24601e04c3fSmrg   GLuint slot = elt & (ELT_TABLE_SIZE-1);
24701e04c3fSmrg
24801e04c3fSmrg   /* Look up the incoming element in the vertex cache.  Re-emit if
24901e04c3fSmrg    * necessary.
25001e04c3fSmrg    */
25101e04c3fSmrg   if (copy->vert_cache[slot].in != elt) {
25201e04c3fSmrg      GLubyte *csr = copy->dstptr;
25301e04c3fSmrg      GLuint i;
25401e04c3fSmrg
25501e04c3fSmrg      for (i = 0; i < copy->nr_varying; i++) {
25601e04c3fSmrg         const struct tnl_vertex_array *srcarray = copy->varying[i].array;
25701e04c3fSmrg         const struct gl_vertex_buffer_binding* srcbinding
25801e04c3fSmrg            = srcarray->BufferBinding;
25901e04c3fSmrg         const GLubyte *srcptr
26001e04c3fSmrg            = copy->varying[i].src_ptr + elt * srcbinding->Stride;
26101e04c3fSmrg
26201e04c3fSmrg         memcpy(csr, srcptr, copy->varying[i].size);
26301e04c3fSmrg         csr += copy->varying[i].size;
26401e04c3fSmrg
26501e04c3fSmrg#ifdef NAN_CHECK
266b9abf16eSmaya         if (srcarray->Format.Type == GL_FLOAT) {
26701e04c3fSmrg            GLuint k;
26801e04c3fSmrg            GLfloat *f = (GLfloat *) srcptr;
26901e04c3fSmrg            for (k = 0; k < srcarray->Size; k++) {
2707ec681f3Smrg               assert(!util_is_inf_or_nan(f[k]));
27101e04c3fSmrg               assert(f[k] <= 1.0e20 && f[k] >= -1.0e20);
27201e04c3fSmrg            }
27301e04c3fSmrg         }
27401e04c3fSmrg#endif
27501e04c3fSmrg
27601e04c3fSmrg         if (0) {
27701e04c3fSmrg            const GLuint *f = (const GLuint *)srcptr;
27801e04c3fSmrg            GLuint j;
27901e04c3fSmrg            printf("  varying %d: ", i);
28001e04c3fSmrg            for (j = 0; j < copy->varying[i].size / 4; j++)
28101e04c3fSmrg               printf("%x ", f[j]);
28201e04c3fSmrg            printf("\n");
28301e04c3fSmrg         }
28401e04c3fSmrg      }
28501e04c3fSmrg
28601e04c3fSmrg      copy->vert_cache[slot].in = elt;
28701e04c3fSmrg      copy->vert_cache[slot].out = copy->dstbuf_nr++;
28801e04c3fSmrg      copy->dstptr += copy->vertex_size;
28901e04c3fSmrg
29001e04c3fSmrg      assert(csr == copy->dstptr);
29101e04c3fSmrg      assert(copy->dstptr == (copy->dstbuf +
29201e04c3fSmrg                              copy->dstbuf_nr * copy->vertex_size));
29301e04c3fSmrg   }
29401e04c3fSmrg
29501e04c3fSmrg   copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
29601e04c3fSmrg   return check_flush(copy);
29701e04c3fSmrg}
29801e04c3fSmrg
29901e04c3fSmrg
30001e04c3fSmrg/**
30101e04c3fSmrg * Called at end of each primitive during replay.
30201e04c3fSmrg */
30301e04c3fSmrgstatic void
30401e04c3fSmrgend(struct copy_context *copy, GLboolean end_flag)
30501e04c3fSmrg{
30601e04c3fSmrg   struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
30701e04c3fSmrg
30801e04c3fSmrg   prim->end = end_flag;
30901e04c3fSmrg   prim->count = copy->dstelt_nr - prim->start;
31001e04c3fSmrg
31101e04c3fSmrg   if (++copy->dstprim_nr == MAX_PRIM || check_flush(copy)) {
31201e04c3fSmrg      flush(copy);
31301e04c3fSmrg   }
31401e04c3fSmrg}
31501e04c3fSmrg
31601e04c3fSmrg
31701e04c3fSmrgstatic void
31801e04c3fSmrgreplay_elts(struct copy_context *copy)
31901e04c3fSmrg{
32001e04c3fSmrg   GLuint i, j, k;
32101e04c3fSmrg   GLboolean split;
32201e04c3fSmrg
32301e04c3fSmrg   for (i = 0; i < copy->nr_prims; i++) {
32401e04c3fSmrg      const struct _mesa_prim *prim = &copy->prim[i];
32501e04c3fSmrg      const GLuint start = prim->start;
32601e04c3fSmrg      GLuint first, incr;
32701e04c3fSmrg
32801e04c3fSmrg      switch (prim->mode) {
32901e04c3fSmrg      case GL_LINE_LOOP:
33001e04c3fSmrg         /* Convert to linestrip and emit the final vertex explicitly,
33101e04c3fSmrg          * but only in the resultant strip that requires it.
33201e04c3fSmrg          */
33301e04c3fSmrg         j = 0;
33401e04c3fSmrg         while (j != prim->count) {
33501e04c3fSmrg            begin(copy, GL_LINE_STRIP, prim->begin && j == 0);
33601e04c3fSmrg
33701e04c3fSmrg            for (split = GL_FALSE; j != prim->count && !split; j++)
33801e04c3fSmrg               split = elt(copy, start + j);
33901e04c3fSmrg
34001e04c3fSmrg            if (j == prim->count) {
34101e04c3fSmrg               /* Done, emit final line.  Split doesn't matter as
34201e04c3fSmrg                * it is always raised a bit early so we can emit
34301e04c3fSmrg                * the last verts if necessary!
34401e04c3fSmrg                */
34501e04c3fSmrg               if (prim->end)
34601e04c3fSmrg                  (void)elt(copy, start + 0);
34701e04c3fSmrg
34801e04c3fSmrg               end(copy, prim->end);
34901e04c3fSmrg            }
35001e04c3fSmrg            else {
35101e04c3fSmrg               /* Wrap
35201e04c3fSmrg                */
35301e04c3fSmrg               assert(split);
35401e04c3fSmrg               end(copy, 0);
35501e04c3fSmrg               j--;
35601e04c3fSmrg            }
35701e04c3fSmrg         }
35801e04c3fSmrg         break;
35901e04c3fSmrg
36001e04c3fSmrg      case GL_TRIANGLE_FAN:
36101e04c3fSmrg      case GL_POLYGON:
36201e04c3fSmrg         j = 2;
36301e04c3fSmrg         while (j != prim->count) {
36401e04c3fSmrg            begin(copy, prim->mode, prim->begin && j == 0);
36501e04c3fSmrg
36601e04c3fSmrg            split = elt(copy, start+0);
36701e04c3fSmrg            assert(!split);
36801e04c3fSmrg
36901e04c3fSmrg            split = elt(copy, start+j-1);
37001e04c3fSmrg            assert(!split);
37101e04c3fSmrg
37201e04c3fSmrg            for (; j != prim->count && !split; j++)
37301e04c3fSmrg               split = elt(copy, start+j);
37401e04c3fSmrg
37501e04c3fSmrg            end(copy, prim->end && j == prim->count);
37601e04c3fSmrg
37701e04c3fSmrg            if (j != prim->count) {
37801e04c3fSmrg               /* Wrapped the primitive, need to repeat some vertices:
37901e04c3fSmrg                */
38001e04c3fSmrg               j -= 1;
38101e04c3fSmrg            }
38201e04c3fSmrg         }
38301e04c3fSmrg         break;
38401e04c3fSmrg
38501e04c3fSmrg      default:
38601e04c3fSmrg         (void)_tnl_split_prim_inplace(prim->mode, &first, &incr);
38701e04c3fSmrg
38801e04c3fSmrg         j = 0;
38901e04c3fSmrg         while (j != prim->count) {
39001e04c3fSmrg
39101e04c3fSmrg            begin(copy, prim->mode, prim->begin && j == 0);
39201e04c3fSmrg
39301e04c3fSmrg            split = 0;
39401e04c3fSmrg            for (k = 0; k < first; k++, j++)
39501e04c3fSmrg               split |= elt(copy, start+j);
39601e04c3fSmrg
39701e04c3fSmrg            assert(!split);
39801e04c3fSmrg
39901e04c3fSmrg            for (; j != prim->count && !split;)
40001e04c3fSmrg               for (k = 0; k < incr; k++, j++)
40101e04c3fSmrg                  split |= elt(copy, start+j);
40201e04c3fSmrg
40301e04c3fSmrg            end(copy, prim->end && j == prim->count);
40401e04c3fSmrg
40501e04c3fSmrg            if (j != prim->count) {
40601e04c3fSmrg               /* Wrapped the primitive, need to repeat some vertices:
40701e04c3fSmrg                */
40801e04c3fSmrg               assert(j > first - incr);
40901e04c3fSmrg               j -= (first - incr);
41001e04c3fSmrg            }
41101e04c3fSmrg         }
41201e04c3fSmrg         break;
41301e04c3fSmrg      }
41401e04c3fSmrg   }
41501e04c3fSmrg
41601e04c3fSmrg   if (copy->dstprim_nr)
41701e04c3fSmrg      flush(copy);
41801e04c3fSmrg}
41901e04c3fSmrg
42001e04c3fSmrg
42101e04c3fSmrgstatic void
42201e04c3fSmrgreplay_init(struct copy_context *copy)
42301e04c3fSmrg{
42401e04c3fSmrg   struct gl_context *ctx = copy->ctx;
42501e04c3fSmrg   GLuint i;
42601e04c3fSmrg   GLuint offset;
42701e04c3fSmrg   const GLvoid *srcptr;
42801e04c3fSmrg
42901e04c3fSmrg   /* Make a list of varying attributes and their vbo's.  Also
43001e04c3fSmrg    * calculate vertex size.
43101e04c3fSmrg    */
43201e04c3fSmrg   copy->vertex_size = 0;
43301e04c3fSmrg   for (i = 0; i < VERT_ATTRIB_MAX; i++) {
43401e04c3fSmrg      const struct tnl_vertex_array *array = &copy->array[i];
43501e04c3fSmrg      const struct gl_vertex_buffer_binding *binding = array->BufferBinding;
43601e04c3fSmrg
43701e04c3fSmrg      if (binding->Stride == 0) {
43801e04c3fSmrg         copy_vertex_array(&copy->dstarray[i], array);
43901e04c3fSmrg      }
44001e04c3fSmrg      else {
44101e04c3fSmrg         const struct gl_array_attributes *attrib = array->VertexAttrib;
44201e04c3fSmrg         struct gl_buffer_object *vbo = binding->BufferObj;
44301e04c3fSmrg         const GLubyte *ptr = _mesa_vertex_attrib_address(attrib, binding);
44401e04c3fSmrg         GLuint j = copy->nr_varying++;
44501e04c3fSmrg
44601e04c3fSmrg         copy->varying[j].attr = i;
44701e04c3fSmrg         copy->varying[j].array = &copy->array[i];
448b9abf16eSmaya         copy->varying[j].size = attrib->Format._ElementSize;
449b9abf16eSmaya         copy->vertex_size += attrib->Format._ElementSize;
45001e04c3fSmrg
4517ec681f3Smrg         if (vbo) {
4527ec681f3Smrg            if (!_mesa_bufferobj_mapped(vbo, MAP_INTERNAL)) {
4537ec681f3Smrg               ctx->Driver.MapBufferRange(ctx, 0, vbo->Size, GL_MAP_READ_BIT, vbo,
4547ec681f3Smrg                                          MAP_INTERNAL);
4557ec681f3Smrg            }
45601e04c3fSmrg
4577ec681f3Smrg            copy->varying[j].src_ptr =
4587ec681f3Smrg                  ADD_POINTERS(vbo->Mappings[MAP_INTERNAL].Pointer, ptr);
4597ec681f3Smrg         } else {
4607ec681f3Smrg            copy->varying[j].src_ptr = ptr;
4617ec681f3Smrg         }
46201e04c3fSmrg
46301e04c3fSmrg         copy->dstarray[i].VertexAttrib = &copy->varying[j].dstattribs;
46401e04c3fSmrg         copy->dstarray[i].BufferBinding = &copy->varying[j].dstbinding;
46501e04c3fSmrg      }
46601e04c3fSmrg   }
46701e04c3fSmrg
46801e04c3fSmrg   /* There must always be an index buffer.  Currently require the
46901e04c3fSmrg    * caller convert non-indexed prims to indexed.  Could alternately
47001e04c3fSmrg    * do it internally.
47101e04c3fSmrg    */
4727ec681f3Smrg   if (copy->ib->obj) {
4737ec681f3Smrg      if (!_mesa_bufferobj_mapped(copy->ib->obj, MAP_INTERNAL))
4747ec681f3Smrg         ctx->Driver.MapBufferRange(ctx, 0, copy->ib->obj->Size, GL_MAP_READ_BIT,
4757ec681f3Smrg                                    copy->ib->obj, MAP_INTERNAL);
4767ec681f3Smrg
4777ec681f3Smrg      srcptr = (const GLubyte *)
4787ec681f3Smrg         ADD_POINTERS(copy->ib->obj->Mappings[MAP_INTERNAL].Pointer,
4797ec681f3Smrg                      copy->ib->ptr);
4807ec681f3Smrg   } else
4817ec681f3Smrg      srcptr = copy->ib->ptr;
4827ec681f3Smrg
4837ec681f3Smrg   switch (copy->ib->index_size_shift) {
4847ec681f3Smrg   case 0:
48501e04c3fSmrg      copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
48601e04c3fSmrg      copy->srcelt = copy->translated_elt_buf;
48701e04c3fSmrg
48801e04c3fSmrg      for (i = 0; i < copy->ib->count; i++)
48901e04c3fSmrg         copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i];
49001e04c3fSmrg      break;
49101e04c3fSmrg
4927ec681f3Smrg   case 1:
49301e04c3fSmrg      copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
49401e04c3fSmrg      copy->srcelt = copy->translated_elt_buf;
49501e04c3fSmrg
49601e04c3fSmrg      for (i = 0; i < copy->ib->count; i++)
49701e04c3fSmrg         copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i];
49801e04c3fSmrg      break;
49901e04c3fSmrg
5007ec681f3Smrg   case 2:
50101e04c3fSmrg      copy->translated_elt_buf = NULL;
50201e04c3fSmrg      copy->srcelt = (const GLuint *)srcptr;
50301e04c3fSmrg      break;
50401e04c3fSmrg   }
50501e04c3fSmrg
50601e04c3fSmrg   /* Figure out the maximum allowed vertex buffer size:
50701e04c3fSmrg    */
50801e04c3fSmrg   if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) {
50901e04c3fSmrg      copy->dstbuf_size = copy->limits->max_verts;
51001e04c3fSmrg   }
51101e04c3fSmrg   else {
51201e04c3fSmrg      copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size;
51301e04c3fSmrg   }
51401e04c3fSmrg
51501e04c3fSmrg   /* Allocate an output vertex buffer:
51601e04c3fSmrg    *
51701e04c3fSmrg    * XXX:  This should be a VBO!
51801e04c3fSmrg    */
51901e04c3fSmrg   copy->dstbuf = malloc(copy->dstbuf_size * copy->vertex_size);
52001e04c3fSmrg   copy->dstptr = copy->dstbuf;
52101e04c3fSmrg
52201e04c3fSmrg   /* Setup new vertex arrays to point into the output buffer:
52301e04c3fSmrg    */
52401e04c3fSmrg   for (offset = 0, i = 0; i < copy->nr_varying; i++) {
52501e04c3fSmrg      const struct tnl_vertex_array *src = copy->varying[i].array;
52601e04c3fSmrg      const struct gl_array_attributes *srcattr = src->VertexAttrib;
52701e04c3fSmrg      struct tnl_vertex_array *dst = &copy->dstarray[copy->varying[i].attr];
52801e04c3fSmrg      struct gl_vertex_buffer_binding *dstbind = &copy->varying[i].dstbinding;
52901e04c3fSmrg      struct gl_array_attributes *dstattr = &copy->varying[i].dstattribs;
53001e04c3fSmrg
531b9abf16eSmaya      dstattr->Format = srcattr->Format;
53201e04c3fSmrg      dstattr->Ptr = copy->dstbuf + offset;
533b9abf16eSmaya      dstbind->Stride = copy->vertex_size;
5347ec681f3Smrg      dstbind->BufferObj = NULL;
53501e04c3fSmrg      dst->BufferBinding = dstbind;
53601e04c3fSmrg      dst->VertexAttrib = dstattr;
53701e04c3fSmrg
53801e04c3fSmrg      offset += copy->varying[i].size;
53901e04c3fSmrg   }
54001e04c3fSmrg
54101e04c3fSmrg   /* Allocate an output element list:
54201e04c3fSmrg    */
54301e04c3fSmrg   copy->dstelt_size = MIN2(65536, copy->ib->count * 2 + 3);
54401e04c3fSmrg   copy->dstelt_size = MIN2(copy->dstelt_size, copy->limits->max_indices);
54501e04c3fSmrg   copy->dstelt = malloc(sizeof(GLuint) * copy->dstelt_size);
54601e04c3fSmrg   copy->dstelt_nr = 0;
54701e04c3fSmrg
54801e04c3fSmrg   /* Setup the new index buffer to point to the allocated element
54901e04c3fSmrg    * list:
55001e04c3fSmrg    */
55101e04c3fSmrg   copy->dstib.count = 0;        /* duplicates dstelt_nr */
5527ec681f3Smrg   copy->dstib.index_size_shift = 2;
5537ec681f3Smrg   copy->dstib.obj = NULL;
55401e04c3fSmrg   copy->dstib.ptr = copy->dstelt;
55501e04c3fSmrg}
55601e04c3fSmrg
55701e04c3fSmrg
55801e04c3fSmrg/**
55901e04c3fSmrg * Free up everything allocated during split/replay.
56001e04c3fSmrg */
56101e04c3fSmrgstatic void
56201e04c3fSmrgreplay_finish(struct copy_context *copy)
56301e04c3fSmrg{
56401e04c3fSmrg   struct gl_context *ctx = copy->ctx;
56501e04c3fSmrg   GLuint i;
56601e04c3fSmrg
56701e04c3fSmrg   /* Free our vertex and index buffers */
56801e04c3fSmrg   free(copy->translated_elt_buf);
56901e04c3fSmrg   free(copy->dstbuf);
57001e04c3fSmrg   free(copy->dstelt);
57101e04c3fSmrg
57201e04c3fSmrg   /* Unmap VBO's */
57301e04c3fSmrg   for (i = 0; i < copy->nr_varying; i++) {
57401e04c3fSmrg      struct gl_buffer_object *vbo =
57501e04c3fSmrg         copy->varying[i].array->BufferBinding->BufferObj;
5767ec681f3Smrg      if (vbo && _mesa_bufferobj_mapped(vbo, MAP_INTERNAL))
57701e04c3fSmrg         ctx->Driver.UnmapBuffer(ctx, vbo, MAP_INTERNAL);
57801e04c3fSmrg   }
57901e04c3fSmrg
58001e04c3fSmrg   /* Unmap index buffer */
5817ec681f3Smrg   if (copy->ib->obj &&
58201e04c3fSmrg       _mesa_bufferobj_mapped(copy->ib->obj, MAP_INTERNAL)) {
58301e04c3fSmrg      ctx->Driver.UnmapBuffer(ctx, copy->ib->obj, MAP_INTERNAL);
58401e04c3fSmrg   }
58501e04c3fSmrg}
58601e04c3fSmrg
58701e04c3fSmrg
58801e04c3fSmrg/**
58901e04c3fSmrg * Split VBO into smaller pieces, draw the pieces.
59001e04c3fSmrg */
59101e04c3fSmrgvoid
59201e04c3fSmrg_tnl_split_copy(struct gl_context *ctx,
59301e04c3fSmrg                const struct tnl_vertex_array *arrays,
59401e04c3fSmrg                const struct _mesa_prim *prim,
59501e04c3fSmrg                GLuint nr_prims,
59601e04c3fSmrg                const struct _mesa_index_buffer *ib,
59701e04c3fSmrg                tnl_draw_func draw,
59801e04c3fSmrg                const struct split_limits *limits)
59901e04c3fSmrg{
60001e04c3fSmrg   struct copy_context copy;
60101e04c3fSmrg   GLuint i, this_nr_prims;
60201e04c3fSmrg
60301e04c3fSmrg   for (i = 0; i < nr_prims;) {
60401e04c3fSmrg      /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices
60501e04c3fSmrg       * will rebase the elements to the basevertex, and we'll only
60601e04c3fSmrg       * emit strings of prims with the same basevertex in one draw call.
60701e04c3fSmrg       */
60801e04c3fSmrg      for (this_nr_prims = 1; i + this_nr_prims < nr_prims;
60901e04c3fSmrg           this_nr_prims++) {
61001e04c3fSmrg         if (prim[i].basevertex != prim[i + this_nr_prims].basevertex)
61101e04c3fSmrg            break;
61201e04c3fSmrg      }
61301e04c3fSmrg
61401e04c3fSmrg      memset(&copy, 0, sizeof(copy));
61501e04c3fSmrg
61601e04c3fSmrg      /* Require indexed primitives:
61701e04c3fSmrg       */
61801e04c3fSmrg      assert(ib);
61901e04c3fSmrg
62001e04c3fSmrg      copy.ctx = ctx;
62101e04c3fSmrg      copy.array = arrays;
62201e04c3fSmrg      copy.prim = &prim[i];
62301e04c3fSmrg      copy.nr_prims = this_nr_prims;
62401e04c3fSmrg      copy.ib = ib;
62501e04c3fSmrg      copy.draw = draw;
62601e04c3fSmrg      copy.limits = limits;
62701e04c3fSmrg
62801e04c3fSmrg      /* Clear the vertex cache:
62901e04c3fSmrg       */
63001e04c3fSmrg      for (i = 0; i < ELT_TABLE_SIZE; i++)
63101e04c3fSmrg         copy.vert_cache[i].in = ~0;
63201e04c3fSmrg
63301e04c3fSmrg      replay_init(&copy);
63401e04c3fSmrg      replay_elts(&copy);
63501e04c3fSmrg      replay_finish(&copy);
63601e04c3fSmrg   }
63701e04c3fSmrg}
638