Fixed off by one errors in clipping.
[mesa.git] / src / mesa / drivers / dri / unichrome / via_dmatmp.h
1 /*
2 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
3 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sub license,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS 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 OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 /* Template for render stages which build and emit vertices directly
26 * to fixed-size dma buffers. Useful for rendering strips and other
27 * native primitives where clipping and per-vertex tweaks such as
28 * those in t_dd_tritmp.h are not required.
29 *
30 * Produces code for both inline triangles and indexed triangles.
31 * Where various primitive types are unaccelerated by hardware, the
32 * code attempts to fallback to other primitive types (quadstrips to
33 * tristrips, lineloops to linestrips), or to indexed vertices.
34 * Ultimately, a FALLBACK() macro is invoked if there is no way to
35 * render the primitive natively.
36 */
37
38 #if !defined(HAVE_TRIANGLES)
39 #error "must have at least triangles to use render template"
40 #endif
41
42 #if !HAVE_ELTS
43 #define ELTS_VARS
44 #define ALLOC_ELTS(nr)
45 #define EMIT_ELT(offset, elt)
46 #define EMIT_TWO_ELTS(offset, elt0, elt1)
47 #define INCR_ELTS(nr)
48 #define ELT_INIT(prim)
49 #define GET_CURRENT_VB_MAX_ELTS() 0
50 #define GET_SUBSEQUENT_VB_MAX_ELTS() 0
51 #define ALLOC_ELTS_NEW_PRIMITIVE(nr)
52 #define RELEASE_ELT_VERTS()
53 #define EMIT_INDEXED_VERTS(ctx, start, count)
54 #endif
55
56 #ifndef EMIT_TWO_ELTS
57 #define EMIT_TWO_ELTS(offset, elt0, elt1) \
58 do { \
59 EMIT_ELT(offset, elt0); \
60 EMIT_ELT(offset + 1, elt1); \
61 } while (0)
62 #endif
63
64 #ifndef FINISH
65 #define FINISH
66 #endif
67
68 /***********************************************************************
69 * Render non-indexed primitives.
70 ***********************************************************************/
71
72 static void TAG(render_points_verts)(GLcontext *ctx,
73 GLuint start,
74 GLuint count,
75 GLuint flags)
76 {
77 #ifdef PERFORMANCE_MEASURE
78 if (VIA_PERFORMANCE) P_M_X;
79 #endif
80 #ifdef DEBUG
81 if (VIA_DEBUG) fprintf(stderr, "%s in\n", __FUNCTION__);
82 #endif
83 if (HAVE_POINTS) {
84 LOCAL_VARS;
85 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
86 int currentsz = GET_CURRENT_VB_MAX_VERTS();
87 GLuint j, nr;
88
89 INIT(GL_POINTS);
90
91 if (currentsz < 8)
92 currentsz = dmasz;
93
94 for (j = start; j < count; j += nr) {
95 nr = MIN2(currentsz, count - j);
96 EMIT_VERTS(ctx, j, nr);
97 currentsz = dmasz;
98 }
99
100 FINISH;
101 }
102 else {
103 VERT_FALLBACK(ctx, start, count, flags);
104 }
105 #ifdef DEBUG
106 if (VIA_DEBUG) fprintf(stderr, "%s out\n", __FUNCTION__);
107 #endif
108 }
109
110 static void TAG(render_lines_verts)(GLcontext *ctx,
111 GLuint start,
112 GLuint count,
113 GLuint flags)
114 {
115 #ifdef PERFORMANCE_MEASURE
116 if (VIA_PERFORMANCE) P_M_X;
117 #endif
118 #ifdef DEBUG
119 if (VIA_DEBUG) fprintf(stderr, "%s in\n", __FUNCTION__);
120 #endif
121 if (HAVE_LINES) {
122 LOCAL_VARS;
123 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
124 int currentsz = GET_CURRENT_VB_MAX_VERTS();
125 GLuint j, nr;
126
127 INIT(GL_LINES);
128
129 /* Emit whole number of lines in total and in each buffer:
130 */
131 count -= (count - start) & 1;
132 currentsz -= currentsz & 1;
133 dmasz -= dmasz & 1;
134
135 if (currentsz < 8)
136 currentsz = dmasz;
137
138 for (j = start; j < count; j += nr) {
139 nr = MIN2(currentsz, count - j);
140 EMIT_VERTS(ctx, j, nr);
141 currentsz = dmasz;
142 }
143
144 FINISH;
145 }
146 else {
147 VERT_FALLBACK(ctx, start, count, flags);
148 }
149 #ifdef DEBUG
150 if (VIA_DEBUG) fprintf(stderr, "%s out\n", __FUNCTION__);
151 #endif
152 }
153
154
155 static void TAG(render_line_strip_verts)(GLcontext *ctx,
156 GLuint start,
157 GLuint count,
158 GLuint flags)
159 {
160 #ifdef PERFORMANCE_MEASURE
161 if (VIA_PERFORMANCE) P_M_X;
162 #endif
163 #ifdef DEBUG
164 if (VIA_DEBUG) fprintf(stderr, "%s in\n", __FUNCTION__);
165 #endif
166 if (HAVE_LINE_STRIPS) {
167 LOCAL_VARS;
168 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
169 int currentsz = GET_CURRENT_VB_MAX_VERTS();
170 GLuint j, nr;
171
172 INIT(GL_LINE_STRIP);
173
174 if (currentsz < 8)
175 currentsz = dmasz;
176
177 for (j = start; j + 1 < count; j += nr - 1) {
178 nr = MIN2(currentsz, count - j);
179 EMIT_VERTS(ctx, j, nr);
180 currentsz = dmasz;
181 }
182
183 FINISH;
184 }
185 else {
186 VERT_FALLBACK(ctx, start, count, flags);
187 }
188 #ifdef DEBUG
189 if (VIA_DEBUG) fprintf(stderr, "%s out\n", __FUNCTION__);
190 #endif
191 }
192
193
194 static void TAG(render_line_loop_verts)(GLcontext *ctx,
195 GLuint start,
196 GLuint count,
197 GLuint flags)
198 {
199 #ifdef PERFORMANCE_MEASURE
200 if (VIA_PERFORMANCE) P_M_X;
201 #endif
202 #ifdef DEBUG
203 if (VIA_DEBUG) fprintf(stderr, "%s in\n", __FUNCTION__);
204 #endif
205 if (HAVE_LINE_STRIPS) {
206 LOCAL_VARS;
207 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
208 int currentsz = GET_CURRENT_VB_MAX_VERTS();
209 GLuint j, nr;
210
211 INIT(GL_LINE_STRIP);
212
213 if (flags & PRIM_BEGIN)
214 j = start;
215 else
216 j = start + 1;
217
218 /* Ensure last vertex won't wrap buffers:
219 */
220 currentsz--;
221 dmasz--;
222
223 if (currentsz < 8)
224 currentsz = dmasz;
225
226 for (; j + 1 < count; j += nr - 1) {
227 nr = MIN2(currentsz, count - j);
228 EMIT_VERTS(ctx, j, nr);
229 currentsz = dmasz;
230 }
231
232 if (start < count - 1 && (flags & PRIM_END))
233 EMIT_VERTS(ctx, start, 1);
234
235 FINISH;
236 }
237 else {
238 VERT_FALLBACK(ctx, start, count, flags);
239 }
240 #ifdef DEBUG
241 if (VIA_DEBUG) fprintf(stderr, "%s out\n", __FUNCTION__);
242 #endif
243 }
244
245
246 static void TAG(render_triangles_verts)(GLcontext *ctx,
247 GLuint start,
248 GLuint count,
249 GLuint flags)
250 {
251 LOCAL_VARS;
252 int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS() / 3) * 3;
253 int currentsz = (GET_CURRENT_VB_MAX_VERTS() / 3) * 3;
254 GLuint j, nr;
255 #ifdef DEBUG
256 if (VIA_DEBUG) fprintf(stderr, "%s - in\n", __FUNCTION__);
257 #endif
258 #ifdef PERFORMANCE_MEASURE
259 if (VIA_PERFORMANCE) P_M_X;
260 #endif
261 INIT(GL_TRIANGLES);
262
263 /* Emit whole number of tris in total. dmasz is already a multiple
264 * of 3.
265 */
266 count -= (count - start) % 3;
267
268 if (currentsz < 8)
269 currentsz = dmasz;
270
271 for (j = start; j < count; j += nr) {
272 nr = MIN2(currentsz, count - j);
273 EMIT_VERTS(ctx, j, nr);
274 currentsz = dmasz;
275 }
276 FINISH;
277 #ifdef DEBUG
278 if (VIA_DEBUG) fprintf(stderr, "%s - out\n", __FUNCTION__);
279 #endif
280 }
281
282
283 static void TAG(render_tri_strip_verts)(GLcontext *ctx,
284 GLuint start,
285 GLuint count,
286 GLuint flags)
287 {
288 #ifdef PERFORMANCE_MEASURE
289 if (VIA_PERFORMANCE) P_M_X;
290 #endif
291 #ifdef DEBUG
292 if (VIA_DEBUG) fprintf(stderr, "%s in\n", __FUNCTION__);
293 #endif
294 if (HAVE_TRI_STRIPS) {
295 LOCAL_VARS;
296 GLuint j, nr;
297 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
298 int currentsz = GET_CURRENT_VB_MAX_VERTS();
299
300 INIT(GL_TRIANGLE_STRIP);
301
302 if (currentsz < 8) {
303 NEW_BUFFER();
304 currentsz = dmasz;
305 }
306
307 /* From here on emit even numbers of tris when wrapping over buffers:
308 */
309 dmasz -= (dmasz & 1);
310 currentsz -= (currentsz & 1);
311
312 for (j = start; j + 2 < count; j += nr - 2) {
313 nr = MIN2(currentsz, count - j);
314 EMIT_VERTS(ctx, j, nr);
315 currentsz = dmasz;
316 }
317
318 FINISH;
319 }
320 else {
321 VERT_FALLBACK(ctx, start, count, flags);
322 }
323 #ifdef DEBUG
324 if (VIA_DEBUG) fprintf(stderr, "%s out\n", __FUNCTION__);
325 #endif
326 }
327
328 static void TAG(render_tri_fan_verts)(GLcontext *ctx,
329 GLuint start,
330 GLuint count,
331 GLuint flags)
332 {
333 #ifdef DEBUG
334 if (VIA_DEBUG) fprintf(stderr, "%s - in\n", __FUNCTION__);
335 #endif
336 #ifdef PERFORMANCE_MEASURE
337 if (VIA_PERFORMANCE) P_M_X;
338 #endif
339 if (HAVE_TRI_FANS) {
340 LOCAL_VARS;
341 GLuint j, nr;
342 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
343 int currentsz = GET_CURRENT_VB_MAX_VERTS();
344
345 INIT(GL_TRIANGLE_FAN);
346
347 if (currentsz < 8) {
348 NEW_BUFFER();
349 currentsz = dmasz;
350 }
351
352 for (j = start + 1; j + 1 < count; j += nr - 1) {
353 nr = MIN2(currentsz, count - j + 1);
354 EMIT_VERTS(ctx, start, 1);
355 EMIT_VERTS(ctx, j, nr - 1);
356 currentsz = dmasz;
357 }
358
359 FINISH;
360 }
361 else {
362 /* Could write code to emit these as indexed vertices (for the
363 * g400, for instance).
364 */
365 VERT_FALLBACK(ctx, start, count, flags);
366 }
367 #ifdef DEBUG
368 if (VIA_DEBUG) fprintf(stderr, "%s - out\n", __FUNCTION__);
369 #endif
370 }
371
372
373 static void TAG(render_poly_verts)(GLcontext *ctx,
374 GLuint start,
375 GLuint count,
376 GLuint flags)
377 {
378 #ifdef PERFORMANCE_MEASURE
379 if (VIA_PERFORMANCE) P_M_X;
380 #endif
381 #ifdef DEBUG
382 if (VIA_DEBUG) fprintf(stderr, "%s in\n", __FUNCTION__);
383 #endif
384 if (HAVE_POLYGONS) {
385 LOCAL_VARS;
386 GLuint j, nr;
387 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
388 int currentsz = GET_CURRENT_VB_MAX_VERTS();
389
390 INIT(GL_POLYGON);
391
392 if (currentsz < 8) {
393 NEW_BUFFER();
394 currentsz = dmasz;
395 }
396
397 for (j = start + 1; j + 1 < count; j += nr - 1) {
398 nr = MIN2(currentsz, count - j + 1);
399 EMIT_VERTS(ctx, start, 1);
400 EMIT_VERTS(ctx, j, nr - 1);
401 currentsz = dmasz;
402 }
403
404 FINISH;
405 }
406 else if (HAVE_TRI_FANS && !(ctx->_TriangleCaps & DD_FLATSHADE)) {
407 TAG(render_tri_fan_verts)(ctx, start, count, flags);
408 }
409 else {
410 VERT_FALLBACK(ctx, start, count, flags);
411 }
412 #ifdef DEBUG
413 if (VIA_DEBUG) fprintf(stderr, "%s out\n", __FUNCTION__);
414 #endif
415 }
416
417 static void TAG(render_quad_strip_verts)(GLcontext *ctx,
418 GLuint start,
419 GLuint count,
420 GLuint flags)
421 {
422 GLuint j, nr;
423 #ifdef PERFORMANCE_MEASURE
424 if (VIA_PERFORMANCE) P_M_X;
425 #endif
426 #ifdef DEBUG
427 if (VIA_DEBUG) fprintf(stderr, "%s in\n", __FUNCTION__);
428 #endif
429 if (HAVE_QUAD_STRIPS) {
430 LOCAL_VARS;
431 GLuint j, nr;
432 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
433 int currentsz;
434
435 INIT(GL_QUAD_STRIP);
436
437 currentsz = GET_CURRENT_VB_MAX_VERTS();
438
439 if (currentsz < 8) {
440 NEW_BUFFER();
441 currentsz = dmasz;
442 }
443
444 dmasz -= (dmasz & 2);
445 currentsz -= (currentsz & 2);
446
447 for (j = start; j + 3 < count; j += nr - 2) {
448 nr = MIN2(currentsz, count - j);
449 EMIT_VERTS(ctx, j, nr);
450 currentsz = dmasz;
451 }
452
453 FINISH;
454 }
455 else if (HAVE_TRI_STRIPS) {
456 LOCAL_VARS;
457 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
458 int currentsz = GET_CURRENT_VB_MAX_VERTS();
459
460 /* Emit smooth-shaded quadstrips as tristrips:
461 */
462 INIT(GL_TRIANGLE_STRIP);
463
464 /* Emit whole number of quads in total, and in each buffer.
465 */
466 dmasz -= dmasz & 1;
467 currentsz -= currentsz & 1;
468 count -= (count - start) & 1;
469
470 if (currentsz < 8) {
471 NEW_BUFFER();
472 currentsz = dmasz;
473 }
474
475 for (j = start; j + 3 < count; j += nr - 2) {
476 nr = MIN2(currentsz, count - j);
477 EMIT_VERTS(ctx, j, nr);
478 currentsz = dmasz;
479 }
480
481 FINISH;
482 }
483 else {
484 VERT_FALLBACK(ctx, start, count, flags);
485 }
486 #ifdef DEBUG
487 if (VIA_DEBUG) fprintf(stderr, "%s out\n", __FUNCTION__);
488 #endif
489 }
490
491
492 static void TAG(render_quads_verts)(GLcontext *ctx,
493 GLuint start,
494 GLuint count,
495 GLuint flags)
496 {
497 #ifdef DEBUG
498 if (VIA_DEBUG) fprintf(stderr, "%s - in\n", __FUNCTION__);
499 #endif
500 #ifdef PERFORMANCE_MEASURE
501 if (VIA_PERFORMANCE) P_M_X;
502 #endif
503 if (HAVE_QUADS) {
504 LOCAL_VARS;
505 int dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS() / 4) * 4;
506 int currentsz = (GET_CURRENT_VB_MAX_VERTS() / 4) * 4;
507 GLuint j, nr;
508
509 INIT(GL_QUADS);
510
511 /* Emit whole number of quads in total. dmasz is already a multiple
512 * of 4.
513 */
514 count -= (count - start) % 4;
515
516 if (currentsz < 8)
517 currentsz = dmasz;
518
519 for (j = start; j < count; j += nr) {
520 nr = MIN2(currentsz, count - j);
521 EMIT_VERTS(ctx, j, nr);
522 currentsz = dmasz;
523 }
524 FINISH;
525 }
526 else if (HAVE_TRIANGLES) {
527 /* Hardware doesn't have a quad primitive type -- try to
528 * simulate it using triangle primitive.
529 */
530 LOCAL_VARS;
531 int dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
532 int currentsz;
533 GLuint j;
534
535 INIT(GL_TRIANGLES);
536
537 currentsz = GET_CURRENT_VB_MAX_VERTS();
538
539 /* Emit whole number of quads in total, and in each buffer.
540 */
541 dmasz -= dmasz & 3;
542 count -= (count - start) & 3;
543 currentsz -= currentsz & 3;
544
545 /* Adjust for rendering as triangles:
546 */
547 currentsz = currentsz / 6 * 4;
548 dmasz = dmasz / 6 * 4;
549
550 if (currentsz < 8)
551 currentsz = dmasz;
552
553 for (j = start; j < count; j += 4) {
554 /* Send v0, v1, v3
555 */
556 EMIT_VERTS(ctx, j, 2);
557 EMIT_VERTS(ctx, j + 3, 1);
558 /* Send v1, v2, v3
559 */
560 EMIT_VERTS(ctx, j + 1, 3);
561 }
562 FINISH;
563 }
564 else {
565 /* Vertices won't fit in a single buffer, fallback.
566 */
567 VERT_FALLBACK(ctx, start, count, flags);
568 }
569 #ifdef DEBUG
570 if (VIA_DEBUG) fprintf(stderr, "%s - out\n", __FUNCTION__);
571 #endif
572 }
573
574 static void TAG(render_noop)(GLcontext *ctx,
575 GLuint start,
576 GLuint count,
577 GLuint flags)
578 {
579 }
580
581
582 static tnl_render_func TAG(render_tab_verts)[GL_POLYGON + 2] =
583 {
584 TAG(render_points_verts),
585 TAG(render_lines_verts),
586 TAG(render_line_loop_verts),
587 TAG(render_line_strip_verts),
588 TAG(render_triangles_verts),
589 TAG(render_tri_strip_verts),
590 TAG(render_tri_fan_verts),
591 TAG(render_quads_verts),
592 TAG(render_quad_strip_verts),
593 TAG(render_poly_verts),
594 TAG(render_noop),
595 };
596