"Fossies" - the Fresh Open Source Software Archive

Member "mesa-20.1.8/src/gallium/drivers/i915/i915_prim_vbuf.c" (16 Sep 2020, 21996 Bytes) of package /linux/misc/mesa-20.1.8.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "i915_prim_vbuf.c" see the Fossies "Dox" file reference documentation.

    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 
   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 *
  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
  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 *
  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
  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
  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
  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 *
  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 occurred 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
  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
  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
  326 i915_vbuf_render_set_primitive(struct vbuf_render *render, 
  327                                enum pipe_prim_type 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
  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
  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
  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, I915_FLUSH_ASYNC);
  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
  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, I915_FLUSH_ASYNC);
  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
  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
  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 
  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, I915_FLUSH_ASYNC);
  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
  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
  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 *
  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 = 4*4096;
  708 
  709    /* NOTE: it must be such that state and vertices indices fit in a single 
  710     * batch buffer. 4096 is one batch buffer and 430 is the max amount of 
  711     * state in dwords. The result is the number of 16-bit indices which can
  712     * fit in a single batch buffer.
  713     */
  714    i915_render->base.max_indices = (4096 - 430 * 4) / 2;
  715 
  716    i915_render->base.get_vertex_info = i915_vbuf_render_get_vertex_info;
  717    i915_render->base.allocate_vertices = i915_vbuf_render_allocate_vertices;
  718    i915_render->base.map_vertices = i915_vbuf_render_map_vertices;
  719    i915_render->base.unmap_vertices = i915_vbuf_render_unmap_vertices;
  720    i915_render->base.set_primitive = i915_vbuf_render_set_primitive;
  721    i915_render->base.draw_elements = i915_vbuf_render_draw_elements;
  722    i915_render->base.draw_arrays = i915_vbuf_render_draw_arrays;
  723    i915_render->base.release_vertices = i915_vbuf_render_release_vertices;
  724    i915_render->base.destroy = i915_vbuf_render_destroy;
  725 
  726 #ifndef VBUF_MAP_BUFFER
  727    i915_render->map_size = 0;
  728    i915_render->map_used_start = 0;
  729    i915_render->map_used_end = 0;
  730 #endif
  731 
  732    i915_render->vbo = NULL;
  733    i915_render->vbo_ptr = NULL;
  734    i915_render->vbo_size = 0;
  735    i915_render->vbo_hw_offset = 0;
  736    i915_render->vbo_sw_offset = 0;
  737    i915_render->vbo_alloc_size = i915_render->base.max_vertex_buffer_bytes * 4;
  738 
  739 #ifdef VBUF_USE_POOL
  740    i915_render->pool_used = FALSE;
  741    i915_render->pool_buffer_size = i915_render->vbo_alloc_size;
  742    i915_render->pool_fifo = u_fifo_create(6);
  743    for (i = 0; i < 6; i++)
  744       u_fifo_add(i915_render->pool_fifo,
  745                  iws->buffer_create(iws, i915_render->pool_buffer_size,
  746                                     I915_NEW_VERTEX));
  747 #else
  748    (void)i;
  749    (void)iws;
  750 #endif
  751 
  752    return &i915_render->base;
  753 }
  754 
  755 /**
  756  * Create a new primitive vbuf/render stage.
  757  */
  758 struct draw_stage *i915_draw_vbuf_stage(struct i915_context *i915)
  759 {
  760    struct vbuf_render *render;
  761    struct draw_stage *stage;
  762    
  763    render = i915_vbuf_render_create(i915);
  764    if (!render)
  765       return NULL;
  766    
  767    stage = draw_vbuf_stage(i915->draw, render);
  768    if (!stage) {
  769       render->destroy(render);
  770       return NULL;
  771    }
  772    /** TODO JB: this shouldn't be here */
  773    draw_set_render(i915->draw, render);
  774 
  775    return stage;
  776 }