1 /************************************************************************** 2 * 3 * Copyright 2007 VMware, Inc. 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 VMWARE 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.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.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_LINES_ADJACENCY: 384 for (i = 3; i < nr; i += 4) { 385 sp_setup_line( setup, 386 get_vert(vertex_buffer, i-2, stride), 387 get_vert(vertex_buffer, i-1, stride) ); 388 } 389 break; 390 391 case PIPE_PRIM_LINE_STRIP: 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 break; 398 399 case PIPE_PRIM_LINE_STRIP_ADJACENCY: 400 for (i = 3; i < nr; i++) { 401 sp_setup_line( setup, 402 get_vert(vertex_buffer, i-2, stride), 403 get_vert(vertex_buffer, i-1, stride) ); 404 } 405 break; 406 407 case PIPE_PRIM_LINE_LOOP: 408 for (i = 1; i < nr; i ++) { 409 sp_setup_line( setup, 410 get_vert(vertex_buffer, i-1, stride), 411 get_vert(vertex_buffer, i-0, stride) ); 412 } 413 if (nr) { 414 sp_setup_line( setup, 415 get_vert(vertex_buffer, nr-1, stride), 416 get_vert(vertex_buffer, 0, stride) ); 417 } 418 break; 419 420 case PIPE_PRIM_TRIANGLES: 421 for (i = 2; i < nr; i += 3) { 422 sp_setup_tri( setup, 423 get_vert(vertex_buffer, i-2, stride), 424 get_vert(vertex_buffer, i-1, stride), 425 get_vert(vertex_buffer, i-0, stride) ); 426 } 427 break; 428 429 case PIPE_PRIM_TRIANGLES_ADJACENCY: 430 for (i = 5; i < nr; i += 6) { 431 sp_setup_tri( setup, 432 get_vert(vertex_buffer, i-5, stride), 433 get_vert(vertex_buffer, i-3, stride), 434 get_vert(vertex_buffer, i-1, stride) ); 435 } 436 break; 437 438 case PIPE_PRIM_TRIANGLE_STRIP: 439 if (flatshade_first) { 440 for (i = 2; i < nr; i++) { 441 /* emit first triangle vertex as first triangle vertex */ 442 sp_setup_tri( setup, 443 get_vert(vertex_buffer, i-2, stride), 444 get_vert(vertex_buffer, i+(i&1)-1, stride), 445 get_vert(vertex_buffer, i-(i&1), stride) ); 446 } 447 } 448 else { 449 for (i = 2; i < nr; i++) { 450 /* emit last triangle vertex as last triangle vertex */ 451 sp_setup_tri( setup, 452 get_vert(vertex_buffer, i+(i&1)-2, stride), 453 get_vert(vertex_buffer, i-(i&1)-1, stride), 454 get_vert(vertex_buffer, i-0, stride) ); 455 } 456 } 457 break; 458 459 case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: 460 if (flatshade_first) { 461 for (i = 5; i < nr; i += 2) { 462 /* emit first triangle vertex as first triangle vertex */ 463 sp_setup_tri( setup, 464 get_vert(vertex_buffer, i-5, stride), 465 get_vert(vertex_buffer, i+(i&1)*2-3, stride), 466 get_vert(vertex_buffer, i-(i&1)*2-1, stride) ); 467 } 468 } 469 else { 470 for (i = 5; i < nr; i += 2) { 471 /* emit last triangle vertex as last triangle vertex */ 472 sp_setup_tri( setup, 473 get_vert(vertex_buffer, i+(i&1)*2-5, stride), 474 get_vert(vertex_buffer, i-(i&1)*2-3, stride), 475 get_vert(vertex_buffer, i-1, stride) ); 476 } 477 } 478 break; 479 480 case PIPE_PRIM_TRIANGLE_FAN: 481 if (flatshade_first) { 482 for (i = 2; i < nr; i += 1) { 483 /* emit first non-spoke vertex as first vertex */ 484 sp_setup_tri( setup, 485 get_vert(vertex_buffer, i-1, stride), 486 get_vert(vertex_buffer, i-0, stride), 487 get_vert(vertex_buffer, 0, stride) ); 488 } 489 } 490 else { 491 for (i = 2; i < nr; i += 1) { 492 /* emit last non-spoke vertex as last vertex */ 493 sp_setup_tri( setup, 494 get_vert(vertex_buffer, 0, stride), 495 get_vert(vertex_buffer, i-1, stride), 496 get_vert(vertex_buffer, i-0, stride) ); 497 } 498 } 499 break; 500 501 case PIPE_PRIM_QUADS: 502 /* GL quads don't follow provoking vertex convention */ 503 if (flatshade_first) { 504 /* emit last quad vertex as first triangle vertex */ 505 for (i = 3; i < nr; i += 4) { 506 sp_setup_tri( setup, 507 get_vert(vertex_buffer, i-0, stride), 508 get_vert(vertex_buffer, i-3, stride), 509 get_vert(vertex_buffer, i-2, stride) ); 510 sp_setup_tri( setup, 511 get_vert(vertex_buffer, i-0, stride), 512 get_vert(vertex_buffer, i-2, stride), 513 get_vert(vertex_buffer, i-1, stride) ); 514 } 515 } 516 else { 517 /* emit last quad vertex as last triangle vertex */ 518 for (i = 3; i < nr; i += 4) { 519 sp_setup_tri( setup, 520 get_vert(vertex_buffer, i-3, stride), 521 get_vert(vertex_buffer, i-2, stride), 522 get_vert(vertex_buffer, i-0, stride) ); 523 sp_setup_tri( setup, 524 get_vert(vertex_buffer, i-2, stride), 525 get_vert(vertex_buffer, i-1, stride), 526 get_vert(vertex_buffer, i-0, stride) ); 527 } 528 } 529 break; 530 531 case PIPE_PRIM_QUAD_STRIP: 532 /* GL quad strips don't follow provoking vertex convention */ 533 if (flatshade_first) { 534 /* emit last quad vertex as first triangle vertex */ 535 for (i = 3; i < nr; i += 2) { 536 sp_setup_tri( setup, 537 get_vert(vertex_buffer, i-0, stride), 538 get_vert(vertex_buffer, i-3, stride), 539 get_vert(vertex_buffer, i-2, stride) ); 540 sp_setup_tri( setup, 541 get_vert(vertex_buffer, i-0, stride), 542 get_vert(vertex_buffer, i-1, stride), 543 get_vert(vertex_buffer, i-3, stride) ); 544 } 545 } 546 else { 547 /* emit last quad vertex as last triangle vertex */ 548 for (i = 3; i < nr; i += 2) { 549 sp_setup_tri( setup, 550 get_vert(vertex_buffer, i-3, stride), 551 get_vert(vertex_buffer, i-2, stride), 552 get_vert(vertex_buffer, i-0, stride) ); 553 sp_setup_tri( setup, 554 get_vert(vertex_buffer, i-1, stride), 555 get_vert(vertex_buffer, i-3, stride), 556 get_vert(vertex_buffer, i-0, stride) ); 557 } 558 } 559 break; 560 561 case PIPE_PRIM_POLYGON: 562 /* Almost same as tri fan but the _first_ vertex specifies the flat 563 * shading color. 564 */ 565 if (flatshade_first) { 566 /* emit first polygon vertex as first triangle vertex */ 567 for (i = 2; i < nr; i += 1) { 568 sp_setup_tri( setup, 569 get_vert(vertex_buffer, 0, stride), 570 get_vert(vertex_buffer, i-1, stride), 571 get_vert(vertex_buffer, i-0, stride) ); 572 } 573 } 574 else { 575 /* emit first polygon vertex as last triangle vertex */ 576 for (i = 2; i < nr; i += 1) { 577 sp_setup_tri( setup, 578 get_vert(vertex_buffer, i-1, stride), 579 get_vert(vertex_buffer, i-0, stride), 580 get_vert(vertex_buffer, 0, stride) ); 581 } 582 } 583 break; 584 585 default: 586 assert(0); 587 } 588 } 589 590 /* 591 * FIXME: it is unclear if primitives_storage_needed (which is generally 592 * the same as pipe query num_primitives_generated) should increase 593 * if SO is disabled for d3d10, but for GL we definitely need to 594 * increase num_primitives_generated and this is only called for active 595 * SO. If it must not increase for d3d10 need to disambiguate the counters 596 * in the driver and do some work for getting correct values, if it should 597 * increase too should call this from outside streamout code. 598 */ 599 static void 600 sp_vbuf_so_info(struct vbuf_render *vbr, uint primitives, uint prim_generated) 601 { 602 struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); 603 struct softpipe_context *softpipe = cvbr->softpipe; 604 605 softpipe->so_stats.num_primitives_written += primitives; 606 softpipe->so_stats.primitives_storage_needed += prim_generated; 607 } 608 609 static void 610 sp_vbuf_pipeline_statistics( 611 struct vbuf_render *vbr, 612 const struct pipe_query_data_pipeline_statistics *stats) 613 { 614 struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); 615 struct softpipe_context *softpipe = cvbr->softpipe; 616 617 softpipe->pipeline_statistics.ia_vertices += 618 stats->ia_vertices; 619 softpipe->pipeline_statistics.ia_primitives += 620 stats->ia_primitives; 621 softpipe->pipeline_statistics.vs_invocations += 622 stats->vs_invocations; 623 softpipe->pipeline_statistics.gs_invocations += 624 stats->gs_invocations; 625 softpipe->pipeline_statistics.gs_primitives += 626 stats->gs_primitives; 627 softpipe->pipeline_statistics.c_invocations += 628 stats->c_invocations; 629 } 630 631 632 static void 633 sp_vbuf_destroy(struct vbuf_render *vbr) 634 { 635 struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr); 636 if (cvbr->vertex_buffer) 637 align_free(cvbr->vertex_buffer); 638 sp_setup_destroy_context(cvbr->setup); 639 FREE(cvbr); 640 } 641 642 643 /** 644 * Create the post-transform vertex handler for the given context. 645 */ 646 struct vbuf_render * 647 sp_create_vbuf_backend(struct softpipe_context *sp) 648 { 649 struct softpipe_vbuf_render *cvbr = CALLOC_STRUCT(softpipe_vbuf_render); 650 651 assert(sp->draw); 652 653 cvbr->base.max_indices = SP_MAX_VBUF_INDEXES; 654 cvbr->base.max_vertex_buffer_bytes = SP_MAX_VBUF_SIZE; 655 656 cvbr->base.get_vertex_info = sp_vbuf_get_vertex_info; 657 cvbr->base.allocate_vertices = sp_vbuf_allocate_vertices; 658 cvbr->base.map_vertices = sp_vbuf_map_vertices; 659 cvbr->base.unmap_vertices = sp_vbuf_unmap_vertices; 660 cvbr->base.set_primitive = sp_vbuf_set_primitive; 661 cvbr->base.draw_elements = sp_vbuf_draw_elements; 662 cvbr->base.draw_arrays = sp_vbuf_draw_arrays; 663 cvbr->base.release_vertices = sp_vbuf_release_vertices; 664 cvbr->base.set_stream_output_info = sp_vbuf_so_info; 665 cvbr->base.pipeline_statistics = sp_vbuf_pipeline_statistics; 666 cvbr->base.destroy = sp_vbuf_destroy; 667 668 cvbr->softpipe = sp; 669 670 cvbr->setup = sp_setup_create_context(cvbr->softpipe); 671 672 return &cvbr->base; 673 } 674