1 /************************************************************************** 2 * 3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * 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 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * 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 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 /** 29 * Interface between 'draw' module's output and the llvmpipe rasterizer/setup 30 * code. When the 'draw' module has finished filling a vertex buffer, the 31 * draw_arrays() functions below will be called. Loop over the vertices and 32 * call the point/line/tri setup functions. 33 * 34 * Authors 35 * Brian Paul 36 */ 37 38 39 #include "lp_setup_context.h" 40 #include "draw/draw_vbuf.h" 41 #include "draw/draw_vertex.h" 42 #include "util/u_memory.h" 43 44 45 #define LP_MAX_VBUF_INDEXES 1024 46 #define LP_MAX_VBUF_SIZE 4096 47 48 49 50 /** cast wrapper */ 51 static struct lp_setup_context * 52 lp_setup_context(struct vbuf_render *vbr) 53 { 54 return (struct lp_setup_context *) vbr; 55 } 56 57 58 59 static const struct vertex_info * 60 lp_setup_get_vertex_info(struct vbuf_render *vbr) 61 { 62 struct lp_setup_context *setup = lp_setup_context(vbr); 63 64 /* Vertex size/info depends on the latest state. 65 * The draw module may have issued additional state-change commands. 66 */ 67 lp_setup_update_state(setup, FALSE); 68 69 return setup->vertex_info; 70 } 71 72 73 static boolean 74 lp_setup_allocate_vertices(struct vbuf_render *vbr, 75 ushort vertex_size, ushort nr_vertices) 76 { 77 struct lp_setup_context *setup = lp_setup_context(vbr); 78 unsigned size = vertex_size * nr_vertices; 79 80 if (setup->vertex_buffer_size < size) { 81 align_free(setup->vertex_buffer); 82 setup->vertex_buffer = align_malloc(size, 16); 83 setup->vertex_buffer_size = size; 84 } 85 86 setup->vertex_size = vertex_size; 87 setup->nr_vertices = nr_vertices; 88 89 return setup->vertex_buffer != NULL; 90 } 91 92 static void 93 lp_setup_release_vertices(struct vbuf_render *vbr) 94 { 95 /* keep the old allocation for next time */ 96 } 97 98 static void * 99 lp_setup_map_vertices(struct vbuf_render *vbr) 100 { 101 struct lp_setup_context *setup = lp_setup_context(vbr); 102 return setup->vertex_buffer; 103 } 104 105 static void 106 lp_setup_unmap_vertices(struct vbuf_render *vbr, 107 ushort min_index, 108 ushort max_index ) 109 { 110 struct lp_setup_context *setup = lp_setup_context(vbr); 111 assert( setup->vertex_buffer_size >= (max_index+1) * setup->vertex_size ); 112 /* do nothing */ 113 } 114 115 116 static void 117 lp_setup_set_primitive(struct vbuf_render *vbr, unsigned prim) 118 { 119 lp_setup_context(vbr)->prim = prim; 120 } 121 122 typedef const float (*const_float4_ptr)[4]; 123 124 static INLINE const_float4_ptr get_vert( const void *vertex_buffer, 125 int index, 126 int stride ) 127 { 128 return (const_float4_ptr)((char *)vertex_buffer + index * stride); 129 } 130 131 /** 132 * draw elements / indexed primitives 133 */ 134 static void 135 lp_setup_draw_elements(struct vbuf_render *vbr, const ushort *indices, uint nr) 136 { 137 struct lp_setup_context *setup = lp_setup_context(vbr); 138 const unsigned stride = setup->vertex_info->size * sizeof(float); 139 const void *vertex_buffer = setup->vertex_buffer; 140 const boolean flatshade_first = setup->flatshade_first; 141 unsigned i; 142 143 assert(setup->setup.variant); 144 145 if (!lp_setup_update_state(setup, TRUE)) 146 return; 147 148 switch (setup->prim) { 149 case PIPE_PRIM_POINTS: 150 for (i = 0; i < nr; i++) { 151 setup->point( setup, 152 get_vert(vertex_buffer, indices[i-0], stride) ); 153 } 154 break; 155 156 case PIPE_PRIM_LINES: 157 for (i = 1; i < nr; i += 2) { 158 setup->line( setup, 159 get_vert(vertex_buffer, indices[i-1], stride), 160 get_vert(vertex_buffer, indices[i-0], stride) ); 161 } 162 break; 163 164 case PIPE_PRIM_LINE_STRIP: 165 for (i = 1; i < nr; i ++) { 166 setup->line( setup, 167 get_vert(vertex_buffer, indices[i-1], stride), 168 get_vert(vertex_buffer, indices[i-0], stride) ); 169 } 170 break; 171 172 case PIPE_PRIM_LINE_LOOP: 173 for (i = 1; i < nr; i ++) { 174 setup->line( setup, 175 get_vert(vertex_buffer, indices[i-1], stride), 176 get_vert(vertex_buffer, indices[i-0], stride) ); 177 } 178 if (nr) { 179 setup->line( setup, 180 get_vert(vertex_buffer, indices[nr-1], stride), 181 get_vert(vertex_buffer, indices[0], stride) ); 182 } 183 break; 184 185 case PIPE_PRIM_TRIANGLES: 186 for (i = 2; i < nr; i += 3) { 187 setup->triangle( setup, 188 get_vert(vertex_buffer, indices[i-2], stride), 189 get_vert(vertex_buffer, indices[i-1], stride), 190 get_vert(vertex_buffer, indices[i-0], stride) ); 191 } 192 break; 193 194 case PIPE_PRIM_TRIANGLE_STRIP: 195 if (flatshade_first) { 196 for (i = 2; i < nr; i += 1) { 197 /* emit first triangle vertex as first triangle vertex */ 198 setup->triangle( setup, 199 get_vert(vertex_buffer, indices[i-2], stride), 200 get_vert(vertex_buffer, indices[i+(i&1)-1], stride), 201 get_vert(vertex_buffer, indices[i-(i&1)], stride) ); 202 203 } 204 } 205 else { 206 for (i = 2; i < nr; i += 1) { 207 /* emit last triangle vertex as last triangle vertex */ 208 setup->triangle( setup, 209 get_vert(vertex_buffer, indices[i+(i&1)-2], stride), 210 get_vert(vertex_buffer, indices[i-(i&1)-1], stride), 211 get_vert(vertex_buffer, indices[i-0], stride) ); 212 } 213 } 214 break; 215 216 case PIPE_PRIM_TRIANGLE_FAN: 217 if (flatshade_first) { 218 for (i = 2; i < nr; i += 1) { 219 /* emit first non-spoke vertex as first vertex */ 220 setup->triangle( setup, 221 get_vert(vertex_buffer, indices[i-1], stride), 222 get_vert(vertex_buffer, indices[i-0], stride), 223 get_vert(vertex_buffer, indices[0], stride) ); 224 } 225 } 226 else { 227 for (i = 2; i < nr; i += 1) { 228 /* emit last non-spoke vertex as last vertex */ 229 setup->triangle( setup, 230 get_vert(vertex_buffer, indices[0], stride), 231 get_vert(vertex_buffer, indices[i-1], stride), 232 get_vert(vertex_buffer, indices[i-0], stride) ); 233 } 234 } 235 break; 236 237 case PIPE_PRIM_QUADS: 238 /* GL quads don't follow provoking vertex convention */ 239 if (flatshade_first) { 240 /* emit last quad vertex as first triangle vertex */ 241 for (i = 3; i < nr; i += 4) { 242 setup->triangle( setup, 243 get_vert(vertex_buffer, indices[i-0], stride), 244 get_vert(vertex_buffer, indices[i-3], stride), 245 get_vert(vertex_buffer, indices[i-2], stride) ); 246 247 setup->triangle( setup, 248 get_vert(vertex_buffer, indices[i-0], stride), 249 get_vert(vertex_buffer, indices[i-2], stride), 250 get_vert(vertex_buffer, indices[i-1], stride) ); 251 } 252 } 253 else { 254 /* emit last quad vertex as last triangle vertex */ 255 for (i = 3; i < nr; i += 4) { 256 setup->triangle( setup, 257 get_vert(vertex_buffer, indices[i-3], stride), 258 get_vert(vertex_buffer, indices[i-2], stride), 259 get_vert(vertex_buffer, indices[i-0], stride) ); 260 261 setup->triangle( setup, 262 get_vert(vertex_buffer, indices[i-2], stride), 263 get_vert(vertex_buffer, indices[i-1], stride), 264 get_vert(vertex_buffer, indices[i-0], stride) ); 265 } 266 } 267 break; 268 269 case PIPE_PRIM_QUAD_STRIP: 270 /* GL quad strips don't follow provoking vertex convention */ 271 if (flatshade_first) { 272 /* emit last quad vertex as first triangle vertex */ 273 for (i = 3; i < nr; i += 2) { 274 setup->triangle( setup, 275 get_vert(vertex_buffer, indices[i-0], stride), 276 get_vert(vertex_buffer, indices[i-3], stride), 277 get_vert(vertex_buffer, indices[i-2], stride) ); 278 setup->triangle( setup, 279 get_vert(vertex_buffer, indices[i-0], stride), 280 get_vert(vertex_buffer, indices[i-1], stride), 281 get_vert(vertex_buffer, indices[i-3], stride) ); 282 } 283 } 284 else { 285 /* emit last quad vertex as last triangle vertex */ 286 for (i = 3; i < nr; i += 2) { 287 setup->triangle( setup, 288 get_vert(vertex_buffer, indices[i-3], stride), 289 get_vert(vertex_buffer, indices[i-2], stride), 290 get_vert(vertex_buffer, indices[i-0], stride) ); 291 setup->triangle( setup, 292 get_vert(vertex_buffer, indices[i-1], stride), 293 get_vert(vertex_buffer, indices[i-3], stride), 294 get_vert(vertex_buffer, indices[i-0], stride) ); 295 } 296 } 297 break; 298 299 case PIPE_PRIM_POLYGON: 300 /* Almost same as tri fan but the _first_ vertex specifies the flat 301 * shading color. 302 */ 303 if (flatshade_first) { 304 /* emit first polygon vertex as first triangle vertex */ 305 for (i = 2; i < nr; i += 1) { 306 setup->triangle( setup, 307 get_vert(vertex_buffer, indices[0], stride), 308 get_vert(vertex_buffer, indices[i-1], stride), 309 get_vert(vertex_buffer, indices[i-0], stride) ); 310 } 311 } 312 else { 313 /* emit first polygon vertex as last triangle vertex */ 314 for (i = 2; i < nr; i += 1) { 315 setup->triangle( setup, 316 get_vert(vertex_buffer, indices[i-1], stride), 317 get_vert(vertex_buffer, indices[i-0], stride), 318 get_vert(vertex_buffer, indices[0], stride) ); 319 } 320 } 321 break; 322 323 default: 324 assert(0); 325 } 326 } 327 328 329 /** 330 * This function is hit when the draw module is working in pass-through mode. 331 * It's up to us to convert the vertex array into point/line/tri prims. 332 */ 333 static void 334 lp_setup_draw_arrays(struct vbuf_render *vbr, uint start, uint nr) 335 { 336 struct lp_setup_context *setup = lp_setup_context(vbr); 337 const unsigned stride = setup->vertex_info->size * sizeof(float); 338 const void *vertex_buffer = 339 (void *) get_vert(setup->vertex_buffer, start, stride); 340 const boolean flatshade_first = setup->flatshade_first; 341 unsigned i; 342 343 if (!lp_setup_update_state(setup, TRUE)) 344 return; 345 346 switch (setup->prim) { 347 case PIPE_PRIM_POINTS: 348 for (i = 0; i < nr; i++) { 349 setup->point( setup, 350 get_vert(vertex_buffer, i-0, stride) ); 351 } 352 break; 353 354 case PIPE_PRIM_LINES: 355 for (i = 1; i < nr; i += 2) { 356 setup->line( setup, 357 get_vert(vertex_buffer, i-1, stride), 358 get_vert(vertex_buffer, i-0, stride) ); 359 } 360 break; 361 362 case PIPE_PRIM_LINE_STRIP: 363 for (i = 1; i < nr; i ++) { 364 setup->line( setup, 365 get_vert(vertex_buffer, i-1, stride), 366 get_vert(vertex_buffer, i-0, stride) ); 367 } 368 break; 369 370 case PIPE_PRIM_LINE_LOOP: 371 for (i = 1; i < nr; i ++) { 372 setup->line( setup, 373 get_vert(vertex_buffer, i-1, stride), 374 get_vert(vertex_buffer, i-0, stride) ); 375 } 376 if (nr) { 377 setup->line( setup, 378 get_vert(vertex_buffer, nr-1, stride), 379 get_vert(vertex_buffer, 0, stride) ); 380 } 381 break; 382 383 case PIPE_PRIM_TRIANGLES: 384 for (i = 2; i < nr; i += 3) { 385 setup->triangle( setup, 386 get_vert(vertex_buffer, i-2, stride), 387 get_vert(vertex_buffer, i-1, stride), 388 get_vert(vertex_buffer, i-0, stride) ); 389 } 390 break; 391 392 case PIPE_PRIM_TRIANGLE_STRIP: 393 if (flatshade_first) { 394 for (i = 2; i < nr; i++) { 395 /* emit first triangle vertex as first triangle vertex */ 396 setup->triangle( setup, 397 get_vert(vertex_buffer, i-2, stride), 398 get_vert(vertex_buffer, i+(i&1)-1, stride), 399 get_vert(vertex_buffer, i-(i&1), stride) ); 400 } 401 } 402 else { 403 for (i = 2; i < nr; i++) { 404 /* emit last triangle vertex as last triangle vertex */ 405 setup->triangle( setup, 406 get_vert(vertex_buffer, i+(i&1)-2, stride), 407 get_vert(vertex_buffer, i-(i&1)-1, stride), 408 get_vert(vertex_buffer, i-0, stride) ); 409 } 410 } 411 break; 412 413 case PIPE_PRIM_TRIANGLE_FAN: 414 if (flatshade_first) { 415 for (i = 2; i < nr; i += 1) { 416 /* emit first non-spoke vertex as first vertex */ 417 setup->triangle( setup, 418 get_vert(vertex_buffer, i-1, stride), 419 get_vert(vertex_buffer, i-0, stride), 420 get_vert(vertex_buffer, 0, stride) ); 421 } 422 } 423 else { 424 for (i = 2; i < nr; i += 1) { 425 /* emit last non-spoke vertex as last vertex */ 426 setup->triangle( setup, 427 get_vert(vertex_buffer, 0, stride), 428 get_vert(vertex_buffer, i-1, stride), 429 get_vert(vertex_buffer, i-0, stride) ); 430 } 431 } 432 break; 433 434 case PIPE_PRIM_QUADS: 435 /* GL quads don't follow provoking vertex convention */ 436 if (flatshade_first) { 437 /* emit last quad vertex as first triangle vertex */ 438 for (i = 3; i < nr; i += 4) { 439 setup->triangle( setup, 440 get_vert(vertex_buffer, i-0, stride), 441 get_vert(vertex_buffer, i-3, stride), 442 get_vert(vertex_buffer, i-2, stride) ); 443 setup->triangle( setup, 444 get_vert(vertex_buffer, i-0, stride), 445 get_vert(vertex_buffer, i-2, stride), 446 get_vert(vertex_buffer, i-1, stride) ); 447 } 448 } 449 else { 450 /* emit last quad vertex as last triangle vertex */ 451 for (i = 3; i < nr; i += 4) { 452 setup->triangle( setup, 453 get_vert(vertex_buffer, i-3, stride), 454 get_vert(vertex_buffer, i-2, stride), 455 get_vert(vertex_buffer, i-0, stride) ); 456 setup->triangle( setup, 457 get_vert(vertex_buffer, i-2, stride), 458 get_vert(vertex_buffer, i-1, stride), 459 get_vert(vertex_buffer, i-0, stride) ); 460 } 461 } 462 break; 463 464 case PIPE_PRIM_QUAD_STRIP: 465 /* GL quad strips don't follow provoking vertex convention */ 466 if (flatshade_first) { 467 /* emit last quad vertex as first triangle vertex */ 468 for (i = 3; i < nr; i += 2) { 469 setup->triangle( setup, 470 get_vert(vertex_buffer, i-0, stride), 471 get_vert(vertex_buffer, i-3, stride), 472 get_vert(vertex_buffer, i-2, stride) ); 473 setup->triangle( setup, 474 get_vert(vertex_buffer, i-0, stride), 475 get_vert(vertex_buffer, i-1, stride), 476 get_vert(vertex_buffer, i-3, stride) ); 477 } 478 } 479 else { 480 /* emit last quad vertex as last triangle vertex */ 481 for (i = 3; i < nr; i += 2) { 482 setup->triangle( setup, 483 get_vert(vertex_buffer, i-3, stride), 484 get_vert(vertex_buffer, i-2, stride), 485 get_vert(vertex_buffer, i-0, stride) ); 486 setup->triangle( setup, 487 get_vert(vertex_buffer, i-1, stride), 488 get_vert(vertex_buffer, i-3, stride), 489 get_vert(vertex_buffer, i-0, stride) ); 490 } 491 } 492 break; 493 494 case PIPE_PRIM_POLYGON: 495 /* Almost same as tri fan but the _first_ vertex specifies the flat 496 * shading color. 497 */ 498 if (flatshade_first) { 499 /* emit first polygon vertex as first triangle vertex */ 500 for (i = 2; i < nr; i += 1) { 501 setup->triangle( setup, 502 get_vert(vertex_buffer, 0, stride), 503 get_vert(vertex_buffer, i-1, stride), 504 get_vert(vertex_buffer, i-0, stride) ); 505 } 506 } 507 else { 508 /* emit first polygon vertex as last triangle vertex */ 509 for (i = 2; i < nr; i += 1) { 510 setup->triangle( setup, 511 get_vert(vertex_buffer, i-1, stride), 512 get_vert(vertex_buffer, i-0, stride), 513 get_vert(vertex_buffer, 0, stride) ); 514 } 515 } 516 break; 517 518 default: 519 assert(0); 520 } 521 } 522 523 524 525 static void 526 lp_setup_vbuf_destroy(struct vbuf_render *vbr) 527 { 528 struct lp_setup_context *setup = lp_setup_context(vbr); 529 if (setup->vertex_buffer) { 530 align_free(setup->vertex_buffer); 531 setup->vertex_buffer = NULL; 532 } 533 lp_setup_destroy(setup); 534 } 535 536 537 /** 538 * Create the post-transform vertex handler for the given context. 539 */ 540 void 541 lp_setup_init_vbuf(struct lp_setup_context *setup) 542 { 543 setup->base.max_indices = LP_MAX_VBUF_INDEXES; 544 setup->base.max_vertex_buffer_bytes = LP_MAX_VBUF_SIZE; 545 546 setup->base.get_vertex_info = lp_setup_get_vertex_info; 547 setup->base.allocate_vertices = lp_setup_allocate_vertices; 548 setup->base.map_vertices = lp_setup_map_vertices; 549 setup->base.unmap_vertices = lp_setup_unmap_vertices; 550 setup->base.set_primitive = lp_setup_set_primitive; 551 setup->base.draw_elements = lp_setup_draw_elements; 552 setup->base.draw_arrays = lp_setup_draw_arrays; 553 setup->base.release_vertices = lp_setup_release_vertices; 554 setup->base.destroy = lp_setup_vbuf_destroy; 555 } 556