Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 1
/*
2
 * Mesa 3-D graphics library
3
 *
4
 * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the "Software"),
8
 * to deal in the Software without restriction, including without limitation
9
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
 * and/or sell copies of the Software, and to permit persons to whom the
11
 * Software is furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included
14
 * in all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
 * OTHER DEALINGS IN THE SOFTWARE.
23
 *
24
 * Authors:
25
 *    Keith Whitwell 
26
 */
27
 
28
 
29
/**
30
 * \file t_dd_dmatmp.h
31
 * Template for render stages which build and emit vertices directly
32
 * to fixed-size dma buffers.  Useful for rendering strips and other
33
 * native primitives where clipping and per-vertex tweaks such as
34
 * those in t_dd_tritmp.h are not required.
35
 *
36
 * Produces code for both inline triangles and indexed triangles.
37
 * Where various primitive types are unaccelerated by hardware, the
38
 * code attempts to fallback to other primitive types (quadstrips to
39
 * tristrips, lineloops to linestrips), or to indexed vertices.
40
 */
41
 
42
#if !defined(HAVE_TRIANGLES)
43
#error "must have at least triangles to use render template"
44
#endif
45
 
46
#if !HAVE_ELTS
47
#define ELTS_VARS(buf)
48
#define ALLOC_ELTS(nr) 0
49
#define EMIT_ELT( offset, elt )
50
#define EMIT_TWO_ELTS( offset, elt0, elt1 )
51
#define INCR_ELTS( nr )
52
#define ELT_INIT(prim)
53
#define GET_CURRENT_VB_MAX_ELTS() 0
54
#define GET_SUBSEQUENT_VB_MAX_ELTS() 0
55
#define RELEASE_ELT_VERTS()
56
#define EMIT_INDEXED_VERTS( ctx, start, count )
57
#endif
58
 
59
#ifndef EMIT_TWO_ELTS
60
#define EMIT_TWO_ELTS( offset, elt0, elt1 )	\
61
do { 						\
62
   EMIT_ELT( offset, elt0 ); 			\
63
   EMIT_ELT( offset+1, elt1 ); 			\
64
} while (0)
65
#endif
66
 
67
 
68
/**********************************************************************/
69
/*                  Render whole begin/end objects                    */
70
/**********************************************************************/
71
 
72
 
73
 
74
 
75
#if (HAVE_ELTS)
76
static void *TAG(emit_elts)( struct gl_context *ctx, GLuint *elts, GLuint nr,
77
			     void *buf)
78
{
79
   GLint i;
80
   LOCAL_VARS;
81
   ELTS_VARS(buf);
82
 
83
   for ( i = 0 ; i+1 < nr ; i+=2, elts += 2 ) {
84
      EMIT_TWO_ELTS( 0, elts[0], elts[1] );
85
      INCR_ELTS( 2 );
86
   }
87
 
88
   if (i < nr) {
89
      EMIT_ELT( 0, elts[0] );
90
      INCR_ELTS( 1 );
91
   }
92
 
93
   return (void *)ELTPTR;
94
}
95
#endif
96
 
97
static __inline void *TAG(emit_verts)( struct gl_context *ctx, GLuint start,
98
				     GLuint count, void *buf )
99
{
100
   return EMIT_VERTS(ctx, start, count, buf);
101
}
102
 
103
/***********************************************************************
104
 *                    Render non-indexed primitives.
105
 ***********************************************************************/
106
 
107
static void TAG(render_points_verts)( struct gl_context *ctx,
108
				      GLuint start,
109
				      GLuint count,
110
				      GLuint flags )
111
{
112
   if (HAVE_POINTS) {
113
      LOCAL_VARS;
114
      int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
115
      int currentsz;
116
      GLuint j, nr;
117
 
118
      INIT( GL_POINTS );
119
 
120
      currentsz = GET_CURRENT_VB_MAX_VERTS();
121
      if (currentsz < 8)
122
	 currentsz = dmasz;
123
 
124
      for (j = start; j < count; j += nr ) {
125
	 nr = MIN2( currentsz, count - j );
126
	 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
127
	 currentsz = dmasz;
128
      }
129
 
130
   } else {
131
      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
132
      return;
133
   }
134
}
135
 
136
static void TAG(render_lines_verts)( struct gl_context *ctx,
137
				     GLuint start,
138
				     GLuint count,
139
				     GLuint flags )
140
{
141
   if (HAVE_LINES) {
142
      LOCAL_VARS;
143
      int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
144
      int currentsz;
145
      GLuint j, nr;
146
 
147
      INIT( GL_LINES );
148
 
149
      /* Emit whole number of lines in total and in each buffer:
150
       */
151
      count -= (count-start) & 1;
152
      currentsz = GET_CURRENT_VB_MAX_VERTS();
153
      currentsz -= currentsz & 1;
154
      dmasz -= dmasz & 1;
155
 
156
      if (currentsz < 8)
157
	 currentsz = dmasz;
158
 
159
      for (j = start; j < count; j += nr ) {
160
	 nr = MIN2( currentsz, count - j );
161
	 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
162
	 currentsz = dmasz;
163
      }
164
 
165
   } else {
166
      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
167
      return;
168
   }
169
}
170
 
171
 
172
static void TAG(render_line_strip_verts)( struct gl_context *ctx,
173
					  GLuint start,
174
					  GLuint count,
175
					  GLuint flags )
176
{
177
   if (HAVE_LINE_STRIPS) {
178
      LOCAL_VARS;
179
      int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
180
      int currentsz;
181
      GLuint j, nr;
182
 
183
      INIT( GL_LINE_STRIP );
184
 
185
      currentsz = GET_CURRENT_VB_MAX_VERTS();
186
      if (currentsz < 8)
187
	 currentsz = dmasz;
188
 
189
      for (j = start; j + 1 < count; j += nr - 1 ) {
190
	 nr = MIN2( currentsz, count - j );
191
	 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
192
	 currentsz = dmasz;
193
      }
194
 
195
      FLUSH();
196
 
197
   } else {
198
      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
199
      return;
200
   }
201
}
202
 
203
 
204
static void TAG(render_line_loop_verts)( struct gl_context *ctx,
205
					 GLuint start,
206
					 GLuint count,
207
					 GLuint flags )
208
{
209
   if (HAVE_LINE_STRIPS) {
210
      LOCAL_VARS;
211
      int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
212
      int currentsz;
213
      GLuint j, nr;
214
 
215
      INIT( GL_LINE_STRIP );
216
 
217
      if (flags & PRIM_BEGIN)
218
	 j = start;
219
      else
220
	 j = start + 1;
221
 
222
      /* Ensure last vertex won't wrap buffers:
223
       */
224
      currentsz = GET_CURRENT_VB_MAX_VERTS();
225
      currentsz--;
226
      dmasz--;
227
 
228
      if (currentsz < 8) {
229
	 currentsz = dmasz;
230
      }
231
 
232
      if (j + 1 < count) {
233
	 for ( ; j + 1 < count; j += nr - 1 ) {
234
	    nr = MIN2( currentsz, count - j );
235
 
236
	    if (j + nr >= count &&
237
		start < count - 1 &&
238
		(flags & PRIM_END))
239
	    {
240
	       void *tmp;
241
	       tmp = ALLOC_VERTS(nr+1);
242
	       tmp = TAG(emit_verts)( ctx, j, nr, tmp );
243
	       tmp = TAG(emit_verts)( ctx, start, 1, tmp );
244
	       (void) tmp;
245
	    }
246
	    else {
247
	       TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
248
	       currentsz = dmasz;
249
	    }
250
	 }
251
 
252
      }
253
      else if (start + 1 < count && (flags & PRIM_END)) {
254
	 void *tmp;
255
	 tmp = ALLOC_VERTS(2);
256
	 tmp = TAG(emit_verts)( ctx, start+1, 1, tmp );
257
	 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
258
	 (void) tmp;
259
      }
260
 
261
      FLUSH();
262
 
263
   } else {
264
      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
265
      return;
266
   }
267
}
268
 
269
 
270
static void TAG(render_triangles_verts)( struct gl_context *ctx,
271
					 GLuint start,
272
					 GLuint count,
273
					 GLuint flags )
274
{
275
   LOCAL_VARS;
276
   int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS()/3) * 3;
277
   int currentsz;
278
   GLuint j, nr;
279
 
280
   INIT(GL_TRIANGLES);
281
 
282
   currentsz = (GET_CURRENT_VB_MAX_VERTS()/3) * 3;
283
 
284
   /* Emit whole number of tris in total.  dmasz is already a multiple
285
    * of 3.
286
    */
287
   count -= (count-start)%3;
288
 
289
   if (currentsz < 8)
290
      currentsz = dmasz;
291
 
292
   for (j = start; j < count; j += nr) {
293
      nr = MIN2( currentsz, count - j );
294
      TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
295
      currentsz = dmasz;
296
   }
297
}
298
 
299
 
300
 
301
static void TAG(render_tri_strip_verts)( struct gl_context *ctx,
302
					 GLuint start,
303
					 GLuint count,
304
					 GLuint flags )
305
{
306
   if (HAVE_TRI_STRIPS) {
307
      LOCAL_VARS;
308
      GLuint j, nr;
309
      int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
310
      int currentsz;
311
 
312
      INIT(GL_TRIANGLE_STRIP);
313
 
314
      currentsz = GET_CURRENT_VB_MAX_VERTS();
315
 
316
      if (currentsz < 8) {
317
	 currentsz = dmasz;
318
      }
319
 
320
      /* From here on emit even numbers of tris when wrapping over buffers:
321
       */
322
      dmasz -= (dmasz & 1);
323
      currentsz -= (currentsz & 1);
324
 
325
      for (j = start ; j + 2 < count; j += nr - 2 ) {
326
	 nr = MIN2( currentsz, count - j );
327
	 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
328
	 currentsz = dmasz;
329
      }
330
 
331
      FLUSH();
332
 
333
   } else {
334
      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
335
      return;
336
   }
337
}
338
 
339
static void TAG(render_tri_fan_verts)( struct gl_context *ctx,
340
				       GLuint start,
341
				       GLuint count,
342
				       GLuint flags )
343
{
344
   if (HAVE_TRI_FANS) {
345
      LOCAL_VARS;
346
      GLuint j, nr;
347
      int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
348
      int currentsz;
349
 
350
      INIT(GL_TRIANGLE_FAN);
351
 
352
      currentsz = GET_CURRENT_VB_MAX_VERTS();
353
      if (currentsz < 8) {
354
	 currentsz = dmasz;
355
      }
356
 
357
      for (j = start + 1 ; j + 1 < count; j += nr - 2 ) {
358
	 void *tmp;
359
	 nr = MIN2( currentsz, count - j + 1 );
360
	 tmp = ALLOC_VERTS( nr );
361
	 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
362
	 tmp = TAG(emit_verts)( ctx, j, nr - 1, tmp );
363
	 (void) tmp;
364
	 currentsz = dmasz;
365
      }
366
 
367
      FLUSH();
368
   }
369
   else {
370
      /* Could write code to emit these as indexed vertices (for the
371
       * g400, for instance).
372
       */
373
      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
374
      return;
375
   }
376
}
377
 
378
 
379
static void TAG(render_poly_verts)( struct gl_context *ctx,
380
				    GLuint start,
381
				    GLuint count,
382
				    GLuint flags )
383
{
384
   if (HAVE_POLYGONS) {
385
      LOCAL_VARS;
386
      GLuint j, nr;
387
      int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
388
      int currentsz;
389
 
390
      INIT(GL_POLYGON);
391
 
392
      currentsz = GET_CURRENT_VB_MAX_VERTS();
393
      if (currentsz < 8) {
394
	 currentsz = dmasz;
395
      }
396
 
397
      for (j = start + 1 ; j + 1 < count ; j += nr - 2 ) {
398
	 void *tmp;
399
	 nr = MIN2( currentsz, count - j + 1 );
400
	 tmp = ALLOC_VERTS( nr );
401
	 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
402
	 tmp = TAG(emit_verts)( ctx, j, nr - 1, tmp );
403
	 (void) tmp;
404
	 currentsz = dmasz;
405
      }
406
 
407
      FLUSH();
408
   }
409
   else if (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH) {
410
      TAG(render_tri_fan_verts)( ctx, start, count, flags );
411
   } else {
412
      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
413
      return;
414
   }
415
}
416
 
417
static void TAG(render_quad_strip_verts)( struct gl_context *ctx,
418
					  GLuint start,
419
					  GLuint count,
420
					  GLuint flags )
421
{
422
   GLuint j, nr;
423
 
424
   if (HAVE_QUAD_STRIPS) {
425
      LOCAL_VARS;
426
      GLuint j, nr;
427
      int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
428
      int currentsz;
429
 
430
      INIT(GL_QUAD_STRIP);
431
 
432
      currentsz = GET_CURRENT_VB_MAX_VERTS();
433
      if (currentsz < 8) {
434
	 currentsz = dmasz;
435
      }
436
 
437
      dmasz -= (dmasz & 2);
438
      currentsz -= (currentsz & 2);
439
 
440
      for (j = start ; j + 3 < count; j += nr - 2 ) {
441
	 nr = MIN2( currentsz, count - j );
442
	 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
443
	 currentsz = dmasz;
444
      }
445
 
446
      FLUSH();
447
 
448
   } else if (HAVE_TRI_STRIPS &&
449
	      ctx->Light.ShadeModel == GL_FLAT &&
450
	      TNL_CONTEXT(ctx)->vb.AttribPtr[_TNL_ATTRIB_COLOR0]->stride) {
451
      if (HAVE_ELTS) {
452
	 LOCAL_VARS;
453
	 int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
454
	 int currentsz;
455
	 GLuint j, nr;
456
 
457
         EMIT_INDEXED_VERTS( ctx, start, count );
458
 
459
	 /* Simulate flat-shaded quadstrips using indexed vertices:
460
	  */
461
	 ELT_INIT( GL_TRIANGLES );
462
 
463
	 currentsz = GET_CURRENT_VB_MAX_ELTS();
464
 
465
	 /* Emit whole number of quads in total, and in each buffer.
466
	  */
467
	 dmasz -= dmasz & 1;
468
	 count -= (count-start) & 1;
469
	 currentsz -= currentsz & 1;
470
 
471
	 if (currentsz < 12)
472
	    currentsz = dmasz;
473
 
474
	 currentsz = currentsz/6*2;
475
	 dmasz = dmasz/6*2;
476
 
477
	 for (j = start; j + 3 < count; j += nr - 2 ) {
478
	    nr = MIN2( currentsz, count - j );
479
	    if (nr >= 4) {
480
	       GLint quads = (nr/2)-1;
481
	       GLint i;
482
	       ELTS_VARS( ALLOC_ELTS( quads*6 ) );
483
 
484
	       for ( i = j-start ; i < j-start+quads*2 ; i+=2 ) {
485
		  EMIT_TWO_ELTS( 0, (i+0), (i+1) );
486
		  EMIT_TWO_ELTS( 2, (i+2), (i+1) );
487
		  EMIT_TWO_ELTS( 4, (i+3), (i+2) );
488
		  INCR_ELTS( 6 );
489
	       }
490
 
491
	       FLUSH();
492
	    }
493
	    currentsz = dmasz;
494
	 }
495
 
496
	 RELEASE_ELT_VERTS();
497
	 FLUSH();
498
      }
499
      else {
500
	 /* Vertices won't fit in a single buffer or elts not
501
	  * available - should never happen.
502
	  */
503
	 fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
504
	 return;
505
      }
506
   }
507
   else if (HAVE_TRI_STRIPS) {
508
      LOCAL_VARS;
509
      int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
510
      int currentsz;
511
 
512
      /* Emit smooth-shaded quadstrips as tristrips:
513
       */
514
      FLUSH();
515
      INIT( GL_TRIANGLE_STRIP );
516
 
517
      /* Emit whole number of quads in total, and in each buffer.
518
       */
519
      dmasz -= dmasz & 1;
520
      currentsz = GET_CURRENT_VB_MAX_VERTS();
521
      currentsz -= currentsz & 1;
522
      count -= (count-start) & 1;
523
 
524
      if (currentsz < 8) {
525
	 currentsz = dmasz;
526
      }
527
 
528
      for (j = start; j + 3 < count; j += nr - 2 ) {
529
	 nr = MIN2( currentsz, count - j );
530
	 TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
531
	 currentsz = dmasz;
532
      }
533
 
534
      FLUSH();
535
 
536
   } else {
537
      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
538
      return;
539
   }
540
}
541
 
542
 
543
static void TAG(render_quads_verts)( struct gl_context *ctx,
544
				     GLuint start,
545
				     GLuint count,
546
				     GLuint flags )
547
{
548
   if (HAVE_QUADS) {
549
      LOCAL_VARS;
550
      int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS()/4) * 4;
551
      int currentsz;
552
      GLuint j, nr;
553
 
554
      INIT(GL_QUADS);
555
 
556
      /* Emit whole number of quads in total.  dmasz is already a multiple
557
       * of 4.
558
       */
559
      count -= (count-start)%4;
560
 
561
      currentsz = (GET_CURRENT_VB_MAX_VERTS()/4) * 4;
562
      if (currentsz < 8)
563
         currentsz = dmasz;
564
 
565
      for (j = start; j < count; j += nr) {
566
         nr = MIN2( currentsz, count - j );
567
         TAG(emit_verts)( ctx, j, nr, ALLOC_VERTS(nr) );
568
         currentsz = dmasz;
569
      }
570
   }
571
   else if (HAVE_ELTS) {
572
      /* Hardware doesn't have a quad primitive type -- try to
573
       * simulate it using indexed vertices and the triangle
574
       * primitive:
575
       */
576
      LOCAL_VARS;
577
      int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
578
      int currentsz;
579
      GLuint j, nr;
580
 
581
      EMIT_INDEXED_VERTS( ctx, start, count );
582
 
583
      FLUSH();
584
      ELT_INIT( GL_TRIANGLES );
585
      currentsz = GET_CURRENT_VB_MAX_ELTS();
586
 
587
      /* Emit whole number of quads in total, and in each buffer.
588
       */
589
      dmasz -= dmasz & 3;
590
      count -= (count-start) & 3;
591
      currentsz -= currentsz & 3;
592
 
593
      /* Adjust for rendering as triangles:
594
       */
595
      currentsz = currentsz/6*4;
596
      dmasz = dmasz/6*4;
597
 
598
      if (currentsz < 8)
599
	 currentsz = dmasz;
600
 
601
      for (j = start; j < count; j += nr ) {
602
	 nr = MIN2( currentsz, count - j );
603
	 if (nr >= 4) {
604
	    GLint quads = nr/4;
605
	    GLint i;
606
	    ELTS_VARS( ALLOC_ELTS( quads*6 ) );
607
 
608
	    for ( i = j-start ; i < j-start+quads*4 ; i+=4 ) {
609
	       EMIT_TWO_ELTS( 0, (i+0), (i+1) );
610
	       EMIT_TWO_ELTS( 2, (i+3), (i+1) );
611
	       EMIT_TWO_ELTS( 4, (i+2), (i+3) );
612
	       INCR_ELTS( 6 );
613
	    }
614
 
615
	    FLUSH();
616
	 }
617
	 currentsz = dmasz;
618
      }
619
 
620
      RELEASE_ELT_VERTS();
621
   }
622
   else if (HAVE_TRIANGLES) {
623
      /* Hardware doesn't have a quad primitive type -- try to
624
       * simulate it using triangle primitive.  This is a win for
625
       * gears, but is it useful in the broader world?
626
       */
627
      LOCAL_VARS;
628
      GLuint j;
629
 
630
      INIT(GL_TRIANGLES);
631
 
632
      for (j = start; j < count-3; j += 4) {
633
	 void *tmp = ALLOC_VERTS( 6 );
634
	 /* Send v0, v1, v3
635
	  */
636
	 tmp = EMIT_VERTS(ctx, j,     2, tmp);
637
	 tmp = EMIT_VERTS(ctx, j + 3, 1, tmp);
638
	 /* Send v1, v2, v3
639
	  */
640
	 tmp = EMIT_VERTS(ctx, j + 1, 3, tmp);
641
	 (void) tmp;
642
      }
643
   }
644
   else {
645
      /* Vertices won't fit in a single buffer, should never happen.
646
       */
647
      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
648
      return;
649
   }
650
}
651
 
652
static void TAG(render_noop)( struct gl_context *ctx,
653
			      GLuint start,
654
			      GLuint count,
655
			      GLuint flags )
656
{
657
}
658
 
659
 
660
 
661
 
662
static tnl_render_func TAG(render_tab_verts)[GL_POLYGON+2] =
663
{
664
   TAG(render_points_verts),
665
   TAG(render_lines_verts),
666
   TAG(render_line_loop_verts),
667
   TAG(render_line_strip_verts),
668
   TAG(render_triangles_verts),
669
   TAG(render_tri_strip_verts),
670
   TAG(render_tri_fan_verts),
671
   TAG(render_quads_verts),
672
   TAG(render_quad_strip_verts),
673
   TAG(render_poly_verts),
674
   TAG(render_noop),
675
};
676
 
677
 
678
/****************************************************************************
679
 *                 Render elts using hardware indexed verts                 *
680
 ****************************************************************************/
681
 
682
#if (HAVE_ELTS)
683
static void TAG(render_points_elts)( struct gl_context *ctx,
684
				     GLuint start,
685
				     GLuint count,
686
				     GLuint flags )
687
{
688
   if (HAVE_POINTS) {
689
      LOCAL_VARS;
690
      int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
691
      int currentsz;
692
      GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
693
      GLuint j, nr;
694
 
695
      ELT_INIT( GL_POINTS );
696
 
697
      currentsz = GET_CURRENT_VB_MAX_ELTS();
698
      if (currentsz < 8)
699
	 currentsz = dmasz;
700
 
701
      for (j = start; j < count; j += nr ) {
702
	 nr = MIN2( currentsz, count - j );
703
	 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
704
	 FLUSH();
705
	 currentsz = dmasz;
706
      }
707
   } else {
708
      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
709
      return;
710
   }
711
}
712
 
713
 
714
 
715
static void TAG(render_lines_elts)( struct gl_context *ctx,
716
				    GLuint start,
717
				    GLuint count,
718
				    GLuint flags )
719
{
720
   if (HAVE_LINES) {
721
      LOCAL_VARS;
722
      int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
723
      int currentsz;
724
      GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
725
      GLuint j, nr;
726
 
727
      ELT_INIT( GL_LINES );
728
 
729
      /* Emit whole number of lines in total and in each buffer:
730
       */
731
      count -= (count-start) & 1;
732
      currentsz -= currentsz & 1;
733
      dmasz -= dmasz & 1;
734
 
735
      currentsz = GET_CURRENT_VB_MAX_ELTS();
736
      if (currentsz < 8)
737
	 currentsz = dmasz;
738
 
739
      for (j = start; j < count; j += nr ) {
740
	 nr = MIN2( currentsz, count - j );
741
	 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
742
	 FLUSH();
743
	 currentsz = dmasz;
744
      }
745
   } else {
746
      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
747
      return;
748
   }
749
}
750
 
751
 
752
static void TAG(render_line_strip_elts)( struct gl_context *ctx,
753
					 GLuint start,
754
					 GLuint count,
755
					 GLuint flags )
756
{
757
   if (HAVE_LINE_STRIPS) {
758
      LOCAL_VARS;
759
      int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
760
      int currentsz;
761
      GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
762
      GLuint j, nr;
763
 
764
      FLUSH(); /* always a new primitive */
765
      ELT_INIT( GL_LINE_STRIP );
766
 
767
      currentsz = GET_CURRENT_VB_MAX_ELTS();
768
      if (currentsz < 8)
769
	 currentsz = dmasz;
770
 
771
      for (j = start; j + 1 < count; j += nr - 1 ) {
772
	 nr = MIN2( currentsz, count - j );
773
	 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
774
	 FLUSH();
775
	 currentsz = dmasz;
776
      }
777
   } else {
778
      /* TODO: Try to emit as indexed lines.
779
       */
780
      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
781
      return;
782
   }
783
}
784
 
785
 
786
static void TAG(render_line_loop_elts)( struct gl_context *ctx,
787
					GLuint start,
788
					GLuint count,
789
					GLuint flags )
790
{
791
   if (HAVE_LINE_STRIPS) {
792
      LOCAL_VARS;
793
      int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
794
      int currentsz;
795
      GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
796
      GLuint j, nr;
797
 
798
      FLUSH();
799
      ELT_INIT( GL_LINE_STRIP );
800
 
801
      if (flags & PRIM_BEGIN)
802
	 j = start;
803
      else
804
	 j = start + 1;
805
 
806
      currentsz = GET_CURRENT_VB_MAX_ELTS();
807
      if (currentsz < 8) {
808
	 currentsz = dmasz;
809
      }
810
 
811
      /* Ensure last vertex doesn't wrap:
812
       */
813
      currentsz--;
814
      dmasz--;
815
 
816
      if (j + 1 < count) {
817
	 for ( ; j + 1 < count; j += nr - 1 ) {
818
	    nr = MIN2( currentsz, count - j );
819
 
820
	    if (j + nr >= count &&
821
		start < count - 1 &&
822
		(flags & PRIM_END))
823
	    {
824
	       void *tmp;
825
	       tmp = ALLOC_ELTS(nr+1);
826
	       tmp = TAG(emit_elts)( ctx, elts+j, nr, tmp );
827
	       tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
828
	       (void) tmp;
829
	    }
830
	    else {
831
	       TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
832
	       currentsz = dmasz;
833
	    }
834
	 }
835
 
836
      }
837
      else if (start + 1 < count && (flags & PRIM_END)) {
838
	 void *tmp;
839
	 tmp = ALLOC_ELTS(2);
840
	 tmp = TAG(emit_elts)( ctx, elts+start+1, 1, tmp );
841
	 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
842
	 (void) tmp;
843
      }
844
 
845
      FLUSH();
846
   } else {
847
      /* TODO: Try to emit as indexed lines */
848
      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
849
      return;
850
   }
851
}
852
 
853
 
854
/* For verts, we still eliminate the copy from main memory to dma
855
 * buffers.  For elts, this is probably no better (worse?) than the
856
 * standard path.
857
 */
858
static void TAG(render_triangles_elts)( struct gl_context *ctx,
859
					GLuint start,
860
					GLuint count,
861
					GLuint flags )
862
{
863
   LOCAL_VARS;
864
   GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
865
   int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS()/3*3;
866
   int currentsz;
867
   GLuint j, nr;
868
 
869
   FLUSH();
870
   ELT_INIT( GL_TRIANGLES );
871
 
872
   currentsz = GET_CURRENT_VB_MAX_ELTS();
873
 
874
   /* Emit whole number of tris in total.  dmasz is already a multiple
875
    * of 3.
876
    */
877
   count -= (count-start)%3;
878
   currentsz -= currentsz%3;
879
   if (currentsz < 8)
880
      currentsz = dmasz;
881
 
882
   for (j = start; j < count; j += nr) {
883
      nr = MIN2( currentsz, count - j );
884
      TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
885
      FLUSH();
886
      currentsz = dmasz;
887
   }
888
}
889
 
890
 
891
 
892
static void TAG(render_tri_strip_elts)( struct gl_context *ctx,
893
					GLuint start,
894
					GLuint count,
895
					GLuint flags )
896
{
897
   if (HAVE_TRI_STRIPS) {
898
      LOCAL_VARS;
899
      GLuint j, nr;
900
      GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
901
      int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
902
      int currentsz;
903
 
904
      FLUSH();
905
      ELT_INIT( GL_TRIANGLE_STRIP );
906
 
907
      currentsz = GET_CURRENT_VB_MAX_ELTS();
908
      if (currentsz < 8) {
909
	 currentsz = dmasz;
910
      }
911
 
912
      /* Keep the same winding over multiple buffers:
913
       */
914
      dmasz -= (dmasz & 1);
915
      currentsz -= (currentsz & 1);
916
 
917
      for (j = start ; j + 2 < count; j += nr - 2 ) {
918
	 nr = MIN2( currentsz, count - j );
919
	 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
920
	 FLUSH();
921
	 currentsz = dmasz;
922
      }
923
   } else {
924
      /* TODO: try to emit as indexed triangles */
925
      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
926
      return;
927
   }
928
}
929
 
930
static void TAG(render_tri_fan_elts)( struct gl_context *ctx,
931
				      GLuint start,
932
				      GLuint count,
933
				      GLuint flags )
934
{
935
   if (HAVE_TRI_FANS) {
936
      LOCAL_VARS;
937
      GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
938
      GLuint j, nr;
939
      int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
940
      int currentsz;
941
 
942
      FLUSH();
943
      ELT_INIT( GL_TRIANGLE_FAN );
944
 
945
      currentsz = GET_CURRENT_VB_MAX_ELTS();
946
      if (currentsz < 8) {
947
	 currentsz = dmasz;
948
      }
949
 
950
      for (j = start + 1 ; j + 1 < count; j += nr - 2 ) {
951
	 void *tmp;
952
	 nr = MIN2( currentsz, count - j + 1 );
953
	 tmp = ALLOC_ELTS( nr );
954
	 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
955
	 tmp = TAG(emit_elts)( ctx, elts+j, nr - 1, tmp );
956
	 (void) tmp;
957
	 FLUSH();
958
	 currentsz = dmasz;
959
      }
960
   } else {
961
      /* TODO: try to emit as indexed triangles */
962
      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
963
      return;
964
   }
965
}
966
 
967
 
968
static void TAG(render_poly_elts)( struct gl_context *ctx,
969
				   GLuint start,
970
				   GLuint count,
971
				   GLuint flags )
972
{
973
   if (HAVE_POLYGONS) {
974
      LOCAL_VARS;
975
      GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
976
      GLuint j, nr;
977
      int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
978
      int currentsz;
979
 
980
      FLUSH();
981
      ELT_INIT( GL_POLYGON );
982
 
983
      currentsz = GET_CURRENT_VB_MAX_ELTS();
984
      if (currentsz < 8) {
985
	 currentsz = dmasz;
986
      }
987
 
988
      for (j = start + 1 ; j + 1 < count; j += nr - 2 ) {
989
	 void *tmp;
990
	 nr = MIN2( currentsz, count - j + 1 );
991
	 tmp = ALLOC_ELTS( nr );
992
	 tmp = TAG(emit_elts)( ctx, elts+start, 1, tmp );
993
	 tmp = TAG(emit_elts)( ctx, elts+j, nr - 1, tmp );
994
	 (void) tmp;
995
	 FLUSH();
996
	 currentsz = dmasz;
997
      }
998
   } else if (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH) {
999
      TAG(render_tri_fan_verts)( ctx, start, count, flags );
1000
   } else {
1001
      fprintf(stderr, "%s - cannot draw primitive\n", __FUNCTION__);
1002
      return;
1003
   }
1004
}
1005
 
1006
static void TAG(render_quad_strip_elts)( struct gl_context *ctx,
1007
					 GLuint start,
1008
					 GLuint count,
1009
					 GLuint flags )
1010
{
1011
   if (HAVE_QUAD_STRIPS && 0) {
1012
   }
1013
   else if (HAVE_TRI_STRIPS) {
1014
      LOCAL_VARS;
1015
      GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
1016
      int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
1017
      int currentsz;
1018
      GLuint j, nr;
1019
 
1020
      FLUSH();
1021
      currentsz = GET_CURRENT_VB_MAX_ELTS();
1022
 
1023
      /* Emit whole number of quads in total, and in each buffer.
1024
       */
1025
      dmasz -= dmasz & 1;
1026
      count -= (count-start) & 1;
1027
      currentsz -= currentsz & 1;
1028
 
1029
      if (currentsz < 12)
1030
	 currentsz = dmasz;
1031
 
1032
      if (ctx->Light.ShadeModel == GL_FLAT) {
1033
	 ELT_INIT( GL_TRIANGLES );
1034
 
1035
	 currentsz = currentsz/6*2;
1036
	 dmasz = dmasz/6*2;
1037
 
1038
	 for (j = start; j + 3 < count; j += nr - 2 ) {
1039
	    nr = MIN2( currentsz, count - j );
1040
 
1041
	    if (nr >= 4)
1042
	    {
1043
	       GLint i;
1044
	       GLint quads = (nr/2)-1;
1045
	       ELTS_VARS( ALLOC_ELTS( quads*6 ) );
1046
 
1047
	       for ( i = j-start ; i < j-start+quads ; i++, elts += 2 ) {
1048
		  EMIT_TWO_ELTS( 0, elts[0], elts[1] );
1049
		  EMIT_TWO_ELTS( 2, elts[2], elts[1] );
1050
		  EMIT_TWO_ELTS( 4, elts[3], elts[2] );
1051
		  INCR_ELTS( 6 );
1052
	       }
1053
 
1054
	       FLUSH();
1055
	    }
1056
 
1057
	    currentsz = dmasz;
1058
	 }
1059
      }
1060
      else {
1061
	 ELT_INIT( GL_TRIANGLE_STRIP );
1062
 
1063
	 for (j = start; j + 3 < count; j += nr - 2 ) {
1064
	    nr = MIN2( currentsz, count - j );
1065
	    TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
1066
	    FLUSH();
1067
	    currentsz = dmasz;
1068
	 }
1069
      }
1070
   }
1071
}
1072
 
1073
 
1074
static void TAG(render_quads_elts)( struct gl_context *ctx,
1075
				    GLuint start,
1076
				    GLuint count,
1077
				    GLuint flags )
1078
{
1079
   if (HAVE_QUADS) {
1080
      LOCAL_VARS;
1081
      GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
1082
      int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS()/4*4;
1083
      int currentsz;
1084
      GLuint j, nr;
1085
 
1086
      FLUSH();
1087
      ELT_INIT( GL_TRIANGLES );
1088
 
1089
      currentsz = GET_CURRENT_VB_MAX_ELTS()/4*4;
1090
 
1091
      count -= (count-start)%4;
1092
 
1093
      if (currentsz < 8)
1094
	 currentsz = dmasz;
1095
 
1096
      for (j = start; j < count; j += nr) {
1097
	 nr = MIN2( currentsz, count - j );
1098
	 TAG(emit_elts)( ctx, elts+j, nr, ALLOC_ELTS(nr) );
1099
	 FLUSH();
1100
	 currentsz = dmasz;
1101
      }
1102
   } else {
1103
      LOCAL_VARS;
1104
      GLuint *elts = TNL_CONTEXT(ctx)->vb.Elts;
1105
      int dmasz = GET_SUBSEQUENT_VB_MAX_ELTS();
1106
      int currentsz;
1107
      GLuint j, nr;
1108
 
1109
      ELT_INIT( GL_TRIANGLES );
1110
      currentsz = GET_CURRENT_VB_MAX_ELTS();
1111
 
1112
      /* Emit whole number of quads in total, and in each buffer.
1113
       */
1114
      dmasz -= dmasz & 3;
1115
      count -= (count-start) & 3;
1116
      currentsz -= currentsz & 3;
1117
 
1118
      /* Adjust for rendering as triangles:
1119
       */
1120
      currentsz = currentsz/6*4;
1121
      dmasz = dmasz/6*4;
1122
 
1123
      if (currentsz < 8)
1124
	 currentsz = dmasz;
1125
 
1126
      for (j = start; j + 3 < count; j += nr - 2 ) {
1127
	 nr = MIN2( currentsz, count - j );
1128
 
1129
	 if (nr >= 4)
1130
	 {
1131
	    GLint quads = nr/4;
1132
	    GLint i;
1133
	    ELTS_VARS( ALLOC_ELTS( quads * 6 ) );
1134
 
1135
	    for ( i = j-start ; i < j-start+quads ; i++, elts += 4 ) {
1136
	       EMIT_TWO_ELTS( 0, elts[0], elts[1] );
1137
	       EMIT_TWO_ELTS( 2, elts[3], elts[1] );
1138
	       EMIT_TWO_ELTS( 4, elts[2], elts[3] );
1139
	       INCR_ELTS( 6 );
1140
	    }
1141
 
1142
	    FLUSH();
1143
	 }
1144
 
1145
	 currentsz = dmasz;
1146
      }
1147
   }
1148
}
1149
 
1150
 
1151
 
1152
static tnl_render_func TAG(render_tab_elts)[GL_POLYGON+2] =
1153
{
1154
   TAG(render_points_elts),
1155
   TAG(render_lines_elts),
1156
   TAG(render_line_loop_elts),
1157
   TAG(render_line_strip_elts),
1158
   TAG(render_triangles_elts),
1159
   TAG(render_tri_strip_elts),
1160
   TAG(render_tri_fan_elts),
1161
   TAG(render_quads_elts),
1162
   TAG(render_quad_strip_elts),
1163
   TAG(render_poly_elts),
1164
   TAG(render_noop),
1165
};
1166
 
1167
 
1168
 
1169
#endif
1170
 
1171
 
1172
 
1173
/* Pre-check the primitives in the VB to prevent the need for
1174
 * fallbacks later on.
1175
 */
1176
static GLboolean TAG(validate_render)( struct gl_context *ctx,
1177
				       struct vertex_buffer *VB )
1178
{
1179
   GLint i;
1180
 
1181
   if (VB->ClipOrMask & ~CLIP_CULL_BIT)
1182
      return GL_FALSE;
1183
 
1184
   if (VB->Elts && !HAVE_ELTS)
1185
      return GL_FALSE;
1186
 
1187
   for (i = 0 ; i < VB->PrimitiveCount ; i++) {
1188
      GLuint prim = VB->Primitive[i].mode;
1189
      GLuint count = VB->Primitive[i].count;
1190
      GLboolean ok = GL_FALSE;
1191
 
1192
      if (!count)
1193
	 continue;
1194
 
1195
      switch (prim & PRIM_MODE_MASK) {
1196
      case GL_POINTS:
1197
	 ok = HAVE_POINTS;
1198
	 break;
1199
      case GL_LINES:
1200
	 ok = HAVE_LINES && !ctx->Line.StippleFlag;
1201
	 break;
1202
      case GL_LINE_STRIP:
1203
	 ok = HAVE_LINE_STRIPS && !ctx->Line.StippleFlag;
1204
	 break;
1205
      case GL_LINE_LOOP:
1206
	 ok = HAVE_LINE_STRIPS && !ctx->Line.StippleFlag;
1207
	 break;
1208
      case GL_TRIANGLES:
1209
	 ok = HAVE_TRIANGLES;
1210
	 break;
1211
      case GL_TRIANGLE_STRIP:
1212
	 ok = HAVE_TRI_STRIPS;
1213
	 break;
1214
      case GL_TRIANGLE_FAN:
1215
	 ok = HAVE_TRI_FANS;
1216
	 break;
1217
      case GL_POLYGON:
1218
	 if (HAVE_POLYGONS) {
1219
	    ok = GL_TRUE;
1220
	 }
1221
	 else {
1222
	    ok = (HAVE_TRI_FANS && ctx->Light.ShadeModel == GL_SMOOTH);
1223
         }
1224
	 break;
1225
      case GL_QUAD_STRIP:
1226
	 if (VB->Elts) {
1227
	    ok = HAVE_TRI_STRIPS;
1228
	 }
1229
	 else if (HAVE_QUAD_STRIPS) {
1230
	    ok = GL_TRUE;
1231
	 } else if (HAVE_TRI_STRIPS &&
1232
		    ctx->Light.ShadeModel == GL_FLAT &&
1233
		    VB->AttribPtr[_TNL_ATTRIB_COLOR0]->stride != 0) {
1234
	    if (HAVE_ELTS) {
1235
	       ok = (GLint) count < GET_SUBSEQUENT_VB_MAX_ELTS();
1236
	    }
1237
	    else {
1238
	       ok = GL_FALSE;
1239
	    }
1240
	 }
1241
	 else
1242
	    ok = HAVE_TRI_STRIPS;
1243
	 break;
1244
      case GL_QUADS:
1245
	 if (HAVE_QUADS) {
1246
	    ok = GL_TRUE;
1247
	 } else if (HAVE_ELTS) {
1248
	    ok = (GLint) count < GET_SUBSEQUENT_VB_MAX_ELTS();
1249
	 }
1250
	 else {
1251
	    ok = HAVE_TRIANGLES; /* flatshading is ok. */
1252
	 }
1253
	 break;
1254
      default:
1255
	 break;
1256
      }
1257
 
1258
      if (!ok) {
1259
/* 	 fprintf(stderr, "not ok %s\n", _mesa_lookup_enum_by_nr(prim & PRIM_MODE_MASK)); */
1260
	 return GL_FALSE;
1261
      }
1262
   }
1263
 
1264
   return GL_TRUE;
1265
}
1266