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 softpipe 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 "sp_context.h" 40 #include "sp_setup.h" 41 #include "sp_state.h" 42 #include "sp_prim_vbuf.h" 43 #include "draw/draw_context.h" 44 #include "draw/draw_vbuf.h" 45 #include "util/u_memory.h" 46 #include "util/u_prim.h" 47 48 49 #define SP_MAX_VBUF_INDEXES 1024 50 #define SP_MAX_VBUF_SIZE 4096 51 52 typedef const float (*cptrf4)[4]; 53 54 /** 55 * Subclass of vbuf_render. 56 */ 57 struct softpipe_vbuf_render 58 { 59 struct vbuf_render base; 60 struct softpipe_context *softpipe; 61 struct setup_context *setup; 62 63 uint prim; 64 uint vertex_size; 65 uint nr_vertices; 66 uint vertex_buffer_size; 67 void *vertex_buffer; 68 }; 69 70 71 /** cast wrapper */ 72 static struct softpipe_vbuf_render * 73 softpipe_vbuf_render(struct vbuf_render *vbr) 74 { 75 return (struct softpipe_vbuf_render *) vbr; 76 } 77 78 79 /** This tells the draw module about our desired vertex layout */ 80 static const struct vertex_info * 81 sp_vbuf_get_vertex_info(struct vbuf_render *vbr) 82 { 83 struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); 84 return softpipe_get_vbuf_vertex_info(cvbr->softpipe); 85 } 86 87 88 static boolean 89 sp_vbuf_allocate_vertices(struct vbuf_render *vbr, 90 ushort vertex_size, ushort nr_vertices) 91 { 92 struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); 93 unsigned size = vertex_size * nr_vertices; 94 95 if (cvbr->vertex_buffer_size < size) { 96 align_free(cvbr->vertex_buffer); 97 cvbr->vertex_buffer = align_malloc(size, 16); 98 cvbr->vertex_buffer_size = size; 99 } 100 101 cvbr->vertex_size = vertex_size; 102 cvbr->nr_vertices = nr_vertices; 103 104 return cvbr->vertex_buffer != NULL; 105 } 106 107 108 static void 109 sp_vbuf_release_vertices(struct vbuf_render *vbr) 110 { 111 /* keep the old allocation for next time */ 112 } 113 114 115 static void * 116 sp_vbuf_map_vertices(struct vbuf_render *vbr) 117 { 118 struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); 119 return cvbr->vertex_buffer; 120 } 121 122 123 static void 124 sp_vbuf_unmap_vertices(struct vbuf_render *vbr, 125 ushort min_index, 126 ushort max_index ) 127 { 128 struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); 129 assert( cvbr->vertex_buffer_size >= (max_index+1) * cvbr->vertex_size ); 130 (void) cvbr; 131 /* do nothing */ 132 } 133 134 135 static void 136 sp_vbuf_set_primitive(struct vbuf_render *vbr, unsigned prim) 137 { 138 struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); 139 struct setup_context *setup_ctx = cvbr->setup; 140 141 sp_setup_prepare( setup_ctx ); 142 143 cvbr->softpipe->reduced_prim = u_reduced_prim(prim); 144 cvbr->prim = prim; 145 } 146 147 148 static INLINE cptrf4 get_vert( const void *vertex_buffer, 149 int index, 150 int stride ) 151 { 152 return (cptrf4)((char *)vertex_buffer + index * stride); 153 } 154 155 156 /** 157 * draw elements / indexed primitives 158 */ 159 static void 160 sp_vbuf_draw_elements(struct vbuf_render *vbr, const ushort *indices, uint nr) 161 { 162 struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); 163 struct softpipe_context *softpipe = cvbr->softpipe; 164 const unsigned stride = softpipe->vertex_info_vbuf.size * sizeof(float); 165 const void *vertex_buffer = cvbr->vertex_buffer; 166 struct setup_context *setup = cvbr->setup; 167 const boolean flatshade_first = softpipe->rasterizer->flatshade_first; 168 unsigned i; 169 170 switch (cvbr->prim) { 171 case PIPE_PRIM_POINTS: 172 for (i = 0; i < nr; i++) { 173 sp_setup_point( setup, 174 get_vert(vertex_buffer, indices[i-0], stride) ); 175 } 176 break; 177 178 case PIPE_PRIM_LINES: 179 for (i = 1; i < nr; i += 2) { 180 sp_setup_line( setup, 181 get_vert(vertex_buffer, indices[i-1], stride), 182 get_vert(vertex_buffer, indices[i-0], stride) ); 183 } 184 break; 185 186 case PIPE_PRIM_LINE_STRIP: 187 for (i = 1; i < nr; i ++) { 188 sp_setup_line( setup, 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_LINE_LOOP: 195 for (i = 1; i < nr; i ++) { 196 sp_setup_line( setup, 197 get_vert(vertex_buffer, indices[i-1], stride), 198 get_vert(vertex_buffer, indices[i-0], stride) ); 199 } 200 if (nr) { 201 sp_setup_line( setup, 202 get_vert(vertex_buffer, indices[nr-1], stride), 203 get_vert(vertex_buffer, indices[0], stride) ); 204 } 205 break; 206 207 case PIPE_PRIM_TRIANGLES: 208 for (i = 2; i < nr; i += 3) { 209 sp_setup_tri( setup, 210 get_vert(vertex_buffer, indices[i-2], stride), 211 get_vert(vertex_buffer, indices[i-1], stride), 212 get_vert(vertex_buffer, indices[i-0], stride) ); 213 } 214 break; 215 216 case PIPE_PRIM_TRIANGLE_STRIP: 217 if (flatshade_first) { 218 for (i = 2; i < nr; i += 1) { 219 /* emit first triangle vertex as first triangle vertex */ 220 sp_setup_tri( setup, 221 get_vert(vertex_buffer, indices[i-2], stride), 222 get_vert(vertex_buffer, indices[i+(i&1)-1], stride), 223 get_vert(vertex_buffer, indices[i-(i&1)], stride) ); 224 225 } 226 } 227 else { 228 for (i = 2; i < nr; i += 1) { 229 /* emit last triangle vertex as last triangle vertex */ 230 sp_setup_tri( setup, 231 get_vert(vertex_buffer, indices[i+(i&1)-2], stride), 232 get_vert(vertex_buffer, indices[i-(i&1)-1], stride), 233 get_vert(vertex_buffer, indices[i-0], stride) ); 234 } 235 } 236 break; 237 238 case PIPE_PRIM_TRIANGLE_FAN: 239 if (flatshade_first) { 240 for (i = 2; i < nr; i += 1) { 241 /* emit first non-spoke vertex as first vertex */ 242 sp_setup_tri( setup, 243 get_vert(vertex_buffer, indices[i-1], stride), 244 get_vert(vertex_buffer, indices[i-0], stride), 245 get_vert(vertex_buffer, indices[0], stride) ); 246 } 247 } 248 else { 249 for (i = 2; i < nr; i += 1) { 250 /* emit last non-spoke vertex as last vertex */ 251 sp_setup_tri( setup, 252 get_vert(vertex_buffer, indices[0], stride), 253 get_vert(vertex_buffer, indices[i-1], stride), 254 get_vert(vertex_buffer, indices[i-0], stride) ); 255 } 256 } 257 break; 258 259 case PIPE_PRIM_QUADS: 260 /* GL quads don't follow provoking vertex convention */ 261 if (flatshade_first) { 262 /* emit last quad vertex as first triangle vertex */ 263 for (i = 3; i < nr; i += 4) { 264 sp_setup_tri( setup, 265 get_vert(vertex_buffer, indices[i-0], stride), 266 get_vert(vertex_buffer, indices[i-3], stride), 267 get_vert(vertex_buffer, indices[i-2], stride) ); 268 269 sp_setup_tri( setup, 270 get_vert(vertex_buffer, indices[i-0], stride), 271 get_vert(vertex_buffer, indices[i-2], stride), 272 get_vert(vertex_buffer, indices[i-1], stride) ); 273 } 274 } 275 else { 276 /* emit last quad vertex as last triangle vertex */ 277 for (i = 3; i < nr; i += 4) { 278 sp_setup_tri( setup, 279 get_vert(vertex_buffer, indices[i-3], stride), 280 get_vert(vertex_buffer, indices[i-2], stride), 281 get_vert(vertex_buffer, indices[i-0], stride) ); 282 283 sp_setup_tri( setup, 284 get_vert(vertex_buffer, indices[i-2], stride), 285 get_vert(vertex_buffer, indices[i-1], stride), 286 get_vert(vertex_buffer, indices[i-0], stride) ); 287 } 288 } 289 break; 290 291 case PIPE_PRIM_QUAD_STRIP: 292 /* GL quad strips don't follow provoking vertex convention */ 293 if (flatshade_first) { 294 /* emit last quad vertex as first triangle vertex */ 295 for (i = 3; i < nr; i += 2) { 296 sp_setup_tri( setup, 297 get_vert(vertex_buffer, indices[i-0], stride), 298 get_vert(vertex_buffer, indices[i-3], stride), 299 get_vert(vertex_buffer, indices[i-2], stride) ); 300 sp_setup_tri( setup, 301 get_vert(vertex_buffer, indices[i-0], stride), 302 get_vert(vertex_buffer, indices[i-1], stride), 303 get_vert(vertex_buffer, indices[i-3], stride) ); 304 } 305 } 306 else { 307 /* emit last quad vertex as last triangle vertex */ 308 for (i = 3; i < nr; i += 2) { 309 sp_setup_tri( setup, 310 get_vert(vertex_buffer, indices[i-3], stride), 311 get_vert(vertex_buffer, indices[i-2], stride), 312 get_vert(vertex_buffer, indices[i-0], stride) ); 313 sp_setup_tri( setup, 314 get_vert(vertex_buffer, indices[i-1], stride), 315 get_vert(vertex_buffer, indices[i-3], stride), 316 get_vert(vertex_buffer, indices[i-0], stride) ); 317 } 318 } 319 break; 320 321 case PIPE_PRIM_POLYGON: 322 /* Almost same as tri fan but the _first_ vertex specifies the flat 323 * shading color. 324 */ 325 if (flatshade_first) { 326 /* emit first polygon vertex as first triangle vertex */ 327 for (i = 2; i < nr; i += 1) { 328 sp_setup_tri( setup, 329 get_vert(vertex_buffer, indices[0], stride), 330 get_vert(vertex_buffer, indices[i-1], stride), 331 get_vert(vertex_buffer, indices[i-0], stride) ); 332 } 333 } 334 else { 335 /* emit first polygon vertex as last triangle vertex */ 336 for (i = 2; i < nr; i += 1) { 337 sp_setup_tri( setup, 338 get_vert(vertex_buffer, indices[i-1], stride), 339 get_vert(vertex_buffer, indices[i-0], stride), 340 get_vert(vertex_buffer, indices[0], stride) ); 341 } 342 } 343 break; 344 345 default: 346 assert(0); 347 } 348 } 349 350 351 /** 352 * This function is hit when the draw module is working in pass-through mode. 353 * It's up to us to convert the vertex array into point/line/tri prims. 354 */ 355 static void 356 sp_vbuf_draw_arrays(struct vbuf_render *vbr, uint start, uint nr) 357 { 358 struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); 359 struct softpipe_context *softpipe = cvbr->softpipe; 360 struct setup_context *setup = cvbr->setup; 361 const unsigned stride = softpipe->vertex_info_vbuf.size * sizeof(float); 362 const void *vertex_buffer = 363 (void *) get_vert(cvbr->vertex_buffer, start, stride); 364 const boolean flatshade_first = softpipe->rasterizer->flatshade_first; 365 unsigned i; 366 367 switch (cvbr->prim) { 368 case PIPE_PRIM_POINTS: 369 for (i = 0; i < nr; i++) { 370 sp_setup_point( setup, 371 get_vert(vertex_buffer, i-0, stride) ); 372 } 373 break; 374 375 case PIPE_PRIM_LINES: 376 for (i = 1; i < nr; i += 2) { 377 sp_setup_line( setup, 378 get_vert(vertex_buffer, i-1, stride), 379 get_vert(vertex_buffer, i-0, stride) ); 380 } 381 break; 382 383 case PIPE_PRIM_LINE_STRIP: 384 for (i = 1; i < nr; i ++) { 385 sp_setup_line( setup, 386 get_vert(vertex_buffer, i-1, stride), 387 get_vert(vertex_buffer, i-0, stride) ); 388 } 389 break; 390 391 case PIPE_PRIM_LINE_LOOP: 392 for (i = 1; i < nr; i ++) { 393 sp_setup_line( setup, 394 get_vert(vertex_buffer, i-1, stride), 395 get_vert(vertex_buffer, i-0, stride) ); 396 } 397 if (nr) { 398 sp_setup_line( setup, 399 get_vert(vertex_buffer, nr-1, stride), 400 get_vert(vertex_buffer, 0, stride) ); 401 } 402 break; 403 404 case PIPE_PRIM_TRIANGLES: 405 for (i = 2; i < nr; i += 3) { 406 sp_setup_tri( setup, 407 get_vert(vertex_buffer, i-2, stride), 408 get_vert(vertex_buffer, i-1, stride), 409 get_vert(vertex_buffer, i-0, stride) ); 410 } 411 break; 412 413 case PIPE_PRIM_TRIANGLE_STRIP: 414 if (flatshade_first) { 415 for (i = 2; i < nr; i++) { 416 /* emit first triangle vertex as first triangle vertex */ 417 sp_setup_tri( setup, 418 get_vert(vertex_buffer, i-2, stride), 419 get_vert(vertex_buffer, i+(i&1)-1, stride), 420 get_vert(vertex_buffer, i-(i&1), stride) ); 421 } 422 } 423 else { 424 for (i = 2; i < nr; i++) { 425 /* emit last triangle vertex as last triangle vertex */ 426 sp_setup_tri( setup, 427 get_vert(vertex_buffer, i+(i&1)-2, stride), 428 get_vert(vertex_buffer, i-(i&1)-1, stride), 429 get_vert(vertex_buffer, i-0, stride) ); 430 } 431 } 432 break; 433 434 case PIPE_PRIM_TRIANGLE_FAN: 435 if (flatshade_first) { 436 for (i = 2; i < nr; i += 1) { 437 /* emit first non-spoke vertex as first vertex */ 438 sp_setup_tri( setup, 439 get_vert(vertex_buffer, i-1, stride), 440 get_vert(vertex_buffer, i-0, stride), 441 get_vert(vertex_buffer, 0, stride) ); 442 } 443 } 444 else { 445 for (i = 2; i < nr; i += 1) { 446 /* emit last non-spoke vertex as last vertex */ 447 sp_setup_tri( setup, 448 get_vert(vertex_buffer, 0, stride), 449 get_vert(vertex_buffer, i-1, stride), 450 get_vert(vertex_buffer, i-0, stride) ); 451 } 452 } 453 break; 454 455 case PIPE_PRIM_QUADS: 456 /* GL quads don't follow provoking vertex convention */ 457 if (flatshade_first) { 458 /* emit last quad vertex as first triangle vertex */ 459 for (i = 3; i < nr; i += 4) { 460 sp_setup_tri( setup, 461 get_vert(vertex_buffer, i-0, stride), 462 get_vert(vertex_buffer, i-3, stride), 463 get_vert(vertex_buffer, i-2, stride) ); 464 sp_setup_tri( setup, 465 get_vert(vertex_buffer, i-0, stride), 466 get_vert(vertex_buffer, i-2, stride), 467 get_vert(vertex_buffer, i-1, stride) ); 468 } 469 } 470 else { 471 /* emit last quad vertex as last triangle vertex */ 472 for (i = 3; i < nr; i += 4) { 473 sp_setup_tri( setup, 474 get_vert(vertex_buffer, i-3, stride), 475 get_vert(vertex_buffer, i-2, stride), 476 get_vert(vertex_buffer, i-0, stride) ); 477 sp_setup_tri( setup, 478 get_vert(vertex_buffer, i-2, stride), 479 get_vert(vertex_buffer, i-1, stride), 480 get_vert(vertex_buffer, i-0, stride) ); 481 } 482 } 483 break; 484 485 case PIPE_PRIM_QUAD_STRIP: 486 /* GL quad strips don't follow provoking vertex convention */ 487 if (flatshade_first) { 488 /* emit last quad vertex as first triangle vertex */ 489 for (i = 3; i < nr; i += 2) { 490 sp_setup_tri( setup, 491 get_vert(vertex_buffer, i-0, stride), 492 get_vert(vertex_buffer, i-3, stride), 493 get_vert(vertex_buffer, i-2, stride) ); 494 sp_setup_tri( setup, 495 get_vert(vertex_buffer, i-0, stride), 496 get_vert(vertex_buffer, i-1, stride), 497 get_vert(vertex_buffer, i-3, stride) ); 498 } 499 } 500 else { 501 /* emit last quad vertex as last triangle vertex */ 502 for (i = 3; i < nr; i += 2) { 503 sp_setup_tri( setup, 504 get_vert(vertex_buffer, i-3, stride), 505 get_vert(vertex_buffer, i-2, stride), 506 get_vert(vertex_buffer, i-0, stride) ); 507 sp_setup_tri( setup, 508 get_vert(vertex_buffer, i-1, stride), 509 get_vert(vertex_buffer, i-3, stride), 510 get_vert(vertex_buffer, i-0, stride) ); 511 } 512 } 513 break; 514 515 case PIPE_PRIM_POLYGON: 516 /* Almost same as tri fan but the _first_ vertex specifies the flat 517 * shading color. 518 */ 519 if (flatshade_first) { 520 /* emit first polygon vertex as first triangle vertex */ 521 for (i = 2; i < nr; i += 1) { 522 sp_setup_tri( setup, 523 get_vert(vertex_buffer, 0, stride), 524 get_vert(vertex_buffer, i-1, stride), 525 get_vert(vertex_buffer, i-0, stride) ); 526 } 527 } 528 else { 529 /* emit first polygon vertex as last triangle vertex */ 530 for (i = 2; i < nr; i += 1) { 531 sp_setup_tri( setup, 532 get_vert(vertex_buffer, i-1, stride), 533 get_vert(vertex_buffer, i-0, stride), 534 get_vert(vertex_buffer, 0, stride) ); 535 } 536 } 537 break; 538 539 default: 540 assert(0); 541 } 542 } 543 544 static void 545 sp_vbuf_so_info(struct vbuf_render *vbr, uint primitives, uint vertices, 546 uint prim_generated) 547 { 548 struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); 549 struct softpipe_context *softpipe = cvbr->softpipe; 550 551 softpipe->so_stats.num_primitives_written += primitives; 552 softpipe->so_stats.primitives_storage_needed = 553 vertices * 4 /*sizeof(float|int32)*/ * 4 /*x,y,z,w*/; 554 softpipe->num_primitives_generated += prim_generated; 555 } 556 557 558 static void 559 sp_vbuf_destroy(struct vbuf_render *vbr) 560 { 561 struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); 562 if (cvbr->vertex_buffer) 563 align_free(cvbr->vertex_buffer); 564 sp_setup_destroy_context(cvbr->setup); 565 FREE(cvbr); 566 } 567 568 569 /** 570 * Create the post-transform vertex handler for the given context. 571 */ 572 struct vbuf_render * 573 sp_create_vbuf_backend(struct softpipe_context *sp) 574 { 575 struct softpipe_vbuf_render *cvbr = CALLOC_STRUCT(softpipe_vbuf_render); 576 577 assert(sp->draw); 578 579 cvbr->base.max_indices = SP_MAX_VBUF_INDEXES; 580 cvbr->base.max_vertex_buffer_bytes = SP_MAX_VBUF_SIZE; 581 582 cvbr->base.get_vertex_info = sp_vbuf_get_vertex_info; 583 cvbr->base.allocate_vertices = sp_vbuf_allocate_vertices; 584 cvbr->base.map_vertices = sp_vbuf_map_vertices; 585 cvbr->base.unmap_vertices = sp_vbuf_unmap_vertices; 586 cvbr->base.set_primitive = sp_vbuf_set_primitive; 587 cvbr->base.draw_elements = sp_vbuf_draw_elements; 588 cvbr->base.draw_arrays = sp_vbuf_draw_arrays; 589 cvbr->base.release_vertices = sp_vbuf_release_vertices; 590 cvbr->base.set_stream_output_info = sp_vbuf_so_info; 591 cvbr->base.destroy = sp_vbuf_destroy; 592 593 cvbr->softpipe = sp; 594 595 cvbr->setup = sp_setup_create_context(cvbr->softpipe); 596 597 return &cvbr->base; 598 } 599