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