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 <keithw@vmware.com>
26 */
27 #include <stdbool.h>
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 !HAVE_TRIANGLES || !HAVE_LINES || !HAVE_LINE_STRIPS || !HAVE_TRI_STRIPS || !HAVE_TRI_FANS
43 #error "must have lines, line strips, triangles, triangle fans, and triangle strips to use render template"
44 #endif
45
46 #if HAVE_QUAD_STRIPS || HAVE_QUADS || HAVE_ELTS
47 #error "ELTs, quads, and quad strips not supported by render template"
48 #endif
49
50
51 /**********************************************************************/
52 /* Render whole begin/end objects */
53 /**********************************************************************/
54
TAG(emit_verts)55 static inline void *TAG(emit_verts)(struct gl_context *ctx, GLuint start,
56 GLuint count, void *buf)
57 {
58 return EMIT_VERTS(ctx, start, count, buf);
59 }
60
61 /***********************************************************************
62 * Render non-indexed primitives.
63 ***********************************************************************/
64
TAG(render_points_verts)65 static void TAG(render_points_verts)(struct gl_context *ctx,
66 GLuint start,
67 GLuint count,
68 GLuint flags)
69 {
70 if (HAVE_POINTS) {
71 LOCAL_VARS;
72 const unsigned dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
73 unsigned currentsz;
74 GLuint j, nr;
75
76 INIT(GL_POINTS);
77
78 currentsz = GET_CURRENT_VB_MAX_VERTS();
79 if (currentsz < 8)
80 currentsz = dmasz;
81
82 for (j = 0; j < count; j += nr) {
83 nr = MIN2(currentsz, count - j);
84 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
85 currentsz = dmasz;
86 }
87 } else {
88 unreachable("Cannot draw primitive; validate_render should have "
89 "prevented this");
90 }
91 }
92
TAG(render_lines_verts)93 static void TAG(render_lines_verts)(struct gl_context *ctx,
94 GLuint start,
95 GLuint count,
96 GLuint flags)
97 {
98 LOCAL_VARS;
99 const unsigned dmasz = GET_SUBSEQUENT_VB_MAX_VERTS() & ~1;
100 unsigned currentsz;
101 GLuint j, nr;
102
103 INIT(GL_LINES);
104
105 /* Emit whole number of lines in total and in each buffer:
106 */
107 count -= count & 1;
108 currentsz = GET_CURRENT_VB_MAX_VERTS();
109 currentsz -= currentsz & 1;
110
111 if (currentsz < 8)
112 currentsz = dmasz;
113
114 for (j = 0; j < count; j += nr) {
115 nr = MIN2(currentsz, count - j);
116 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
117 currentsz = dmasz;
118 }
119 }
120
121
TAG(render_line_strip_verts)122 static void TAG(render_line_strip_verts)(struct gl_context *ctx,
123 GLuint start,
124 GLuint count,
125 GLuint flags)
126 {
127 LOCAL_VARS;
128 const unsigned dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
129 unsigned currentsz;
130 GLuint j, nr;
131
132 INIT(GL_LINE_STRIP);
133
134 currentsz = GET_CURRENT_VB_MAX_VERTS();
135 if (currentsz < 8)
136 currentsz = dmasz;
137
138 for (j = 0; j + 1 < count; j += nr - 1) {
139 nr = MIN2(currentsz, count - j);
140 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
141 currentsz = dmasz;
142 }
143
144 FLUSH();
145 }
146
147
TAG(render_line_loop_verts)148 static void TAG(render_line_loop_verts)(struct gl_context *ctx,
149 GLuint start,
150 GLuint count,
151 GLuint flags)
152 {
153 LOCAL_VARS;
154 const unsigned dmasz = GET_SUBSEQUENT_VB_MAX_VERTS() - 1;
155 unsigned currentsz;
156 GLuint j, nr;
157
158 INIT(GL_LINE_STRIP);
159
160 j = (flags & PRIM_BEGIN) ? 0 : 1;
161
162 /* Ensure last vertex won't wrap buffers:
163 */
164 currentsz = GET_CURRENT_VB_MAX_VERTS();
165 currentsz--;
166
167 if (currentsz < 8)
168 currentsz = dmasz;
169
170 if (j + 1 < count) {
171 for (/* empty */; j + 1 < count; j += nr - 1) {
172 nr = MIN2(currentsz, count - j);
173
174 if (j + nr >= count &&
175 count > 1 &&
176 (flags & PRIM_END)) {
177 void *tmp;
178 tmp = ALLOC_VERTS(nr+1);
179 tmp = TAG(emit_verts)(ctx, start + j, nr, tmp);
180 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
181 (void) tmp;
182 } else {
183 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
184 currentsz = dmasz;
185 }
186 }
187 } else if (count > 1 && (flags & PRIM_END)) {
188 void *tmp;
189 tmp = ALLOC_VERTS(2);
190 tmp = TAG(emit_verts)( ctx, start+1, 1, tmp );
191 tmp = TAG(emit_verts)( ctx, start, 1, tmp );
192 (void) tmp;
193 }
194
195 FLUSH();
196 }
197
198
TAG(render_triangles_verts)199 static void TAG(render_triangles_verts)(struct gl_context *ctx,
200 GLuint start,
201 GLuint count,
202 GLuint flags)
203 {
204 LOCAL_VARS;
205 const unsigned dmasz = (GET_SUBSEQUENT_VB_MAX_VERTS() / 3) * 3;
206 unsigned currentsz;
207 GLuint j, nr;
208
209 INIT(GL_TRIANGLES);
210
211 currentsz = (GET_CURRENT_VB_MAX_VERTS() / 3) * 3;
212
213 /* Emit whole number of tris in total. dmasz is already a multiple
214 * of 3.
215 */
216 count -= count % 3;
217
218 if (currentsz < 8)
219 currentsz = dmasz;
220
221 for (j = 0; j < count; j += nr) {
222 nr = MIN2(currentsz, count - j);
223 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
224 currentsz = dmasz;
225 }
226 }
227
228
229
TAG(render_tri_strip_verts)230 static void TAG(render_tri_strip_verts)(struct gl_context *ctx,
231 GLuint start,
232 GLuint count,
233 GLuint flags)
234 {
235 LOCAL_VARS;
236 GLuint j, nr;
237 const unsigned dmasz = GET_SUBSEQUENT_VB_MAX_VERTS() & ~1;
238 unsigned currentsz;
239
240 INIT(GL_TRIANGLE_STRIP);
241
242 currentsz = GET_CURRENT_VB_MAX_VERTS();
243
244 if (currentsz < 8)
245 currentsz = dmasz;
246
247 /* From here on emit even numbers of tris when wrapping over buffers:
248 */
249 currentsz -= (currentsz & 1);
250
251 for (j = 0; j + 2 < count; j += nr - 2) {
252 nr = MIN2(currentsz, count - j);
253 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
254 currentsz = dmasz;
255 }
256
257 FLUSH();
258 }
259
TAG(render_tri_fan_verts)260 static void TAG(render_tri_fan_verts)(struct gl_context *ctx,
261 GLuint start,
262 GLuint count,
263 GLuint flags)
264 {
265 LOCAL_VARS;
266 GLuint j, nr;
267 const unsigned dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
268 unsigned currentsz;
269
270 INIT(GL_TRIANGLE_FAN);
271
272 currentsz = GET_CURRENT_VB_MAX_VERTS();
273 if (currentsz < 8)
274 currentsz = dmasz;
275
276 for (j = 1; j + 1 < count; j += nr - 2) {
277 void *tmp;
278 nr = MIN2(currentsz, count - j + 1);
279 tmp = ALLOC_VERTS(nr);
280 tmp = TAG(emit_verts)(ctx, start, 1, tmp);
281 tmp = TAG(emit_verts)(ctx, start + j, nr - 1, tmp);
282 (void) tmp;
283 currentsz = dmasz;
284 }
285
286 FLUSH();
287 }
288
289
TAG(render_poly_verts)290 static void TAG(render_poly_verts)(struct gl_context *ctx,
291 GLuint start,
292 GLuint count,
293 GLuint flags)
294 {
295 if (HAVE_POLYGONS) {
296 LOCAL_VARS;
297 GLuint j, nr;
298 const unsigned dmasz = GET_SUBSEQUENT_VB_MAX_VERTS();
299 unsigned currentsz;
300
301 INIT(GL_POLYGON);
302
303 currentsz = GET_CURRENT_VB_MAX_VERTS();
304 if (currentsz < 8) {
305 currentsz = dmasz;
306 }
307
308 for (j = 1; j + 1 < count; j += nr - 2) {
309 void *tmp;
310 nr = MIN2(currentsz, count - j + 1);
311 tmp = ALLOC_VERTS(nr);
312 tmp = TAG(emit_verts)(ctx, start, 1, tmp);
313 tmp = TAG(emit_verts)(ctx, start + j, nr - 1, tmp);
314 (void) tmp;
315 currentsz = dmasz;
316 }
317
318 FLUSH();
319 } else if (ctx->Light.ShadeModel == GL_SMOOTH ||
320 ctx->Light.ProvokingVertex == GL_FIRST_VERTEX_CONVENTION) {
321 TAG(render_tri_fan_verts)( ctx, start, count, flags );
322 } else {
323 unreachable("Cannot draw primitive; validate_render should have "
324 "prevented this");
325 }
326 }
327
TAG(render_quad_strip_verts)328 static void TAG(render_quad_strip_verts)(struct gl_context *ctx,
329 GLuint start,
330 GLuint count,
331 GLuint flags)
332 {
333 GLuint j, nr;
334
335 if (ctx->Light.ShadeModel == GL_SMOOTH) {
336 LOCAL_VARS;
337 const unsigned dmasz = GET_SUBSEQUENT_VB_MAX_VERTS() & ~1;
338 unsigned currentsz;
339
340 /* Emit smooth-shaded quadstrips as tristrips:
341 */
342 FLUSH();
343 INIT(GL_TRIANGLE_STRIP);
344
345 /* Emit whole number of quads in total, and in each buffer.
346 */
347 currentsz = GET_CURRENT_VB_MAX_VERTS();
348 currentsz -= currentsz & 1;
349 count -= count & 1;
350
351 if (currentsz < 8)
352 currentsz = dmasz;
353
354 for (j = 0; j + 3 < count; j += nr - 2) {
355 nr = MIN2(currentsz, count - j);
356 TAG(emit_verts)(ctx, start + j, nr, ALLOC_VERTS(nr));
357 currentsz = dmasz;
358 }
359
360 FLUSH();
361 } else {
362 unreachable("Cannot draw primitive; validate_render should have "
363 "prevented this");
364 }
365 }
366
367
TAG(render_quads_verts)368 static void TAG(render_quads_verts)(struct gl_context *ctx,
369 GLuint start,
370 GLuint count,
371 GLuint flags)
372 {
373 if (ctx->Light.ShadeModel == GL_SMOOTH ||
374 ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION) {
375 LOCAL_VARS;
376 GLuint j;
377
378 /* Emit whole number of quads in total. */
379 count -= count & 3;
380
381 /* Hardware doesn't have a quad primitive type -- try to simulate it using
382 * triangle primitive. This is a win for gears, but is it useful in the
383 * broader world?
384 */
385 INIT(GL_TRIANGLES);
386
387 for (j = 0; j + 3 < count; j += 4) {
388 void *tmp = ALLOC_VERTS(6);
389 /* Send v0, v1, v3
390 */
391 tmp = EMIT_VERTS(ctx, start + j, 2, tmp);
392 tmp = EMIT_VERTS(ctx, start + j + 3, 1, tmp);
393 /* Send v1, v2, v3
394 */
395 tmp = EMIT_VERTS(ctx, start + j + 1, 3, tmp);
396 (void) tmp;
397 }
398 } else {
399 unreachable("Cannot draw primitive");
400 }
401 }
402
TAG(render_noop)403 static void TAG(render_noop)(struct gl_context *ctx,
404 GLuint start,
405 GLuint count,
406 GLuint flags)
407 {
408 (void) ctx;
409 (void) start;
410 (void) count;
411 (void) flags;
412 }
413
414 static const tnl_render_func TAG(render_tab_verts)[GL_POLYGON+2] =
415 {
416 TAG(render_points_verts),
417 TAG(render_lines_verts),
418 TAG(render_line_loop_verts),
419 TAG(render_line_strip_verts),
420 TAG(render_triangles_verts),
421 TAG(render_tri_strip_verts),
422 TAG(render_tri_fan_verts),
423 TAG(render_quads_verts),
424 TAG(render_quad_strip_verts),
425 TAG(render_poly_verts),
426 TAG(render_noop),
427 };
428
429 /* Pre-check the primitives in the VB to prevent the need for
430 * fallbacks later on.
431 */
TAG(validate_render)432 static bool TAG(validate_render)(struct gl_context *ctx,
433 struct vertex_buffer *VB)
434 {
435 GLint i;
436
437 if (VB->ClipOrMask & ~CLIP_CULL_BIT)
438 return false;
439
440 if (VB->Elts)
441 return false;
442
443 for (i = 0 ; i < VB->PrimitiveCount ; i++) {
444 GLuint prim = VB->Primitive[i].mode;
445 GLuint count = VB->Primitive[i].count;
446 bool ok = false;
447
448 if (!count)
449 continue;
450
451 switch (prim & PRIM_MODE_MASK) {
452 case GL_POINTS:
453 ok = HAVE_POINTS;
454 break;
455 case GL_LINES:
456 case GL_LINE_STRIP:
457 case GL_LINE_LOOP:
458 ok = !ctx->Line.StippleFlag;
459 break;
460 case GL_TRIANGLES:
461 case GL_TRIANGLE_STRIP:
462 case GL_TRIANGLE_FAN:
463 ok = true;
464 break;
465 case GL_POLYGON:
466 ok = (HAVE_POLYGONS) || ctx->Light.ShadeModel == GL_SMOOTH ||
467 ctx->Light.ProvokingVertex == GL_FIRST_VERTEX_CONVENTION;
468 break;
469 case GL_QUAD_STRIP:
470 ok = VB->Elts || ctx->Light.ShadeModel == GL_SMOOTH;
471 break;
472 case GL_QUADS:
473 ok = ctx->Light.ShadeModel == GL_SMOOTH ||
474 ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION;
475 break;
476 default:
477 break;
478 }
479
480 if (!ok) {
481 /* fprintf(stderr, "not ok %s\n", _mesa_enum_to_string(prim & PRIM_MODE_MASK)); */
482 return false;
483 }
484 }
485
486 return true;
487 }
488
489