i915_prim_vbuf.c

Go to the documentation of this file.
00001 /**************************************************************************
00002  * 
00003  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
00004  * All Rights Reserved.
00005  *
00006  * Permission is hereby granted, free of charge, to any person obtaining a
00007  * copy of this software and associated documentation files (the
00008  * "Software"), to deal in the Software without restriction, including
00009  * without limitation the rights to use, copy, modify, merge, publish,
00010  * distribute, sub license, and/or sell copies of the Software, and to
00011  * permit persons to whom the Software is furnished to do so, subject to
00012  * the following conditions:
00013  * 
00014  * The above copyright notice and this permission notice (including the
00015  * next paragraph) shall be included in all copies or substantial portions
00016  * of the Software.
00017  * 
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00019  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
00021  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
00022  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
00023  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
00024  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00025  * 
00026  **************************************************************************/
00027 
00041 #include "draw/draw_context.h"
00042 #include "draw/draw_vbuf.h"
00043 #include "pipe/p_debug.h"
00044 #include "pipe/p_inlines.h"
00045 #include "pipe/p_winsys.h"
00046 #include "util/u_math.h"
00047 #include "util/u_memory.h"
00048 
00049 #include "i915_context.h"
00050 #include "i915_reg.h"
00051 #include "i915_winsys.h"
00052 #include "i915_batch.h"
00053 #include "i915_state.h"
00054 
00055 
00059 struct i915_vbuf_render {
00060    struct vbuf_render base;
00061 
00062    struct i915_context *i915;   
00063 
00065    unsigned vertex_size;
00066 
00068    unsigned prim;
00069 
00071    unsigned hwprim;
00072 
00074    unsigned fallback;
00075 
00076    /* Stuff for the vbo */
00077    struct pipe_buffer *vbo;
00078    size_t vbo_size;
00079    size_t vbo_offset;
00080    void *vbo_ptr;
00081    size_t vbo_alloc_size;
00082 };
00083 
00084 
00088 static INLINE struct i915_vbuf_render *
00089 i915_vbuf_render( struct vbuf_render *render )
00090 {
00091    assert(render);
00092    return (struct i915_vbuf_render *)render;
00093 }
00094 
00095 
00096 static const struct vertex_info *
00097 i915_vbuf_render_get_vertex_info( struct vbuf_render *render )
00098 {
00099    struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
00100    struct i915_context *i915 = i915_render->i915;
00101 
00102    if (i915->dirty) {
00103       /* make sure we have up to date vertex layout */
00104       i915_update_derived( i915 );
00105    }
00106 
00107    return &i915->current.vertex_info;
00108 }
00109 
00110 
00111 static void *
00112 i915_vbuf_render_allocate_vertices( struct vbuf_render *render,
00113                                     ushort vertex_size,
00114                                     ushort nr_vertices )
00115 {
00116    struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
00117    struct i915_context *i915 = i915_render->i915;
00118    struct pipe_screen *screen = i915->pipe.screen;
00119    size_t size = (size_t)vertex_size * (size_t)nr_vertices;
00120 
00121    /* FIXME: handle failure */
00122    assert(!i915->vbo);
00123 
00124    if (i915_render->vbo_size > size + i915_render->vbo_offset && !i915->vbo_flushed) {
00125    } else {
00126       i915->vbo_flushed = 0;
00127       pipe_buffer_reference(screen, &i915_render->vbo, NULL);
00128    }
00129 
00130    if (!i915_render->vbo) {
00131       i915_render->vbo_size = MAX2(size, i915_render->vbo_alloc_size);
00132       i915_render->vbo_offset = 0;
00133       i915_render->vbo = pipe_buffer_create(screen,
00134                                             64,
00135                                             I915_BUFFER_USAGE_LIT_VERTEX,
00136                                             i915_render->vbo_size);
00137       i915_render->vbo_ptr = pipe_buffer_map(screen,
00138                                              i915_render->vbo,
00139                                              PIPE_BUFFER_USAGE_CPU_WRITE);
00140       pipe_buffer_unmap(screen, i915_render->vbo);
00141    }
00142 
00143    i915->vbo = i915_render->vbo;
00144    i915->vbo_offset = i915_render->vbo_offset;
00145    i915->dirty |= I915_NEW_VBO;
00146 
00147    return (unsigned char *)i915_render->vbo_ptr + i915->vbo_offset;
00148 }
00149 
00150 
00151 static boolean
00152 i915_vbuf_render_set_primitive( struct vbuf_render *render, 
00153                                 unsigned prim )
00154 {
00155    struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
00156    i915_render->prim = prim;
00157 
00158    switch(prim) {
00159    case PIPE_PRIM_POINTS:
00160       i915_render->hwprim = PRIM3D_POINTLIST;
00161       i915_render->fallback = 0;
00162       return TRUE;
00163    case PIPE_PRIM_LINES:
00164       i915_render->hwprim = PRIM3D_LINELIST;
00165       i915_render->fallback = 0;
00166       return TRUE;
00167    case PIPE_PRIM_LINE_LOOP:
00168       i915_render->hwprim = PRIM3D_LINELIST;
00169       i915_render->fallback = PIPE_PRIM_LINE_LOOP;
00170       return TRUE;
00171    case PIPE_PRIM_LINE_STRIP:
00172       i915_render->hwprim = PRIM3D_LINESTRIP;
00173       i915_render->fallback = 0;
00174       return TRUE;
00175    case PIPE_PRIM_TRIANGLES:
00176       i915_render->hwprim = PRIM3D_TRILIST;
00177       i915_render->fallback = 0;
00178       return TRUE;
00179    case PIPE_PRIM_TRIANGLE_STRIP:
00180       i915_render->hwprim = PRIM3D_TRISTRIP;
00181       i915_render->fallback = 0;
00182       return TRUE;
00183    case PIPE_PRIM_TRIANGLE_FAN:
00184       i915_render->hwprim = PRIM3D_TRIFAN;
00185       i915_render->fallback = 0;
00186       return TRUE;
00187    case PIPE_PRIM_QUADS:
00188       i915_render->hwprim = PRIM3D_TRILIST;
00189       i915_render->fallback = PIPE_PRIM_QUADS;
00190       return TRUE;
00191    case PIPE_PRIM_QUAD_STRIP:
00192       i915_render->hwprim = PRIM3D_TRILIST;
00193       i915_render->fallback = PIPE_PRIM_QUAD_STRIP;
00194       return TRUE;
00195    case PIPE_PRIM_POLYGON:
00196       i915_render->hwprim = PRIM3D_POLY;
00197       i915_render->fallback = 0;
00198       return TRUE;
00199    default:
00200       assert((int)"Error unkown primtive type" & 0);
00201       /* Actually, can handle a lot more just fine...  Fixme.
00202        */
00203       return FALSE;
00204    }
00205 }
00206 
00207 
00208 
00212 static void
00213 draw_arrays_generate_indices( struct vbuf_render *render,
00214                               unsigned start, uint nr,
00215                               unsigned type )
00216 {
00217    struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
00218    struct i915_context *i915 = i915_render->i915;
00219    unsigned i;
00220    unsigned end = start + nr;
00221    switch(type) {
00222    case 0:
00223       for (i = start; i+1 < end; i += 2)
00224          OUT_BATCH( (i+0) | (i+1) << 16 );
00225       if (i < end)
00226          OUT_BATCH( i );
00227       break;
00228    case PIPE_PRIM_LINE_LOOP:
00229       if (nr >= 2) {
00230          for (i = start + 1; i < end; i++)
00231             OUT_BATCH( (i-0) | (i+0) << 16 );
00232          OUT_BATCH( (i-0) | (  start) << 16 );
00233       }
00234       break;
00235    case PIPE_PRIM_QUADS:
00236       for (i = start; i + 3 < end; i += 4) {
00237          OUT_BATCH( (i+0) | (i+1) << 16 );
00238          OUT_BATCH( (i+3) | (i+1) << 16 );
00239          OUT_BATCH( (i+2) | (i+3) << 16 );
00240       }
00241       break;
00242    case PIPE_PRIM_QUAD_STRIP:
00243       for (i = start; i + 3 < end; i += 2) {
00244          OUT_BATCH( (i+0) | (i+1) << 16 );
00245          OUT_BATCH( (i+3) | (i+2) << 16 );
00246          OUT_BATCH( (i+0) | (i+3) << 16 );
00247       }
00248       break;
00249    default:
00250       assert(0);
00251    }
00252 }
00253 
00254 static unsigned
00255 draw_arrays_calc_nr_indices( uint nr, unsigned type )
00256 {
00257    switch (type) {
00258    case 0:
00259       return nr;
00260    case PIPE_PRIM_LINE_LOOP:
00261       if (nr >= 2)
00262          return nr * 2;
00263       else
00264          return 0;
00265    case PIPE_PRIM_QUADS:
00266       return (nr / 4) * 6;
00267    case PIPE_PRIM_QUAD_STRIP:
00268       return ((nr - 2) / 2) * 6;
00269    default:
00270       assert(0);
00271       return 0;
00272    }
00273 }
00274 
00275 static void
00276 draw_arrays_fallback( struct vbuf_render *render,
00277                       unsigned start,
00278                       uint nr )
00279 {
00280    struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
00281    struct i915_context *i915 = i915_render->i915;
00282    unsigned nr_indices;
00283 
00284    if (i915->dirty)
00285       i915_update_derived( i915 );
00286 
00287    if (i915->hardware_dirty)
00288       i915_emit_hardware_state( i915 );
00289 
00290    nr_indices = draw_arrays_calc_nr_indices( nr, i915_render->fallback );
00291    if (!nr_indices)
00292       return;
00293 
00294    if (!BEGIN_BATCH( 1 + (nr_indices + 1)/2, 1 )) {
00295       FLUSH_BATCH(NULL);
00296 
00297       /* Make sure state is re-emitted after a flush:
00298        */
00299       i915_update_derived( i915 );
00300       i915_emit_hardware_state( i915 );
00301       i915->vbo_flushed = 1;
00302 
00303       if (!BEGIN_BATCH( 1 + (nr_indices + 1)/2, 1 )) {
00304          assert(0);
00305          goto out;
00306       }
00307    }
00308    OUT_BATCH( _3DPRIMITIVE |
00309               PRIM_INDIRECT |
00310               i915_render->hwprim |
00311               PRIM_INDIRECT_ELTS |
00312               nr_indices );
00313 
00314    draw_arrays_generate_indices( render, start, nr, i915_render->fallback );
00315 
00316 out:
00317    return;
00318 }
00319 
00320 static void
00321 i915_vbuf_render_draw_arrays( struct vbuf_render *render,
00322                               unsigned start,
00323                               uint nr )
00324 {
00325    struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
00326 
00327    if (i915_render->fallback) {
00328       draw_arrays_fallback( render, start, nr );
00329       return;
00330    }
00331 
00332    /* JB: TODO submit direct cmds */
00333    draw_arrays_fallback( render, start, nr );
00334 }
00335 
00340 static void
00341 draw_generate_indices( struct vbuf_render *render,
00342                        const ushort *indices,
00343                        uint nr_indices,
00344                        unsigned type )
00345 {
00346    struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
00347    struct i915_context *i915 = i915_render->i915;
00348    unsigned i;
00349 
00350    switch(type) {
00351    case 0:
00352       for (i = 0; i + 1 < nr_indices; i += 2) {
00353          OUT_BATCH( indices[i] | indices[i+1] << 16 );
00354       }
00355       if (i < nr_indices) {
00356          OUT_BATCH( indices[i] );
00357       }
00358       break;
00359    case PIPE_PRIM_LINE_LOOP:
00360       if (nr_indices >= 2) {
00361          for (i = 1; i < nr_indices; i++)
00362             OUT_BATCH( indices[i-1] | indices[i] << 16 );
00363          OUT_BATCH( indices[i-1] | indices[0] << 16 );
00364       }
00365       break;
00366    case PIPE_PRIM_QUADS:
00367       for (i = 0; i + 3 < nr_indices; i += 4) {
00368          OUT_BATCH( indices[i+0] | indices[i+1] << 16 );
00369          OUT_BATCH( indices[i+3] | indices[i+1] << 16 );
00370          OUT_BATCH( indices[i+2] | indices[i+3] << 16 );
00371       }
00372       break;
00373    case PIPE_PRIM_QUAD_STRIP:
00374       for (i = 0; i + 3 < nr_indices; i += 2) {
00375          OUT_BATCH( indices[i+0] | indices[i+1] << 16 );
00376          OUT_BATCH( indices[i+3] | indices[i+2] << 16 );
00377          OUT_BATCH( indices[i+0] | indices[i+3] << 16 );
00378       }
00379       break;
00380    default:
00381       assert(0);
00382       break;
00383    }
00384 }
00385 
00386 static unsigned
00387 draw_calc_nr_indices( uint nr_indices, unsigned type )
00388 {
00389    switch (type) {
00390    case 0:
00391       return nr_indices;
00392    case PIPE_PRIM_LINE_LOOP:
00393       if (nr_indices >= 2)
00394          return nr_indices * 2;
00395       else
00396          return 0;
00397    case PIPE_PRIM_QUADS:
00398       return (nr_indices / 4) * 6;
00399    case PIPE_PRIM_QUAD_STRIP:
00400       return ((nr_indices - 2) / 2) * 6;
00401    default:
00402       assert(0);
00403       return 0;
00404    }
00405 }
00406 
00407 static void 
00408 i915_vbuf_render_draw( struct vbuf_render *render,
00409                        const ushort *indices,
00410                        uint nr_indices)
00411 {
00412    struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
00413    struct i915_context *i915 = i915_render->i915;
00414    unsigned save_nr_indices;
00415 
00416    save_nr_indices = nr_indices;
00417 
00418    nr_indices = draw_calc_nr_indices( nr_indices, i915_render->fallback );
00419    if (!nr_indices)
00420       return;
00421 
00422    if (i915->dirty)
00423       i915_update_derived( i915 );
00424 
00425    if (i915->hardware_dirty)
00426       i915_emit_hardware_state( i915 );
00427 
00428    if (!BEGIN_BATCH( 1 + (nr_indices + 1)/2, 1 )) {
00429       FLUSH_BATCH(NULL);
00430 
00431       /* Make sure state is re-emitted after a flush: 
00432        */
00433       i915_update_derived( i915 );
00434       i915_emit_hardware_state( i915 );
00435       i915->vbo_flushed = 1;
00436 
00437       if (!BEGIN_BATCH( 1 + (nr_indices + 1)/2, 1 )) {
00438          assert(0);
00439      goto out;
00440       }
00441    }
00442 
00443    OUT_BATCH( _3DPRIMITIVE |
00444               PRIM_INDIRECT |
00445               i915_render->hwprim |
00446               PRIM_INDIRECT_ELTS |
00447               nr_indices );
00448    draw_generate_indices( render,
00449                           indices,
00450                           save_nr_indices,
00451                           i915_render->fallback );
00452 
00453 out:
00454    return;
00455 }
00456 
00457 
00458 static void
00459 i915_vbuf_render_release_vertices( struct vbuf_render *render,
00460                                    void *vertices, 
00461                                    unsigned vertex_size,
00462                                    unsigned vertices_used )
00463 {
00464    struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
00465    struct i915_context *i915 = i915_render->i915;
00466    size_t size = (size_t)vertex_size * (size_t)vertices_used;
00467 
00468    assert(i915->vbo);
00469 
00470    i915_render->vbo_offset += size;
00471    i915->vbo = NULL;
00472    i915->dirty |= I915_NEW_VBO;
00473 }
00474 
00475 
00476 static void
00477 i915_vbuf_render_destroy( struct vbuf_render *render )
00478 {
00479    struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
00480    FREE(i915_render);
00481 }
00482 
00483 
00487 static struct vbuf_render *
00488 i915_vbuf_render_create( struct i915_context *i915 )
00489 {
00490    struct i915_vbuf_render *i915_render = CALLOC_STRUCT(i915_vbuf_render);
00491    struct pipe_screen *screen = i915->pipe.screen;
00492 
00493    i915_render->i915 = i915;
00494    
00495    i915_render->base.max_vertex_buffer_bytes = 128*1024;
00496    
00497    /* NOTE: it must be such that state and vertices indices fit in a single 
00498     * batch buffer.
00499     */
00500    i915_render->base.max_indices = 16*1024;
00501 
00502    i915_render->base.get_vertex_info = i915_vbuf_render_get_vertex_info;
00503    i915_render->base.allocate_vertices = i915_vbuf_render_allocate_vertices;
00504    i915_render->base.set_primitive = i915_vbuf_render_set_primitive;
00505    i915_render->base.draw = i915_vbuf_render_draw;
00506    i915_render->base.draw_arrays = i915_vbuf_render_draw_arrays;
00507    i915_render->base.release_vertices = i915_vbuf_render_release_vertices;
00508    i915_render->base.destroy = i915_vbuf_render_destroy;
00509 
00510    i915_render->vbo_alloc_size = 128 * 4096;
00511    i915_render->vbo_size = i915_render->vbo_alloc_size;
00512    i915_render->vbo_offset = 0;
00513    i915_render->vbo = pipe_buffer_create(screen,
00514                                          64,
00515                                          I915_BUFFER_USAGE_LIT_VERTEX,
00516                                          i915_render->vbo_size);
00517    i915_render->vbo_ptr = pipe_buffer_map(screen,
00518                                           i915_render->vbo,
00519                                           PIPE_BUFFER_USAGE_CPU_WRITE);
00520    pipe_buffer_unmap(screen, i915_render->vbo);
00521 
00522    return &i915_render->base;
00523 }
00524 
00525 
00529 struct draw_stage *i915_draw_vbuf_stage( struct i915_context *i915 )
00530 {
00531    struct vbuf_render *render;
00532    struct draw_stage *stage;
00533    
00534    render = i915_vbuf_render_create(i915);
00535    if(!render)
00536       return NULL;
00537    
00538    stage = draw_vbuf_stage( i915->draw, render );
00539    if(!stage) {
00540       render->destroy(render);
00541       return NULL;
00542    }
00544    draw_set_render(i915->draw, render);
00545 
00546    return stage;
00547 }

Generated on Tue Sep 29 06:25:16 2009 for Gallium3D by  doxygen 1.5.4