1b8e80941Smrg
2b8e80941Smrg/*
3b8e80941Smrg * Mesa 3-D graphics library
4b8e80941Smrg *
5b8e80941Smrg * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
6b8e80941Smrg *
7b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
8b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
9b8e80941Smrg * to deal in the Software without restriction, including without limitation
10b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
12b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
13b8e80941Smrg *
14b8e80941Smrg * The above copyright notice and this permission notice shall be included
15b8e80941Smrg * in all copies or substantial portions of the Software.
16b8e80941Smrg *
17b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18b8e80941Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21b8e80941Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22b8e80941Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23b8e80941Smrg * OTHER DEALINGS IN THE SOFTWARE.
24b8e80941Smrg *
25b8e80941Smrg * Authors:
26b8e80941Smrg *    Keith Whitwell <keithw@vmware.com>
27b8e80941Smrg */
28b8e80941Smrg
29b8e80941Smrg/* Split indexed primitives with per-vertex copying.
30b8e80941Smrg */
31b8e80941Smrg
32b8e80941Smrg#include <stdio.h>
33b8e80941Smrg
34b8e80941Smrg#include "main/glheader.h"
35b8e80941Smrg#include "main/bufferobj.h"
36b8e80941Smrg#include "main/imports.h"
37b8e80941Smrg#include "main/glformats.h"
38b8e80941Smrg#include "main/macros.h"
39b8e80941Smrg#include "main/mtypes.h"
40b8e80941Smrg#include "main/varray.h"
41b8e80941Smrg#include "vbo/vbo.h"
42b8e80941Smrg
43b8e80941Smrg#include "t_split.h"
44b8e80941Smrg#include "tnl.h"
45b8e80941Smrg
46b8e80941Smrg
47b8e80941Smrg#define ELT_TABLE_SIZE 16
48b8e80941Smrg
49b8e80941Smrg/**
50b8e80941Smrg * Used for vertex-level splitting of indexed buffers.  Note that
51b8e80941Smrg * non-indexed primitives may be converted to indexed in some cases
52b8e80941Smrg * (eg loops, fans) in order to use this splitting path.
53b8e80941Smrg */
54b8e80941Smrgstruct copy_context {
55b8e80941Smrg   struct gl_context *ctx;
56b8e80941Smrg   const struct tnl_vertex_array *array;
57b8e80941Smrg   const struct _mesa_prim *prim;
58b8e80941Smrg   GLuint nr_prims;
59b8e80941Smrg   const struct _mesa_index_buffer *ib;
60b8e80941Smrg   tnl_draw_func draw;
61b8e80941Smrg
62b8e80941Smrg   const struct split_limits *limits;
63b8e80941Smrg
64b8e80941Smrg   struct {
65b8e80941Smrg      GLuint attr;
66b8e80941Smrg      GLuint size;
67b8e80941Smrg      const struct tnl_vertex_array *array;
68b8e80941Smrg      const GLubyte *src_ptr;
69b8e80941Smrg
70b8e80941Smrg      struct gl_vertex_buffer_binding dstbinding;
71b8e80941Smrg      struct gl_array_attributes dstattribs;
72b8e80941Smrg
73b8e80941Smrg   } varying[VERT_ATTRIB_MAX];
74b8e80941Smrg   GLuint nr_varying;
75b8e80941Smrg
76b8e80941Smrg   struct tnl_vertex_array dstarray[VERT_ATTRIB_MAX];
77b8e80941Smrg   struct _mesa_index_buffer dstib;
78b8e80941Smrg
79b8e80941Smrg   GLuint *translated_elt_buf;
80b8e80941Smrg   const GLuint *srcelt;
81b8e80941Smrg
82b8e80941Smrg   /** A baby hash table to avoid re-emitting (some) duplicate
83b8e80941Smrg    * vertices when splitting indexed primitives.
84b8e80941Smrg    */
85b8e80941Smrg   struct {
86b8e80941Smrg      GLuint in;
87b8e80941Smrg      GLuint out;
88b8e80941Smrg   } vert_cache[ELT_TABLE_SIZE];
89b8e80941Smrg
90b8e80941Smrg   GLuint vertex_size;
91b8e80941Smrg   GLubyte *dstbuf;
92b8e80941Smrg   GLubyte *dstptr;     /**< dstptr == dstbuf + dstelt_max * vertsize */
93b8e80941Smrg   GLuint dstbuf_size;  /**< in vertices */
94b8e80941Smrg   GLuint dstbuf_nr;    /**< count of emitted vertices, also the largest value
95b8e80941Smrg                         * in dstelt.  Our MaxIndex.
96b8e80941Smrg                         */
97b8e80941Smrg
98b8e80941Smrg   GLuint *dstelt;
99b8e80941Smrg   GLuint dstelt_nr;
100b8e80941Smrg   GLuint dstelt_size;
101b8e80941Smrg
102b8e80941Smrg#define MAX_PRIM 32
103b8e80941Smrg   struct _mesa_prim dstprim[MAX_PRIM];
104b8e80941Smrg   GLuint dstprim_nr;
105b8e80941Smrg};
106b8e80941Smrg
107b8e80941Smrg
108b8e80941Smrg/**
109b8e80941Smrg * Shallow copy one vertex array to another.
110b8e80941Smrg */
111b8e80941Smrgstatic inline void
112b8e80941Smrgcopy_vertex_array(struct tnl_vertex_array *dst,
113b8e80941Smrg                  const struct tnl_vertex_array *src)
114b8e80941Smrg{
115b8e80941Smrg   dst->VertexAttrib = src->VertexAttrib;
116b8e80941Smrg   dst->BufferBinding = src->BufferBinding;
117b8e80941Smrg}
118b8e80941Smrg
119b8e80941Smrg
120b8e80941Smrg/**
121b8e80941Smrg * Starts returning true slightly before the buffer fills, to ensure
122b8e80941Smrg * that there is sufficient room for any remaining vertices to finish
123b8e80941Smrg * off the prim:
124b8e80941Smrg */
125b8e80941Smrgstatic GLboolean
126b8e80941Smrgcheck_flush(struct copy_context *copy)
127b8e80941Smrg{
128b8e80941Smrg   GLenum mode = copy->dstprim[copy->dstprim_nr].mode;
129b8e80941Smrg
130b8e80941Smrg   if (GL_TRIANGLE_STRIP == mode &&
131b8e80941Smrg       copy->dstelt_nr & 1) { /* see bug9962 */
132b8e80941Smrg       return GL_FALSE;
133b8e80941Smrg   }
134b8e80941Smrg
135b8e80941Smrg   if (copy->dstbuf_nr + 4 > copy->dstbuf_size)
136b8e80941Smrg      return GL_TRUE;
137b8e80941Smrg
138b8e80941Smrg   if (copy->dstelt_nr + 4 > copy->dstelt_size)
139b8e80941Smrg      return GL_TRUE;
140b8e80941Smrg
141b8e80941Smrg   return GL_FALSE;
142b8e80941Smrg}
143b8e80941Smrg
144b8e80941Smrg
145b8e80941Smrg/**
146b8e80941Smrg * Dump the parameters/info for a vbo->draw() call.
147b8e80941Smrg */
148b8e80941Smrgstatic void
149b8e80941Smrgdump_draw_info(struct gl_context *ctx,
150b8e80941Smrg               const struct tnl_vertex_array *arrays,
151b8e80941Smrg               const struct _mesa_prim *prims,
152b8e80941Smrg               GLuint nr_prims,
153b8e80941Smrg               const struct _mesa_index_buffer *ib,
154b8e80941Smrg               GLuint min_index,
155b8e80941Smrg               GLuint max_index)
156b8e80941Smrg{
157b8e80941Smrg   GLuint i, j;
158b8e80941Smrg
159b8e80941Smrg   printf("VBO Draw:\n");
160b8e80941Smrg   for (i = 0; i < nr_prims; i++) {
161b8e80941Smrg      printf("Prim %u of %u\n", i, nr_prims);
162b8e80941Smrg      printf("  Prim mode 0x%x\n", prims[i].mode);
163b8e80941Smrg      printf("  IB: %p\n", (void*) ib);
164b8e80941Smrg      for (j = 0; j < VERT_ATTRIB_MAX; j++) {
165b8e80941Smrg         const struct tnl_vertex_array *array = &arrays[j];
166b8e80941Smrg         const struct gl_vertex_buffer_binding *binding
167b8e80941Smrg            = array->BufferBinding;
168b8e80941Smrg         const struct gl_array_attributes *attrib = array->VertexAttrib;
169b8e80941Smrg         const GLubyte *ptr = _mesa_vertex_attrib_address(attrib, binding);
170b8e80941Smrg         printf("    array %d at %p:\n", j, (void*) &arrays[j]);
171b8e80941Smrg         printf("      ptr %p, size %d, type 0x%x, stride %d\n",
172b8e80941Smrg                ptr, attrib->Format.Size, attrib->Format.Type, binding->Stride);
173b8e80941Smrg         if (0) {
174b8e80941Smrg            GLint k = prims[i].start + prims[i].count - 1;
175b8e80941Smrg            GLfloat *last = (GLfloat *) (ptr + binding->Stride * k);
176b8e80941Smrg            printf("        last: %f %f %f\n",
177b8e80941Smrg                   last[0], last[1], last[2]);
178b8e80941Smrg         }
179b8e80941Smrg      }
180b8e80941Smrg   }
181b8e80941Smrg}
182b8e80941Smrg
183b8e80941Smrg
184b8e80941Smrgstatic void
185b8e80941Smrgflush(struct copy_context *copy)
186b8e80941Smrg{
187b8e80941Smrg   struct gl_context *ctx = copy->ctx;
188b8e80941Smrg   GLuint i;
189b8e80941Smrg
190b8e80941Smrg   /* Set some counters:
191b8e80941Smrg    */
192b8e80941Smrg   copy->dstib.count = copy->dstelt_nr;
193b8e80941Smrg
194b8e80941Smrg#if 0
195b8e80941Smrg   dump_draw_info(copy->ctx,
196b8e80941Smrg                  copy->dstarray,
197b8e80941Smrg                  copy->dstprim,
198b8e80941Smrg                  copy->dstprim_nr,
199b8e80941Smrg                  &copy->dstib,
200b8e80941Smrg                  0,
201b8e80941Smrg                  copy->dstbuf_nr);
202b8e80941Smrg#else
203b8e80941Smrg   (void) dump_draw_info;
204b8e80941Smrg#endif
205b8e80941Smrg
206b8e80941Smrg   copy->draw(ctx,
207b8e80941Smrg              copy->dstarray,
208b8e80941Smrg              copy->dstprim,
209b8e80941Smrg              copy->dstprim_nr,
210b8e80941Smrg              &copy->dstib,
211b8e80941Smrg              GL_TRUE,
212b8e80941Smrg              0,
213b8e80941Smrg              copy->dstbuf_nr - 1,
214b8e80941Smrg              NULL, 0, NULL);
215b8e80941Smrg
216b8e80941Smrg   /* Reset all pointers:
217b8e80941Smrg    */
218b8e80941Smrg   copy->dstprim_nr = 0;
219b8e80941Smrg   copy->dstelt_nr = 0;
220b8e80941Smrg   copy->dstbuf_nr = 0;
221b8e80941Smrg   copy->dstptr = copy->dstbuf;
222b8e80941Smrg
223b8e80941Smrg   /* Clear the vertex cache:
224b8e80941Smrg    */
225b8e80941Smrg   for (i = 0; i < ELT_TABLE_SIZE; i++)
226b8e80941Smrg      copy->vert_cache[i].in = ~0;
227b8e80941Smrg}
228b8e80941Smrg
229b8e80941Smrg
230b8e80941Smrg/**
231b8e80941Smrg * Called at begin of each primitive during replay.
232b8e80941Smrg */
233b8e80941Smrgstatic void
234b8e80941Smrgbegin(struct copy_context *copy, GLenum mode, GLboolean begin_flag)
235b8e80941Smrg{
236b8e80941Smrg   struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
237b8e80941Smrg
238b8e80941Smrg   prim->mode = mode;
239b8e80941Smrg   prim->begin = begin_flag;
240b8e80941Smrg   prim->num_instances = 1;
241b8e80941Smrg}
242b8e80941Smrg
243b8e80941Smrg
244b8e80941Smrg/**
245b8e80941Smrg * Use a hashtable to attempt to identify recently-emitted vertices
246b8e80941Smrg * and avoid re-emitting them.
247b8e80941Smrg */
248b8e80941Smrgstatic GLuint
249b8e80941Smrgelt(struct copy_context *copy, GLuint elt_idx)
250b8e80941Smrg{
251b8e80941Smrg   GLuint elt = copy->srcelt[elt_idx] + copy->prim->basevertex;
252b8e80941Smrg   GLuint slot = elt & (ELT_TABLE_SIZE-1);
253b8e80941Smrg
254b8e80941Smrg   /* Look up the incoming element in the vertex cache.  Re-emit if
255b8e80941Smrg    * necessary.
256b8e80941Smrg    */
257b8e80941Smrg   if (copy->vert_cache[slot].in != elt) {
258b8e80941Smrg      GLubyte *csr = copy->dstptr;
259b8e80941Smrg      GLuint i;
260b8e80941Smrg
261b8e80941Smrg      for (i = 0; i < copy->nr_varying; i++) {
262b8e80941Smrg         const struct tnl_vertex_array *srcarray = copy->varying[i].array;
263b8e80941Smrg         const struct gl_vertex_buffer_binding* srcbinding
264b8e80941Smrg            = srcarray->BufferBinding;
265b8e80941Smrg         const GLubyte *srcptr
266b8e80941Smrg            = copy->varying[i].src_ptr + elt * srcbinding->Stride;
267b8e80941Smrg
268b8e80941Smrg         memcpy(csr, srcptr, copy->varying[i].size);
269b8e80941Smrg         csr += copy->varying[i].size;
270b8e80941Smrg
271b8e80941Smrg#ifdef NAN_CHECK
272b8e80941Smrg         if (srcarray->Format.Type == GL_FLOAT) {
273b8e80941Smrg            GLuint k;
274b8e80941Smrg            GLfloat *f = (GLfloat *) srcptr;
275b8e80941Smrg            for (k = 0; k < srcarray->Size; k++) {
276b8e80941Smrg               assert(!IS_INF_OR_NAN(f[k]));
277b8e80941Smrg               assert(f[k] <= 1.0e20 && f[k] >= -1.0e20);
278b8e80941Smrg            }
279b8e80941Smrg         }
280b8e80941Smrg#endif
281b8e80941Smrg
282b8e80941Smrg         if (0) {
283b8e80941Smrg            const GLuint *f = (const GLuint *)srcptr;
284b8e80941Smrg            GLuint j;
285b8e80941Smrg            printf("  varying %d: ", i);
286b8e80941Smrg            for (j = 0; j < copy->varying[i].size / 4; j++)
287b8e80941Smrg               printf("%x ", f[j]);
288b8e80941Smrg            printf("\n");
289b8e80941Smrg         }
290b8e80941Smrg      }
291b8e80941Smrg
292b8e80941Smrg      copy->vert_cache[slot].in = elt;
293b8e80941Smrg      copy->vert_cache[slot].out = copy->dstbuf_nr++;
294b8e80941Smrg      copy->dstptr += copy->vertex_size;
295b8e80941Smrg
296b8e80941Smrg      assert(csr == copy->dstptr);
297b8e80941Smrg      assert(copy->dstptr == (copy->dstbuf +
298b8e80941Smrg                              copy->dstbuf_nr * copy->vertex_size));
299b8e80941Smrg   }
300b8e80941Smrg
301b8e80941Smrg   copy->dstelt[copy->dstelt_nr++] = copy->vert_cache[slot].out;
302b8e80941Smrg   return check_flush(copy);
303b8e80941Smrg}
304b8e80941Smrg
305b8e80941Smrg
306b8e80941Smrg/**
307b8e80941Smrg * Called at end of each primitive during replay.
308b8e80941Smrg */
309b8e80941Smrgstatic void
310b8e80941Smrgend(struct copy_context *copy, GLboolean end_flag)
311b8e80941Smrg{
312b8e80941Smrg   struct _mesa_prim *prim = &copy->dstprim[copy->dstprim_nr];
313b8e80941Smrg
314b8e80941Smrg   prim->end = end_flag;
315b8e80941Smrg   prim->count = copy->dstelt_nr - prim->start;
316b8e80941Smrg
317b8e80941Smrg   if (++copy->dstprim_nr == MAX_PRIM || check_flush(copy)) {
318b8e80941Smrg      flush(copy);
319b8e80941Smrg   }
320b8e80941Smrg}
321b8e80941Smrg
322b8e80941Smrg
323b8e80941Smrgstatic void
324b8e80941Smrgreplay_elts(struct copy_context *copy)
325b8e80941Smrg{
326b8e80941Smrg   GLuint i, j, k;
327b8e80941Smrg   GLboolean split;
328b8e80941Smrg
329b8e80941Smrg   for (i = 0; i < copy->nr_prims; i++) {
330b8e80941Smrg      const struct _mesa_prim *prim = &copy->prim[i];
331b8e80941Smrg      const GLuint start = prim->start;
332b8e80941Smrg      GLuint first, incr;
333b8e80941Smrg
334b8e80941Smrg      switch (prim->mode) {
335b8e80941Smrg      case GL_LINE_LOOP:
336b8e80941Smrg         /* Convert to linestrip and emit the final vertex explicitly,
337b8e80941Smrg          * but only in the resultant strip that requires it.
338b8e80941Smrg          */
339b8e80941Smrg         j = 0;
340b8e80941Smrg         while (j != prim->count) {
341b8e80941Smrg            begin(copy, GL_LINE_STRIP, prim->begin && j == 0);
342b8e80941Smrg
343b8e80941Smrg            for (split = GL_FALSE; j != prim->count && !split; j++)
344b8e80941Smrg               split = elt(copy, start + j);
345b8e80941Smrg
346b8e80941Smrg            if (j == prim->count) {
347b8e80941Smrg               /* Done, emit final line.  Split doesn't matter as
348b8e80941Smrg                * it is always raised a bit early so we can emit
349b8e80941Smrg                * the last verts if necessary!
350b8e80941Smrg                */
351b8e80941Smrg               if (prim->end)
352b8e80941Smrg                  (void)elt(copy, start + 0);
353b8e80941Smrg
354b8e80941Smrg               end(copy, prim->end);
355b8e80941Smrg            }
356b8e80941Smrg            else {
357b8e80941Smrg               /* Wrap
358b8e80941Smrg                */
359b8e80941Smrg               assert(split);
360b8e80941Smrg               end(copy, 0);
361b8e80941Smrg               j--;
362b8e80941Smrg            }
363b8e80941Smrg         }
364b8e80941Smrg         break;
365b8e80941Smrg
366b8e80941Smrg      case GL_TRIANGLE_FAN:
367b8e80941Smrg      case GL_POLYGON:
368b8e80941Smrg         j = 2;
369b8e80941Smrg         while (j != prim->count) {
370b8e80941Smrg            begin(copy, prim->mode, prim->begin && j == 0);
371b8e80941Smrg
372b8e80941Smrg            split = elt(copy, start+0);
373b8e80941Smrg            assert(!split);
374b8e80941Smrg
375b8e80941Smrg            split = elt(copy, start+j-1);
376b8e80941Smrg            assert(!split);
377b8e80941Smrg
378b8e80941Smrg            for (; j != prim->count && !split; j++)
379b8e80941Smrg               split = elt(copy, start+j);
380b8e80941Smrg
381b8e80941Smrg            end(copy, prim->end && j == prim->count);
382b8e80941Smrg
383b8e80941Smrg            if (j != prim->count) {
384b8e80941Smrg               /* Wrapped the primitive, need to repeat some vertices:
385b8e80941Smrg                */
386b8e80941Smrg               j -= 1;
387b8e80941Smrg            }
388b8e80941Smrg         }
389b8e80941Smrg         break;
390b8e80941Smrg
391b8e80941Smrg      default:
392b8e80941Smrg         (void)_tnl_split_prim_inplace(prim->mode, &first, &incr);
393b8e80941Smrg
394b8e80941Smrg         j = 0;
395b8e80941Smrg         while (j != prim->count) {
396b8e80941Smrg
397b8e80941Smrg            begin(copy, prim->mode, prim->begin && j == 0);
398b8e80941Smrg
399b8e80941Smrg            split = 0;
400b8e80941Smrg            for (k = 0; k < first; k++, j++)
401b8e80941Smrg               split |= elt(copy, start+j);
402b8e80941Smrg
403b8e80941Smrg            assert(!split);
404b8e80941Smrg
405b8e80941Smrg            for (; j != prim->count && !split;)
406b8e80941Smrg               for (k = 0; k < incr; k++, j++)
407b8e80941Smrg                  split |= elt(copy, start+j);
408b8e80941Smrg
409b8e80941Smrg            end(copy, prim->end && j == prim->count);
410b8e80941Smrg
411b8e80941Smrg            if (j != prim->count) {
412b8e80941Smrg               /* Wrapped the primitive, need to repeat some vertices:
413b8e80941Smrg                */
414b8e80941Smrg               assert(j > first - incr);
415b8e80941Smrg               j -= (first - incr);
416b8e80941Smrg            }
417b8e80941Smrg         }
418b8e80941Smrg         break;
419b8e80941Smrg      }
420b8e80941Smrg   }
421b8e80941Smrg
422b8e80941Smrg   if (copy->dstprim_nr)
423b8e80941Smrg      flush(copy);
424b8e80941Smrg}
425b8e80941Smrg
426b8e80941Smrg
427b8e80941Smrgstatic void
428b8e80941Smrgreplay_init(struct copy_context *copy)
429b8e80941Smrg{
430b8e80941Smrg   struct gl_context *ctx = copy->ctx;
431b8e80941Smrg   GLuint i;
432b8e80941Smrg   GLuint offset;
433b8e80941Smrg   const GLvoid *srcptr;
434b8e80941Smrg
435b8e80941Smrg   /* Make a list of varying attributes and their vbo's.  Also
436b8e80941Smrg    * calculate vertex size.
437b8e80941Smrg    */
438b8e80941Smrg   copy->vertex_size = 0;
439b8e80941Smrg   for (i = 0; i < VERT_ATTRIB_MAX; i++) {
440b8e80941Smrg      const struct tnl_vertex_array *array = &copy->array[i];
441b8e80941Smrg      const struct gl_vertex_buffer_binding *binding = array->BufferBinding;
442b8e80941Smrg
443b8e80941Smrg      if (binding->Stride == 0) {
444b8e80941Smrg         copy_vertex_array(&copy->dstarray[i], array);
445b8e80941Smrg      }
446b8e80941Smrg      else {
447b8e80941Smrg         const struct gl_array_attributes *attrib = array->VertexAttrib;
448b8e80941Smrg         struct gl_buffer_object *vbo = binding->BufferObj;
449b8e80941Smrg         const GLubyte *ptr = _mesa_vertex_attrib_address(attrib, binding);
450b8e80941Smrg         GLuint j = copy->nr_varying++;
451b8e80941Smrg
452b8e80941Smrg         copy->varying[j].attr = i;
453b8e80941Smrg         copy->varying[j].array = &copy->array[i];
454b8e80941Smrg         copy->varying[j].size = attrib->Format._ElementSize;
455b8e80941Smrg         copy->vertex_size += attrib->Format._ElementSize;
456b8e80941Smrg
457b8e80941Smrg         if (_mesa_is_bufferobj(vbo) &&
458b8e80941Smrg             !_mesa_bufferobj_mapped(vbo, MAP_INTERNAL))
459b8e80941Smrg            ctx->Driver.MapBufferRange(ctx, 0, vbo->Size, GL_MAP_READ_BIT, vbo,
460b8e80941Smrg                                       MAP_INTERNAL);
461b8e80941Smrg
462b8e80941Smrg         copy->varying[j].src_ptr =
463b8e80941Smrg               ADD_POINTERS(vbo->Mappings[MAP_INTERNAL].Pointer, ptr);
464b8e80941Smrg
465b8e80941Smrg         copy->dstarray[i].VertexAttrib = &copy->varying[j].dstattribs;
466b8e80941Smrg         copy->dstarray[i].BufferBinding = &copy->varying[j].dstbinding;
467b8e80941Smrg      }
468b8e80941Smrg   }
469b8e80941Smrg
470b8e80941Smrg   /* There must always be an index buffer.  Currently require the
471b8e80941Smrg    * caller convert non-indexed prims to indexed.  Could alternately
472b8e80941Smrg    * do it internally.
473b8e80941Smrg    */
474b8e80941Smrg   if (_mesa_is_bufferobj(copy->ib->obj) &&
475b8e80941Smrg       !_mesa_bufferobj_mapped(copy->ib->obj, MAP_INTERNAL))
476b8e80941Smrg      ctx->Driver.MapBufferRange(ctx, 0, copy->ib->obj->Size, GL_MAP_READ_BIT,
477b8e80941Smrg                                 copy->ib->obj, MAP_INTERNAL);
478b8e80941Smrg
479b8e80941Smrg   srcptr = (const GLubyte *)
480b8e80941Smrg            ADD_POINTERS(copy->ib->obj->Mappings[MAP_INTERNAL].Pointer,
481b8e80941Smrg                         copy->ib->ptr);
482b8e80941Smrg
483b8e80941Smrg   switch (copy->ib->index_size) {
484b8e80941Smrg   case 1:
485b8e80941Smrg      copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
486b8e80941Smrg      copy->srcelt = copy->translated_elt_buf;
487b8e80941Smrg
488b8e80941Smrg      for (i = 0; i < copy->ib->count; i++)
489b8e80941Smrg         copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i];
490b8e80941Smrg      break;
491b8e80941Smrg
492b8e80941Smrg   case 2:
493b8e80941Smrg      copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count);
494b8e80941Smrg      copy->srcelt = copy->translated_elt_buf;
495b8e80941Smrg
496b8e80941Smrg      for (i = 0; i < copy->ib->count; i++)
497b8e80941Smrg         copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i];
498b8e80941Smrg      break;
499b8e80941Smrg
500b8e80941Smrg   case 4:
501b8e80941Smrg      copy->translated_elt_buf = NULL;
502b8e80941Smrg      copy->srcelt = (const GLuint *)srcptr;
503b8e80941Smrg      break;
504b8e80941Smrg   }
505b8e80941Smrg
506b8e80941Smrg   /* Figure out the maximum allowed vertex buffer size:
507b8e80941Smrg    */
508b8e80941Smrg   if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) {
509b8e80941Smrg      copy->dstbuf_size = copy->limits->max_verts;
510b8e80941Smrg   }
511b8e80941Smrg   else {
512b8e80941Smrg      copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size;
513b8e80941Smrg   }
514b8e80941Smrg
515b8e80941Smrg   /* Allocate an output vertex buffer:
516b8e80941Smrg    *
517b8e80941Smrg    * XXX:  This should be a VBO!
518b8e80941Smrg    */
519b8e80941Smrg   copy->dstbuf = malloc(copy->dstbuf_size * copy->vertex_size);
520b8e80941Smrg   copy->dstptr = copy->dstbuf;
521b8e80941Smrg
522b8e80941Smrg   /* Setup new vertex arrays to point into the output buffer:
523b8e80941Smrg    */
524b8e80941Smrg   for (offset = 0, i = 0; i < copy->nr_varying; i++) {
525b8e80941Smrg      const struct tnl_vertex_array *src = copy->varying[i].array;
526b8e80941Smrg      const struct gl_array_attributes *srcattr = src->VertexAttrib;
527b8e80941Smrg      struct tnl_vertex_array *dst = &copy->dstarray[copy->varying[i].attr];
528b8e80941Smrg      struct gl_vertex_buffer_binding *dstbind = &copy->varying[i].dstbinding;
529b8e80941Smrg      struct gl_array_attributes *dstattr = &copy->varying[i].dstattribs;
530b8e80941Smrg
531b8e80941Smrg      dstattr->Format = srcattr->Format;
532b8e80941Smrg      dstattr->Ptr = copy->dstbuf + offset;
533b8e80941Smrg      dstbind->Stride = copy->vertex_size;
534b8e80941Smrg      dstbind->BufferObj = ctx->Shared->NullBufferObj;
535b8e80941Smrg      dst->BufferBinding = dstbind;
536b8e80941Smrg      dst->VertexAttrib = dstattr;
537b8e80941Smrg
538b8e80941Smrg      offset += copy->varying[i].size;
539b8e80941Smrg   }
540b8e80941Smrg
541b8e80941Smrg   /* Allocate an output element list:
542b8e80941Smrg    */
543b8e80941Smrg   copy->dstelt_size = MIN2(65536, copy->ib->count * 2 + 3);
544b8e80941Smrg   copy->dstelt_size = MIN2(copy->dstelt_size, copy->limits->max_indices);
545b8e80941Smrg   copy->dstelt = malloc(sizeof(GLuint) * copy->dstelt_size);
546b8e80941Smrg   copy->dstelt_nr = 0;
547b8e80941Smrg
548b8e80941Smrg   /* Setup the new index buffer to point to the allocated element
549b8e80941Smrg    * list:
550b8e80941Smrg    */
551b8e80941Smrg   copy->dstib.count = 0;        /* duplicates dstelt_nr */
552b8e80941Smrg   copy->dstib.index_size = 4;
553b8e80941Smrg   copy->dstib.obj = ctx->Shared->NullBufferObj;
554b8e80941Smrg   copy->dstib.ptr = copy->dstelt;
555b8e80941Smrg}
556b8e80941Smrg
557b8e80941Smrg
558b8e80941Smrg/**
559b8e80941Smrg * Free up everything allocated during split/replay.
560b8e80941Smrg */
561b8e80941Smrgstatic void
562b8e80941Smrgreplay_finish(struct copy_context *copy)
563b8e80941Smrg{
564b8e80941Smrg   struct gl_context *ctx = copy->ctx;
565b8e80941Smrg   GLuint i;
566b8e80941Smrg
567b8e80941Smrg   /* Free our vertex and index buffers */
568b8e80941Smrg   free(copy->translated_elt_buf);
569b8e80941Smrg   free(copy->dstbuf);
570b8e80941Smrg   free(copy->dstelt);
571b8e80941Smrg
572b8e80941Smrg   /* Unmap VBO's */
573b8e80941Smrg   for (i = 0; i < copy->nr_varying; i++) {
574b8e80941Smrg      struct gl_buffer_object *vbo =
575b8e80941Smrg         copy->varying[i].array->BufferBinding->BufferObj;
576b8e80941Smrg      if (_mesa_is_bufferobj(vbo) && _mesa_bufferobj_mapped(vbo, MAP_INTERNAL))
577b8e80941Smrg         ctx->Driver.UnmapBuffer(ctx, vbo, MAP_INTERNAL);
578b8e80941Smrg   }
579b8e80941Smrg
580b8e80941Smrg   /* Unmap index buffer */
581b8e80941Smrg   if (_mesa_is_bufferobj(copy->ib->obj) &&
582b8e80941Smrg       _mesa_bufferobj_mapped(copy->ib->obj, MAP_INTERNAL)) {
583b8e80941Smrg      ctx->Driver.UnmapBuffer(ctx, copy->ib->obj, MAP_INTERNAL);
584b8e80941Smrg   }
585b8e80941Smrg}
586b8e80941Smrg
587b8e80941Smrg
588b8e80941Smrg/**
589b8e80941Smrg * Split VBO into smaller pieces, draw the pieces.
590b8e80941Smrg */
591b8e80941Smrgvoid
592b8e80941Smrg_tnl_split_copy(struct gl_context *ctx,
593b8e80941Smrg                const struct tnl_vertex_array *arrays,
594b8e80941Smrg                const struct _mesa_prim *prim,
595b8e80941Smrg                GLuint nr_prims,
596b8e80941Smrg                const struct _mesa_index_buffer *ib,
597b8e80941Smrg                tnl_draw_func draw,
598b8e80941Smrg                const struct split_limits *limits)
599b8e80941Smrg{
600b8e80941Smrg   struct copy_context copy;
601b8e80941Smrg   GLuint i, this_nr_prims;
602b8e80941Smrg
603b8e80941Smrg   for (i = 0; i < nr_prims;) {
604b8e80941Smrg      /* Our SW TNL pipeline doesn't handle basevertex yet, so bind_indices
605b8e80941Smrg       * will rebase the elements to the basevertex, and we'll only
606b8e80941Smrg       * emit strings of prims with the same basevertex in one draw call.
607b8e80941Smrg       */
608b8e80941Smrg      for (this_nr_prims = 1; i + this_nr_prims < nr_prims;
609b8e80941Smrg           this_nr_prims++) {
610b8e80941Smrg         if (prim[i].basevertex != prim[i + this_nr_prims].basevertex)
611b8e80941Smrg            break;
612b8e80941Smrg      }
613b8e80941Smrg
614b8e80941Smrg      memset(&copy, 0, sizeof(copy));
615b8e80941Smrg
616b8e80941Smrg      /* Require indexed primitives:
617b8e80941Smrg       */
618b8e80941Smrg      assert(ib);
619b8e80941Smrg
620b8e80941Smrg      copy.ctx = ctx;
621b8e80941Smrg      copy.array = arrays;
622b8e80941Smrg      copy.prim = &prim[i];
623b8e80941Smrg      copy.nr_prims = this_nr_prims;
624b8e80941Smrg      copy.ib = ib;
625b8e80941Smrg      copy.draw = draw;
626b8e80941Smrg      copy.limits = limits;
627b8e80941Smrg
628b8e80941Smrg      /* Clear the vertex cache:
629b8e80941Smrg       */
630b8e80941Smrg      for (i = 0; i < ELT_TABLE_SIZE; i++)
631b8e80941Smrg         copy.vert_cache[i].in = ~0;
632b8e80941Smrg
633b8e80941Smrg      replay_init(&copy);
634b8e80941Smrg      replay_elts(&copy);
635b8e80941Smrg      replay_finish(&copy);
636b8e80941Smrg   }
637b8e80941Smrg}
638