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