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 * \file 30 * Build post-transformation, post-clipping vertex buffers and element 31 * lists by hooking into the end of the primitive pipeline and 32 * manipulating the vertex_id field in the vertex headers. 33 * 34 * XXX: work in progress 35 * 36 * \author José Fonseca <jfonseca@vmware.com> 37 * \author Keith Whitwell <keithw@vmware.com> 38 */ 39 40#include "draw/draw_context.h" 41#include "draw/draw_vbuf.h" 42#include "util/u_debug.h" 43#include "util/u_fifo.h" 44#include "util/u_inlines.h" 45#include "util/u_math.h" 46#include "util/u_memory.h" 47 48#include "i915_batch.h" 49#include "i915_context.h" 50#include "i915_reg.h" 51#include "i915_state.h" 52 53/** 54 * Primitive renderer for i915. 55 */ 56struct i915_vbuf_render { 57 struct vbuf_render base; 58 59 struct i915_context *i915; 60 61 /** Vertex size in bytes */ 62 size_t vertex_size; 63 64 /** Software primitive */ 65 unsigned prim; 66 67 /** Hardware primitive */ 68 unsigned hwprim; 69 70 /** Genereate a vertex list */ 71 unsigned fallback; 72 73 /* Stuff for the vbo */ 74 struct i915_winsys_buffer *vbo; 75 size_t vbo_size; /**< current size of allocated buffer */ 76 size_t vbo_alloc_size; /**< minimum buffer size to allocate */ 77 size_t vbo_hw_offset; /**< offset that we program the hardware with */ 78 size_t vbo_sw_offset; /**< offset that we work with */ 79 size_t vbo_index; /**< index offset to be added to all indices */ 80 void *vbo_ptr; 81 size_t vbo_max_used; 82 size_t vbo_max_index; /**< index offset to be added to all indices */ 83}; 84 85/** 86 * Basically a cast wrapper. 87 */ 88static inline struct i915_vbuf_render * 89i915_vbuf_render(struct vbuf_render *render) 90{ 91 assert(render); 92 return (struct i915_vbuf_render *)render; 93} 94 95/** 96 * If vbo state differs between renderer and context 97 * push state to the context. This function pushes 98 * hw_offset to i915->vbo_offset and vbo to i915->vbo. 99 * 100 * Side effects: 101 * May updates context vbo_offset and vbo fields. 102 */ 103static void 104i915_vbuf_update_vbo_state(struct vbuf_render *render) 105{ 106 struct i915_vbuf_render *i915_render = i915_vbuf_render(render); 107 struct i915_context *i915 = i915_render->i915; 108 109 if (i915->vbo != i915_render->vbo || 110 i915->vbo_offset != i915_render->vbo_hw_offset) { 111 i915->vbo = i915_render->vbo; 112 i915->vbo_offset = i915_render->vbo_hw_offset; 113 i915->dirty |= I915_NEW_VBO; 114 } 115} 116 117/** 118 * Callback exported to the draw module. 119 * Returns the current vertex_info. 120 * 121 * Side effects: 122 * If state is dirty update derived state. 123 */ 124static const struct vertex_info * 125i915_vbuf_render_get_vertex_info(struct vbuf_render *render) 126{ 127 struct i915_vbuf_render *i915_render = i915_vbuf_render(render); 128 struct i915_context *i915 = i915_render->i915; 129 130 if (i915->dirty) { 131 /* make sure we have up to date vertex layout */ 132 i915_update_derived(i915); 133 } 134 135 return &i915->current.vertex_info; 136} 137 138/** 139 * Reserve space in the vbo for vertices. 140 * 141 * Side effects: 142 * None. 143 */ 144static bool 145i915_vbuf_render_reserve(struct i915_vbuf_render *i915_render, size_t size) 146{ 147 struct i915_context *i915 = i915_render->i915; 148 149 if (i915_render->vbo_size < size + i915_render->vbo_sw_offset) 150 return false; 151 152 if (i915->vbo_flushed) 153 return false; 154 155 return true; 156} 157 158/** 159 * Allocate a new vbo buffer should there not be enough space for 160 * the requested number of vertices by the draw module. 161 * 162 * Side effects: 163 * Updates hw_offset, sw_offset, index and allocates a new buffer. 164 * Will set i915->vbo to null on buffer allocation. 165 */ 166static void 167i915_vbuf_render_new_buf(struct i915_vbuf_render *i915_render, size_t size) 168{ 169 struct i915_context *i915 = i915_render->i915; 170 struct i915_winsys *iws = i915->iws; 171 172 if (i915_render->vbo) { 173 iws->buffer_unmap(iws, i915_render->vbo); 174 iws->buffer_destroy(iws, i915_render->vbo); 175 /* 176 * XXX If buffers where referenced then this should be done in 177 * update_vbo_state but since they arn't and malloc likes to reuse 178 * memory we need to set it to null 179 */ 180 i915->vbo = NULL; 181 i915_render->vbo = NULL; 182 } 183 184 i915->vbo_flushed = 0; 185 186 i915_render->vbo_size = MAX2(size, i915_render->vbo_alloc_size); 187 i915_render->vbo_hw_offset = 0; 188 i915_render->vbo_sw_offset = 0; 189 i915_render->vbo_index = 0; 190 191 i915_render->vbo = 192 iws->buffer_create(iws, i915_render->vbo_size, I915_NEW_VERTEX); 193 i915_render->vbo_ptr = iws->buffer_map(iws, i915_render->vbo, true); 194} 195 196/** 197 * Callback exported to the draw module. 198 * 199 * Side effects: 200 * Updates hw_offset, sw_offset, index and may allocate 201 * a new buffer. Also updates may update the vbo state 202 * on the i915 context. 203 */ 204static boolean 205i915_vbuf_render_allocate_vertices(struct vbuf_render *render, 206 ushort vertex_size, ushort nr_vertices) 207{ 208 struct i915_vbuf_render *i915_render = i915_vbuf_render(render); 209 size_t size = (size_t)vertex_size * (size_t)nr_vertices; 210 size_t offset; 211 212 /* 213 * Align sw_offset with first multiple of vertex size from hw_offset. 214 * Set index to be the multiples from from hw_offset to sw_offset. 215 * i915_vbuf_render_new_buf will reset index, sw_offset, hw_offset 216 * when it allocates a new buffer this is correct. 217 */ 218 { 219 offset = i915_render->vbo_sw_offset - i915_render->vbo_hw_offset; 220 offset = util_align_npot(offset, vertex_size); 221 i915_render->vbo_sw_offset = i915_render->vbo_hw_offset + offset; 222 i915_render->vbo_index = offset / vertex_size; 223 } 224 225 if (!i915_vbuf_render_reserve(i915_render, size)) 226 i915_vbuf_render_new_buf(i915_render, size); 227 228 /* 229 * If a new buffer has been alocated sw_offset, 230 * hw_offset & index will be reset by new_buf 231 */ 232 233 i915_render->vertex_size = vertex_size; 234 235 i915_vbuf_update_vbo_state(render); 236 237 if (!i915_render->vbo) 238 return FALSE; 239 return TRUE; 240} 241 242static void * 243i915_vbuf_render_map_vertices(struct vbuf_render *render) 244{ 245 struct i915_vbuf_render *i915_render = i915_vbuf_render(render); 246 struct i915_context *i915 = i915_render->i915; 247 248 if (i915->vbo_flushed) 249 debug_printf("%s bad vbo flush occurred stalling on hw\n", __FUNCTION__); 250 251 return (unsigned char *)i915_render->vbo_ptr + i915_render->vbo_sw_offset; 252} 253 254static void 255i915_vbuf_render_unmap_vertices(struct vbuf_render *render, ushort min_index, 256 ushort max_index) 257{ 258 struct i915_vbuf_render *i915_render = i915_vbuf_render(render); 259 260 i915_render->vbo_max_index = max_index; 261 i915_render->vbo_max_used = MAX2(i915_render->vbo_max_used, 262 i915_render->vertex_size * (max_index + 1)); 263} 264 265/** 266 * Ensure that the given max_index given is not larger ushort max. 267 * If it is larger then ushort max it advanced the hw_offset to the 268 * same position in the vbo as sw_offset and set index to zero. 269 * 270 * Side effects: 271 * On failure update hw_offset and index. 272 */ 273static void 274i915_vbuf_ensure_index_bounds(struct vbuf_render *render, unsigned max_index) 275{ 276 struct i915_vbuf_render *i915_render = i915_vbuf_render(render); 277 278 if (max_index + i915_render->vbo_index < ((1 << 17) - 1)) 279 return; 280 281 i915_render->vbo_hw_offset = i915_render->vbo_sw_offset; 282 i915_render->vbo_index = 0; 283 284 i915_vbuf_update_vbo_state(render); 285} 286 287static void 288i915_vbuf_render_set_primitive(struct vbuf_render *render, 289 enum pipe_prim_type prim) 290{ 291 struct i915_vbuf_render *i915_render = i915_vbuf_render(render); 292 i915_render->prim = prim; 293 294 switch (prim) { 295 case PIPE_PRIM_POINTS: 296 i915_render->hwprim = PRIM3D_POINTLIST; 297 i915_render->fallback = 0; 298 break; 299 case PIPE_PRIM_LINES: 300 i915_render->hwprim = PRIM3D_LINELIST; 301 i915_render->fallback = 0; 302 break; 303 case PIPE_PRIM_LINE_LOOP: 304 i915_render->hwprim = PRIM3D_LINELIST; 305 i915_render->fallback = PIPE_PRIM_LINE_LOOP; 306 break; 307 case PIPE_PRIM_LINE_STRIP: 308 i915_render->hwprim = PRIM3D_LINESTRIP; 309 i915_render->fallback = 0; 310 break; 311 case PIPE_PRIM_TRIANGLES: 312 i915_render->hwprim = PRIM3D_TRILIST; 313 i915_render->fallback = 0; 314 break; 315 case PIPE_PRIM_TRIANGLE_STRIP: 316 i915_render->hwprim = PRIM3D_TRISTRIP; 317 i915_render->fallback = 0; 318 break; 319 case PIPE_PRIM_TRIANGLE_FAN: 320 i915_render->hwprim = PRIM3D_TRIFAN; 321 i915_render->fallback = 0; 322 break; 323 case PIPE_PRIM_QUADS: 324 i915_render->hwprim = PRIM3D_TRILIST; 325 i915_render->fallback = PIPE_PRIM_QUADS; 326 break; 327 case PIPE_PRIM_QUAD_STRIP: 328 i915_render->hwprim = PRIM3D_TRILIST; 329 i915_render->fallback = PIPE_PRIM_QUAD_STRIP; 330 break; 331 case PIPE_PRIM_POLYGON: 332 i915_render->hwprim = PRIM3D_POLY; 333 i915_render->fallback = 0; 334 break; 335 default: 336 /* FIXME: Actually, can handle a lot more just fine... */ 337 assert(0 && "unexpected prim in i915_vbuf_render_set_primitive()"); 338 } 339} 340 341/** 342 * Used for fallbacks in draw_arrays 343 */ 344static void 345draw_arrays_generate_indices(struct vbuf_render *render, unsigned start, 346 uint32_t nr, unsigned type) 347{ 348 struct i915_vbuf_render *i915_render = i915_vbuf_render(render); 349 struct i915_context *i915 = i915_render->i915; 350 unsigned i; 351 unsigned end = start + nr + i915_render->vbo_index; 352 start += i915_render->vbo_index; 353 354 switch (type) { 355 case 0: 356 for (i = start; i + 1 < end; i += 2) 357 OUT_BATCH((i + 0) | (i + 1) << 16); 358 if (i < end) 359 OUT_BATCH(i); 360 break; 361 case PIPE_PRIM_LINE_LOOP: 362 if (nr >= 2) { 363 for (i = start + 1; i < end; i++) 364 OUT_BATCH((i - 1) | (i + 0) << 16); 365 OUT_BATCH((i - 1) | (start) << 16); 366 } 367 break; 368 case PIPE_PRIM_QUADS: 369 for (i = start; i + 3 < end; i += 4) { 370 OUT_BATCH((i + 0) | (i + 1) << 16); 371 OUT_BATCH((i + 3) | (i + 1) << 16); 372 OUT_BATCH((i + 2) | (i + 3) << 16); 373 } 374 break; 375 case PIPE_PRIM_QUAD_STRIP: 376 for (i = start; i + 3 < end; i += 2) { 377 OUT_BATCH((i + 0) | (i + 1) << 16); 378 OUT_BATCH((i + 3) | (i + 2) << 16); 379 OUT_BATCH((i + 0) | (i + 3) << 16); 380 } 381 break; 382 default: 383 assert(0); 384 } 385} 386 387static unsigned 388draw_arrays_calc_nr_indices(uint32_t nr, unsigned type) 389{ 390 switch (type) { 391 case 0: 392 return nr; 393 case PIPE_PRIM_LINE_LOOP: 394 if (nr >= 2) 395 return nr * 2; 396 else 397 return 0; 398 case PIPE_PRIM_QUADS: 399 return (nr / 4) * 6; 400 case PIPE_PRIM_QUAD_STRIP: 401 return ((nr - 2) / 2) * 6; 402 default: 403 assert(0); 404 return 0; 405 } 406} 407 408static void 409draw_arrays_fallback(struct vbuf_render *render, unsigned start, uint32_t nr) 410{ 411 struct i915_vbuf_render *i915_render = i915_vbuf_render(render); 412 struct i915_context *i915 = i915_render->i915; 413 unsigned nr_indices; 414 415 nr_indices = draw_arrays_calc_nr_indices(nr, i915_render->fallback); 416 if (!nr_indices) 417 return; 418 419 i915_vbuf_ensure_index_bounds(render, start + nr_indices); 420 421 if (i915->dirty) 422 i915_update_derived(i915); 423 424 if (i915->hardware_dirty) 425 i915_emit_hardware_state(i915); 426 427 if (!BEGIN_BATCH(1 + (nr_indices + 1) / 2)) { 428 FLUSH_BATCH(NULL, I915_FLUSH_ASYNC); 429 430 /* Make sure state is re-emitted after a flush: 431 */ 432 i915_emit_hardware_state(i915); 433 i915->vbo_flushed = 1; 434 435 if (!BEGIN_BATCH(1 + (nr_indices + 1) / 2)) { 436 mesa_loge("i915: Failed to allocate space for %d indices in fresh " 437 "batch with %d bytes left\n", 438 nr_indices, (int)i915_winsys_batchbuffer_space(i915->batch)); 439 assert(0); 440 goto out; 441 } 442 } 443 444 OUT_BATCH(_3DPRIMITIVE | PRIM_INDIRECT | i915_render->hwprim | 445 PRIM_INDIRECT_ELTS | nr_indices); 446 447 draw_arrays_generate_indices(render, start, nr, i915_render->fallback); 448 449out: 450 return; 451} 452 453static void 454i915_vbuf_render_draw_arrays(struct vbuf_render *render, unsigned start, 455 uint32_t nr) 456{ 457 struct i915_vbuf_render *i915_render = i915_vbuf_render(render); 458 struct i915_context *i915 = i915_render->i915; 459 460 if (i915_render->fallback) { 461 draw_arrays_fallback(render, start, nr); 462 return; 463 } 464 465 i915_vbuf_ensure_index_bounds(render, start + nr); 466 start += i915_render->vbo_index; 467 468 if (i915->dirty) 469 i915_update_derived(i915); 470 471 if (i915->hardware_dirty) 472 i915_emit_hardware_state(i915); 473 474 if (!BEGIN_BATCH(2)) { 475 FLUSH_BATCH(NULL, I915_FLUSH_ASYNC); 476 477 /* Make sure state is re-emitted after a flush: 478 */ 479 i915_emit_hardware_state(i915); 480 i915->vbo_flushed = 1; 481 482 if (!BEGIN_BATCH(2)) { 483 assert(0); 484 goto out; 485 } 486 } 487 488 OUT_BATCH(_3DPRIMITIVE | PRIM_INDIRECT | PRIM_INDIRECT_SEQUENTIAL | 489 i915_render->hwprim | nr); 490 OUT_BATCH(start); /* Beginning vertex index */ 491 492out: 493 return; 494} 495 496/** 497 * Used for normal and fallback emitting of indices 498 * If type is zero normal operation assumed. 499 */ 500static void 501draw_generate_indices(struct vbuf_render *render, const ushort *indices, 502 uint32_t nr_indices, unsigned type) 503{ 504 struct i915_vbuf_render *i915_render = i915_vbuf_render(render); 505 struct i915_context *i915 = i915_render->i915; 506 unsigned i; 507 unsigned o = i915_render->vbo_index; 508 509 switch (type) { 510 case 0: 511 for (i = 0; i + 1 < nr_indices; i += 2) { 512 OUT_BATCH((o + indices[i]) | (o + indices[i + 1]) << 16); 513 } 514 if (i < nr_indices) { 515 OUT_BATCH((o + indices[i])); 516 } 517 break; 518 case PIPE_PRIM_LINE_LOOP: 519 if (nr_indices >= 2) { 520 for (i = 1; i < nr_indices; i++) 521 OUT_BATCH((o + indices[i - 1]) | (o + indices[i]) << 16); 522 OUT_BATCH((o + indices[i - 1]) | (o + indices[0]) << 16); 523 } 524 break; 525 case PIPE_PRIM_QUADS: 526 for (i = 0; i + 3 < nr_indices; i += 4) { 527 OUT_BATCH((o + indices[i + 0]) | (o + indices[i + 1]) << 16); 528 OUT_BATCH((o + indices[i + 3]) | (o + indices[i + 1]) << 16); 529 OUT_BATCH((o + indices[i + 2]) | (o + indices[i + 3]) << 16); 530 } 531 break; 532 case PIPE_PRIM_QUAD_STRIP: 533 for (i = 0; i + 3 < nr_indices; i += 2) { 534 OUT_BATCH((o + indices[i + 0]) | (o + indices[i + 1]) << 16); 535 OUT_BATCH((o + indices[i + 3]) | (o + indices[i + 2]) << 16); 536 OUT_BATCH((o + indices[i + 0]) | (o + indices[i + 3]) << 16); 537 } 538 break; 539 default: 540 assert(0); 541 break; 542 } 543} 544 545static unsigned 546draw_calc_nr_indices(uint32_t nr_indices, unsigned type) 547{ 548 switch (type) { 549 case 0: 550 return nr_indices; 551 case PIPE_PRIM_LINE_LOOP: 552 if (nr_indices >= 2) 553 return nr_indices * 2; 554 else 555 return 0; 556 case PIPE_PRIM_QUADS: 557 return (nr_indices / 4) * 6; 558 case PIPE_PRIM_QUAD_STRIP: 559 return ((nr_indices - 2) / 2) * 6; 560 default: 561 assert(0); 562 return 0; 563 } 564} 565 566static void 567i915_vbuf_render_draw_elements(struct vbuf_render *render, 568 const ushort *indices, uint32_t nr_indices) 569{ 570 struct i915_vbuf_render *i915_render = i915_vbuf_render(render); 571 struct i915_context *i915 = i915_render->i915; 572 unsigned save_nr_indices; 573 574 save_nr_indices = nr_indices; 575 576 nr_indices = draw_calc_nr_indices(nr_indices, i915_render->fallback); 577 if (!nr_indices) 578 return; 579 580 i915_vbuf_ensure_index_bounds(render, i915_render->vbo_max_index); 581 582 if (i915->dirty) 583 i915_update_derived(i915); 584 585 if (i915->hardware_dirty) 586 i915_emit_hardware_state(i915); 587 588 if (!BEGIN_BATCH(1 + (nr_indices + 1) / 2)) { 589 FLUSH_BATCH(NULL, I915_FLUSH_ASYNC); 590 591 /* Make sure state is re-emitted after a flush: 592 */ 593 i915_emit_hardware_state(i915); 594 i915->vbo_flushed = 1; 595 596 if (!BEGIN_BATCH(1 + (nr_indices + 1) / 2)) { 597 mesa_loge("i915: Failed to allocate space for %d indices in fresh " 598 "batch with %d bytes left\n", 599 nr_indices, (int)i915_winsys_batchbuffer_space(i915->batch)); 600 assert(0); 601 goto out; 602 } 603 } 604 605 OUT_BATCH(_3DPRIMITIVE | PRIM_INDIRECT | i915_render->hwprim | 606 PRIM_INDIRECT_ELTS | nr_indices); 607 draw_generate_indices(render, indices, save_nr_indices, 608 i915_render->fallback); 609 610out: 611 return; 612} 613 614static void 615i915_vbuf_render_release_vertices(struct vbuf_render *render) 616{ 617 struct i915_vbuf_render *i915_render = i915_vbuf_render(render); 618 619 i915_render->vbo_sw_offset += i915_render->vbo_max_used; 620 i915_render->vbo_max_used = 0; 621 622 /* 623 * Micro optimization, by calling update here we the offset change 624 * will be picked up on the next pipe_context::draw_*. 625 */ 626 i915_vbuf_update_vbo_state(render); 627} 628 629static void 630i915_vbuf_render_destroy(struct vbuf_render *render) 631{ 632 struct i915_vbuf_render *i915_render = i915_vbuf_render(render); 633 struct i915_context *i915 = i915_render->i915; 634 struct i915_winsys *iws = i915->iws; 635 636 if (i915_render->vbo) { 637 i915->vbo = NULL; 638 iws->buffer_unmap(iws, i915_render->vbo); 639 iws->buffer_destroy(iws, i915_render->vbo); 640 } 641 642 FREE(i915_render); 643} 644 645/** 646 * Create a new primitive render. 647 */ 648static struct vbuf_render * 649i915_vbuf_render_create(struct i915_context *i915) 650{ 651 struct i915_vbuf_render *i915_render = CALLOC_STRUCT(i915_vbuf_render); 652 653 i915_render->i915 = i915; 654 655 i915_render->base.max_vertex_buffer_bytes = 4 * 4096; 656 657 /* NOTE: it must be such that state and vertices indices fit in a single 658 * batch buffer. 4096 is one batch buffer and 430 is the max amount of 659 * state in dwords. The result is the number of 16-bit indices which can 660 * fit in a single batch buffer. 661 */ 662 i915_render->base.max_indices = (4096 - 430 * 4) / 2; 663 664 i915_render->base.get_vertex_info = i915_vbuf_render_get_vertex_info; 665 i915_render->base.allocate_vertices = i915_vbuf_render_allocate_vertices; 666 i915_render->base.map_vertices = i915_vbuf_render_map_vertices; 667 i915_render->base.unmap_vertices = i915_vbuf_render_unmap_vertices; 668 i915_render->base.set_primitive = i915_vbuf_render_set_primitive; 669 i915_render->base.draw_elements = i915_vbuf_render_draw_elements; 670 i915_render->base.draw_arrays = i915_vbuf_render_draw_arrays; 671 i915_render->base.release_vertices = i915_vbuf_render_release_vertices; 672 i915_render->base.destroy = i915_vbuf_render_destroy; 673 674 i915_render->vbo = NULL; 675 i915_render->vbo_ptr = NULL; 676 i915_render->vbo_size = 0; 677 i915_render->vbo_hw_offset = 0; 678 i915_render->vbo_sw_offset = 0; 679 i915_render->vbo_alloc_size = i915_render->base.max_vertex_buffer_bytes * 4; 680 681 return &i915_render->base; 682} 683 684/** 685 * Create a new primitive vbuf/render stage. 686 */ 687struct draw_stage * 688i915_draw_vbuf_stage(struct i915_context *i915) 689{ 690 struct vbuf_render *render; 691 struct draw_stage *stage; 692 693 render = i915_vbuf_render_create(i915); 694 if (!render) 695 return NULL; 696 697 stage = draw_vbuf_stage(i915->draw, render); 698 if (!stage) { 699 render->destroy(render); 700 return NULL; 701 } 702 /** TODO JB: this shouldn't be here */ 703 draw_set_render(i915->draw, render); 704 705 return stage; 706} 707