Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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 *
  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 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
  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.                                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
  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. }
  777.