draw_pipe_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 
00037 #include "pipe/p_debug.h"
00038 #include "util/u_math.h"
00039 #include "util/u_memory.h"
00040 
00041 #include "draw_vbuf.h"
00042 #include "draw_private.h"
00043 #include "draw_vertex.h"
00044 #include "draw_pipe.h"
00045 #include "translate/translate.h"
00046 #include "translate/translate_cache.h"
00047 
00048 
00052 struct vbuf_stage {
00053    struct draw_stage stage; 
00055    struct vbuf_render *render;
00056    
00057    const struct vertex_info *vinfo;
00058    
00060    unsigned vertex_size;
00061 
00062    struct translate *translate;
00063    
00064    /* FIXME: we have no guarantee that 'unsigned' is 32bit */
00065 
00067    unsigned *vertices;
00068    unsigned *vertex_ptr;
00069    unsigned max_vertices;
00070    unsigned nr_vertices;
00071    
00073    ushort *indices;
00074    unsigned max_indices;
00075    unsigned nr_indices;
00076 
00077    /* Cache point size somewhere it's address won't change:
00078     */
00079    float point_size;
00080 
00081    struct translate_cache *cache;
00082 };
00083 
00084 
00088 static INLINE struct vbuf_stage *
00089 vbuf_stage( struct draw_stage *stage )
00090 {
00091    assert(stage);
00092    return (struct vbuf_stage *)stage;
00093 }
00094 
00095 
00096 static void vbuf_flush_indices( struct vbuf_stage *vbuf );
00097 static void vbuf_flush_vertices( struct vbuf_stage *vbuf );
00098 static void vbuf_alloc_vertices( struct vbuf_stage *vbuf );
00099 
00100 
00101 static INLINE boolean 
00102 overflow( void *map, void *ptr, unsigned bytes, unsigned bufsz )
00103 {
00104    unsigned long used = (unsigned long) ((char *)ptr - (char *)map);
00105    return (used + bytes) > bufsz;
00106 }
00107 
00108 
00109 static INLINE void 
00110 check_space( struct vbuf_stage *vbuf, unsigned nr )
00111 {
00112    if (vbuf->nr_vertices + nr > vbuf->max_vertices ) {
00113       vbuf_flush_vertices(vbuf);
00114       vbuf_alloc_vertices(vbuf);
00115    }
00116 
00117    if (vbuf->nr_indices + nr > vbuf->max_indices )
00118       vbuf_flush_indices(vbuf);
00119 }
00120 
00121 
00122 
00123 
00131 static INLINE ushort 
00132 emit_vertex( struct vbuf_stage *vbuf,
00133              struct vertex_header *vertex )
00134 {
00135    if(vertex->vertex_id == UNDEFINED_VERTEX_ID) {      
00136       /* Hmm - vertices are emitted one at a time - better make sure
00137        * set_buffer is efficient.  Consider a special one-shot mode for
00138        * translate.
00139        */
00140       /* Note: we really do want data[0] here, not data[pos]: 
00141        */
00142       vbuf->translate->set_buffer(vbuf->translate, 0, vertex->data[0], 0);
00143       vbuf->translate->run(vbuf->translate, 0, 1, vbuf->vertex_ptr);
00144 
00145       if (0) draw_dump_emitted_vertex(vbuf->vinfo, (uint8_t *)vbuf->vertex_ptr);
00146       
00147       vbuf->vertex_ptr += vbuf->vertex_size/4;
00148       vertex->vertex_id = vbuf->nr_vertices++;
00149    }
00150 
00151    return (ushort)vertex->vertex_id;
00152 }
00153 
00154 
00155 static void 
00156 vbuf_tri( struct draw_stage *stage,
00157           struct prim_header *prim )
00158 {
00159    struct vbuf_stage *vbuf = vbuf_stage( stage );
00160    unsigned i;
00161 
00162    check_space( vbuf, 3 );
00163 
00164    for (i = 0; i < 3; i++) {
00165       vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[i] );
00166    }
00167 }
00168 
00169 
00170 static void 
00171 vbuf_line( struct draw_stage *stage, 
00172            struct prim_header *prim )
00173 {
00174    struct vbuf_stage *vbuf = vbuf_stage( stage );
00175    unsigned i;
00176 
00177    check_space( vbuf, 2 );
00178 
00179    for (i = 0; i < 2; i++) {
00180       vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[i] );
00181    }   
00182 }
00183 
00184 
00185 static void 
00186 vbuf_point( struct draw_stage *stage, 
00187             struct prim_header *prim )
00188 {
00189    struct vbuf_stage *vbuf = vbuf_stage( stage );
00190 
00191    check_space( vbuf, 1 );
00192 
00193    vbuf->indices[vbuf->nr_indices++] = emit_vertex( vbuf, prim->v[0] );
00194 }
00195 
00196 
00197 
00198 
00204 static void
00205 vbuf_set_prim( struct vbuf_stage *vbuf, uint prim )
00206 {
00207    struct translate_key hw_key;
00208    unsigned dst_offset;
00209    unsigned i;
00210 
00211    vbuf->render->set_primitive(vbuf->render, prim);
00212 
00213    /* Must do this after set_primitive() above:
00214     * 
00215     * XXX: need some state managment to track when this needs to be
00216     * recalculated.  The driver should tell us whether there was a
00217     * state change.
00218     */
00219    vbuf->vinfo = vbuf->render->get_vertex_info(vbuf->render);
00220 
00221    if (vbuf->vertex_size != vbuf->vinfo->size * sizeof(float)) {
00222       vbuf_flush_vertices(vbuf);
00223       vbuf->vertex_size = vbuf->vinfo->size * sizeof(float);
00224    }
00225 
00226    /* Translate from pipeline vertices to hw vertices.
00227     */
00228    dst_offset = 0;
00229 
00230    for (i = 0; i < vbuf->vinfo->num_attribs; i++) {
00231       unsigned emit_sz = 0;
00232       unsigned src_buffer = 0;
00233       unsigned output_format;
00234       unsigned src_offset = (vbuf->vinfo->attrib[i].src_index * 4 * sizeof(float) );
00235 
00236       switch (vbuf->vinfo->attrib[i].emit) {
00237       case EMIT_4F:
00238          output_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
00239          emit_sz = 4 * sizeof(float);
00240          break;
00241       case EMIT_3F:
00242          output_format = PIPE_FORMAT_R32G32B32_FLOAT;
00243          emit_sz = 3 * sizeof(float);
00244          break;
00245       case EMIT_2F:
00246          output_format = PIPE_FORMAT_R32G32_FLOAT;
00247          emit_sz = 2 * sizeof(float);
00248          break;
00249       case EMIT_1F:
00250          output_format = PIPE_FORMAT_R32_FLOAT;
00251          emit_sz = 1 * sizeof(float);
00252          break;
00253       case EMIT_1F_PSIZE:
00254          output_format = PIPE_FORMAT_R32_FLOAT;
00255          emit_sz = 1 * sizeof(float);
00256          src_buffer = 1;
00257          src_offset = 0;
00258          break;
00259       case EMIT_4UB:
00260          output_format = PIPE_FORMAT_B8G8R8A8_UNORM;
00261          emit_sz = 4 * sizeof(ubyte);
00262          break;
00263       default:
00264          assert(0);
00265          output_format = PIPE_FORMAT_NONE;
00266          emit_sz = 0;
00267          break;
00268       }
00269       
00270       hw_key.element[i].input_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
00271       hw_key.element[i].input_buffer = src_buffer;
00272       hw_key.element[i].input_offset = src_offset;
00273       hw_key.element[i].output_format = output_format;
00274       hw_key.element[i].output_offset = dst_offset;
00275 
00276       dst_offset += emit_sz;
00277    }
00278 
00279    hw_key.nr_elements = vbuf->vinfo->num_attribs;
00280    hw_key.output_stride = vbuf->vinfo->size * 4;
00281 
00282    /* Don't bother with caching at this stage:
00283     */
00284    if (!vbuf->translate ||
00285        translate_key_compare(&vbuf->translate->key, &hw_key) != 0) 
00286    {
00287       translate_key_sanitize(&hw_key);
00288       vbuf->translate = translate_cache_find(vbuf->cache, &hw_key);
00289 
00290       vbuf->translate->set_buffer(vbuf->translate, 1, &vbuf->point_size, 0);
00291    }
00292 
00293    vbuf->point_size = vbuf->stage.draw->rasterizer->point_size;
00294 
00295    /* Allocate new buffer?
00296     */
00297    if (!vbuf->vertices)
00298       vbuf_alloc_vertices(vbuf);
00299 }
00300 
00301 
00302 static void 
00303 vbuf_first_tri( struct draw_stage *stage,
00304                 struct prim_header *prim )
00305 {
00306    struct vbuf_stage *vbuf = vbuf_stage( stage );
00307 
00308    vbuf_flush_indices( vbuf );   
00309    stage->tri = vbuf_tri;
00310    vbuf_set_prim(vbuf, PIPE_PRIM_TRIANGLES);
00311    stage->tri( stage, prim );
00312 }
00313 
00314 
00315 static void 
00316 vbuf_first_line( struct draw_stage *stage,
00317                  struct prim_header *prim )
00318 {
00319    struct vbuf_stage *vbuf = vbuf_stage( stage );
00320 
00321    vbuf_flush_indices( vbuf );
00322    stage->line = vbuf_line;
00323    vbuf_set_prim(vbuf, PIPE_PRIM_LINES);
00324    stage->line( stage, prim );
00325 }
00326 
00327 
00328 static void 
00329 vbuf_first_point( struct draw_stage *stage,
00330                   struct prim_header *prim )
00331 {
00332    struct vbuf_stage *vbuf = vbuf_stage( stage );
00333 
00334    vbuf_flush_indices( vbuf );
00335    stage->point = vbuf_point;
00336    vbuf_set_prim(vbuf, PIPE_PRIM_POINTS);
00337    stage->point( stage, prim );
00338 }
00339 
00340 
00341 static void 
00342 vbuf_flush_indices( struct vbuf_stage *vbuf ) 
00343 {
00344    if(!vbuf->nr_indices)
00345       return;
00346    
00347    assert((uint) (vbuf->vertex_ptr - vbuf->vertices) == 
00348           vbuf->nr_vertices * vbuf->vertex_size / sizeof(unsigned));
00349 
00350    vbuf->render->draw(vbuf->render, vbuf->indices, vbuf->nr_indices);
00351    
00352    vbuf->nr_indices = 0;
00353 }
00354 
00355 
00363 static void 
00364 vbuf_flush_vertices( struct vbuf_stage *vbuf )
00365 {
00366    if(vbuf->vertices) {      
00367       vbuf_flush_indices(vbuf);
00368       
00369       /* Reset temporary vertices ids */
00370       if(vbuf->nr_vertices)
00371          draw_reset_vertex_ids( vbuf->stage.draw );
00372       
00373       /* Free the vertex buffer */
00374       vbuf->render->release_vertices(vbuf->render,
00375                                      vbuf->vertices,
00376                                      vbuf->vertex_size,
00377                                      vbuf->nr_vertices);
00378       vbuf->max_vertices = vbuf->nr_vertices = 0;
00379       vbuf->vertex_ptr = vbuf->vertices = NULL;
00380       
00381    }
00382 }
00383    
00384 
00385 static void 
00386 vbuf_alloc_vertices( struct vbuf_stage *vbuf )
00387 {
00388    assert(!vbuf->nr_indices);
00389    assert(!vbuf->vertices);
00390    
00391    /* Allocate a new vertex buffer */
00392    vbuf->max_vertices = vbuf->render->max_vertex_buffer_bytes / vbuf->vertex_size;
00393 
00394    /* even number */
00395    vbuf->max_vertices = vbuf->max_vertices & ~1;
00396 
00397    /* Must always succeed -- driver gives us a
00398     * 'max_vertex_buffer_bytes' which it guarantees it can allocate,
00399     * and it will flush itself if necessary to do so.  If this does
00400     * fail, we are basically without usable hardware.
00401     */
00402    vbuf->vertices = (uint *) vbuf->render->allocate_vertices(vbuf->render,
00403                                                              (ushort) vbuf->vertex_size,
00404                                                              (ushort) vbuf->max_vertices);
00405    vbuf->vertex_ptr = vbuf->vertices;
00406 }
00407 
00408 
00409 
00410 static void 
00411 vbuf_flush( struct draw_stage *stage, unsigned flags )
00412 {
00413    struct vbuf_stage *vbuf = vbuf_stage( stage );
00414 
00415    vbuf_flush_indices( vbuf );
00416 
00417    stage->point = vbuf_first_point;
00418    stage->line = vbuf_first_line;
00419    stage->tri = vbuf_first_tri;
00420 
00421    if (flags & DRAW_FLUSH_BACKEND)
00422       vbuf_flush_vertices( vbuf );
00423 }
00424 
00425 
00426 static void 
00427 vbuf_reset_stipple_counter( struct draw_stage *stage )
00428 {
00429    /* XXX: Need to do something here for hardware with linestipple.
00430     */
00431    (void) stage;
00432 }
00433 
00434 
00435 static void vbuf_destroy( struct draw_stage *stage )
00436 {
00437    struct vbuf_stage *vbuf = vbuf_stage( stage );
00438 
00439    if(vbuf->indices)
00440       align_free( vbuf->indices );
00441    
00442    if (vbuf->render)
00443       vbuf->render->destroy( vbuf->render );
00444 
00445    if (vbuf->cache)
00446       translate_cache_destroy(vbuf->cache);
00447 
00448    FREE( stage );
00449 }
00450 
00451 
00455 struct draw_stage *draw_vbuf_stage( struct draw_context *draw,
00456                                     struct vbuf_render *render )
00457 {
00458    struct vbuf_stage *vbuf = CALLOC_STRUCT(vbuf_stage);
00459    if (vbuf == NULL)
00460       goto fail;
00461    
00462    vbuf->stage.draw = draw;
00463    vbuf->stage.point = vbuf_first_point;
00464    vbuf->stage.line = vbuf_first_line;
00465    vbuf->stage.tri = vbuf_first_tri;
00466    vbuf->stage.flush = vbuf_flush;
00467    vbuf->stage.reset_stipple_counter = vbuf_reset_stipple_counter;
00468    vbuf->stage.destroy = vbuf_destroy;
00469    
00470    vbuf->render = render;
00471    vbuf->max_indices = MAX2(render->max_indices, UNDEFINED_VERTEX_ID-1);
00472 
00473    vbuf->indices = (ushort *) align_malloc( vbuf->max_indices * 
00474                                             sizeof(vbuf->indices[0]), 
00475                                             16 );
00476    if (!vbuf->indices)
00477       goto fail;
00478 
00479    vbuf->cache = translate_cache_create();
00480    if (!vbuf->cache) 
00481       goto fail;
00482       
00483    
00484    vbuf->vertices = NULL;
00485    vbuf->vertex_ptr = vbuf->vertices;
00486    
00487    return &vbuf->stage;
00488 
00489  fail:
00490    if (vbuf)
00491       vbuf_destroy(&vbuf->stage);
00492    
00493    return NULL;
00494 }

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