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