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 (at) 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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