draw_pt_fetch_emit.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 
00028  /*
00029   * Authors:
00030   *   Keith Whitwell <keith@tungstengraphics.com>
00031   */
00032 
00033 #include "util/u_memory.h"
00034 #include "draw/draw_context.h"
00035 #include "draw/draw_private.h"
00036 #include "draw/draw_vbuf.h"
00037 #include "draw/draw_vertex.h"
00038 #include "draw/draw_pt.h"
00039 #include "translate/translate.h"
00040 #include "translate/translate_cache.h"
00041 
00042 /* The simplest 'middle end' in the new vertex code.  
00043  * 
00044  * The responsibilities of a middle end are to:
00045  *  - perform vertex fetch using
00046  *       - draw vertex element/buffer state
00047  *       - a list of fetch indices we received as an input
00048  *  - run the vertex shader
00049  *  - cliptest, 
00050  *  - clip coord calculation 
00051  *  - viewport transformation
00052  *  - if necessary, run the primitive pipeline, passing it:
00053  *       - a linear array of vertex_header vertices constructed here
00054  *       - a set of draw indices we received as an input
00055  *  - otherwise, drive the hw backend,
00056  *       - allocate space for hardware format vertices
00057  *       - translate the vertex-shader output vertices to hw format
00058  *       - calling the backend draw functions.
00059  *
00060  * For convenience, we provide a helper function to drive the hardware
00061  * backend given similar inputs to those required to run the pipeline.
00062  *
00063  * In the case of passthrough mode, many of these actions are disabled
00064  * or noops, so we end up doing:
00065  *
00066  *  - perform vertex fetch
00067  *  - drive the hw backend
00068  *
00069  * IE, basically just vertex fetch to post-vs-format vertices,
00070  * followed by a call to the backend helper function.
00071  */
00072 
00073 
00074 struct fetch_emit_middle_end {
00075    struct draw_pt_middle_end base;
00076    struct draw_context *draw;
00077    
00078    struct translate *translate;
00079    const struct vertex_info *vinfo;
00080 
00081    /* Cache point size somewhere it's address won't change:
00082     */
00083    float point_size;
00084 
00085    struct translate_cache *cache;
00086 };
00087 
00088 
00089 
00090 
00091 static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
00092                                 unsigned prim,
00093                                 unsigned opt,
00094                                 unsigned *max_vertices )
00095 {
00096    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
00097    struct draw_context *draw = feme->draw;
00098    const struct vertex_info *vinfo;
00099    unsigned i, dst_offset;
00100    boolean ok;
00101    struct translate_key key;
00102 
00103 
00104    ok = draw->render->set_primitive( draw->render, 
00105                                      prim );
00106    if (!ok) {
00107       assert(0);
00108       return;
00109    }
00110    
00111    /* Must do this after set_primitive() above:
00112     */
00113    vinfo = feme->vinfo = draw->render->get_vertex_info(draw->render);
00114    
00115    
00116 
00117    /* Transform from API vertices to HW vertices, skipping the
00118     * pipeline_vertex intermediate step.
00119     */
00120    dst_offset = 0;
00121    memset(&key, 0, sizeof(key));
00122 
00123    for (i = 0; i < vinfo->num_attribs; i++) {
00124       const struct pipe_vertex_element *src = &draw->pt.vertex_element[vinfo->attrib[i].src_index];
00125 
00126       unsigned emit_sz = 0;
00127       unsigned input_format = src->src_format;
00128       unsigned input_buffer = src->vertex_buffer_index;
00129       unsigned input_offset = src->src_offset;
00130       unsigned output_format;
00131 
00132       switch (vinfo->attrib[i].emit) {
00133       case EMIT_4F:
00134          output_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
00135          emit_sz = 4 * sizeof(float);
00136          break;
00137       case EMIT_3F:
00138          output_format = PIPE_FORMAT_R32G32B32_FLOAT;
00139          emit_sz = 3 * sizeof(float);
00140          break;
00141       case EMIT_2F:
00142          output_format = PIPE_FORMAT_R32G32_FLOAT;
00143          emit_sz = 2 * sizeof(float);
00144          break;
00145       case EMIT_1F:
00146          output_format = PIPE_FORMAT_R32_FLOAT;
00147          emit_sz = 1 * sizeof(float);
00148          break;
00149       case EMIT_1F_PSIZE:
00150          input_format = PIPE_FORMAT_R32_FLOAT;
00151          input_buffer = draw->pt.nr_vertex_buffers;
00152          input_offset = 0;
00153          output_format = PIPE_FORMAT_R32_FLOAT;
00154          emit_sz = 1 * sizeof(float);
00155          break;
00156       default:
00157          assert(0);
00158          output_format = PIPE_FORMAT_NONE;
00159          emit_sz = 0;
00160          continue;
00161       }
00162 
00163       key.element[i].input_format = input_format;
00164       key.element[i].input_buffer = input_buffer;
00165       key.element[i].input_offset = input_offset;
00166       key.element[i].output_format = output_format;
00167       key.element[i].output_offset = dst_offset;
00168       
00169       dst_offset += emit_sz;
00170    }
00171 
00172    key.nr_elements = vinfo->num_attribs;
00173    key.output_stride = vinfo->size * 4;
00174 
00175    /* Don't bother with caching at this stage:
00176     */
00177    if (!feme->translate ||
00178        translate_key_compare(&feme->translate->key, &key) != 0) 
00179    {
00180       translate_key_sanitize(&key);
00181       feme->translate = translate_cache_find(feme->cache,
00182                                              &key);
00183 
00184 
00185       feme->translate->set_buffer(feme->translate, 
00186                                   draw->pt.nr_vertex_buffers, 
00187                                   &feme->point_size,
00188                                   0);
00189    }
00190    
00191    feme->point_size = draw->rasterizer->point_size;
00192 
00193    for (i = 0; i < draw->pt.nr_vertex_buffers; i++) {
00194       feme->translate->set_buffer(feme->translate, 
00195                                   i, 
00196                                   ((char *)draw->pt.user.vbuffer[i] + 
00197                                    draw->pt.vertex_buffer[i].buffer_offset),
00198                                   draw->pt.vertex_buffer[i].pitch );
00199    }
00200 
00201    *max_vertices = (draw->render->max_vertex_buffer_bytes / 
00202                     (vinfo->size * 4));
00203 
00204    /* Return an even number of verts.
00205     * This prevents "parity" errors when splitting long triangle strips which
00206     * can lead to front/back culling mix-ups.
00207     * Every other triangle in a strip has an alternate front/back orientation
00208     * so splitting at an odd position can cause the orientation of subsequent
00209     * triangles to get reversed.
00210     */
00211    *max_vertices = *max_vertices & ~1;
00212 }
00213 
00214 
00215 
00216 
00217 
00218 static void fetch_emit_run( struct draw_pt_middle_end *middle,
00219                             const unsigned *fetch_elts,
00220                             unsigned fetch_count,
00221                             const ushort *draw_elts,
00222                             unsigned draw_count )
00223 {
00224    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
00225    struct draw_context *draw = feme->draw;
00226    void *hw_verts;
00227    
00228    /* XXX: need to flush to get prim_vbuf.c to release its allocation?? 
00229     */
00230    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
00231 
00232    hw_verts = draw->render->allocate_vertices( draw->render,
00233                                                (ushort)feme->translate->key.output_stride,
00234                                                (ushort)fetch_count );
00235    if (!hw_verts) {
00236       assert(0);
00237       return;
00238    }
00239          
00240                                         
00241    /* Single routine to fetch vertices and emit HW verts.
00242     */
00243    feme->translate->run_elts( feme->translate, 
00244                               fetch_elts,
00245                               fetch_count,
00246                               hw_verts );
00247 
00248    if (0) {
00249       unsigned i;
00250       for (i = 0; i < fetch_count; i++) {
00251          debug_printf("\n\nvertex %d:\n", i);
00252          draw_dump_emitted_vertex( feme->vinfo, 
00253                                    (const uint8_t *)hw_verts + feme->vinfo->size * 4 * i );
00254       }
00255    }
00256 
00257    /* XXX: Draw arrays path to avoid re-emitting index list again and
00258     * again.
00259     */
00260    draw->render->draw( draw->render, 
00261                        draw_elts, 
00262                        draw_count );
00263 
00264    /* Done -- that was easy, wasn't it: 
00265     */
00266    draw->render->release_vertices( draw->render, 
00267                                    hw_verts, 
00268                                    feme->translate->key.output_stride, 
00269                                    fetch_count );
00270 
00271 }
00272 
00273 
00274 static void fetch_emit_run_linear( struct draw_pt_middle_end *middle,
00275                                    unsigned start,
00276                                    unsigned count )
00277 {
00278    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
00279    struct draw_context *draw = feme->draw;
00280    void *hw_verts;
00281 
00282    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
00283     */
00284    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
00285 
00286    hw_verts = draw->render->allocate_vertices( draw->render,
00287                                                (ushort)feme->translate->key.output_stride,
00288                                                (ushort)count );
00289    if (!hw_verts) {
00290       assert(0);
00291       return;
00292    }
00293 
00294    /* Single routine to fetch vertices and emit HW verts.
00295     */
00296    feme->translate->run( feme->translate,
00297                          start,
00298                          count,
00299                          hw_verts );
00300 
00301    if (0) {
00302       unsigned i;
00303       for (i = 0; i < count; i++) {
00304          debug_printf("\n\nvertex %d:\n", i);
00305          draw_dump_emitted_vertex( feme->vinfo,
00306                                    (const uint8_t *)hw_verts + feme->vinfo->size * 4 * i );
00307       }
00308    }
00309 
00310    /* XXX: Draw arrays path to avoid re-emitting index list again and
00311     * again.
00312     */
00313    draw->render->draw_arrays( draw->render,
00314                               0, /*start*/
00315                               count );
00316 
00317    /* Done -- that was easy, wasn't it:
00318     */
00319    draw->render->release_vertices( draw->render,
00320                                    hw_verts,
00321                                    feme->translate->key.output_stride,
00322                                    count );
00323 
00324 }
00325 
00326 
00327 static boolean fetch_emit_run_linear_elts( struct draw_pt_middle_end *middle,
00328                                         unsigned start,
00329                                         unsigned count,
00330                                         const ushort *draw_elts,
00331                                         unsigned draw_count )
00332 {
00333    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
00334    struct draw_context *draw = feme->draw;
00335    void *hw_verts;
00336 
00337    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
00338     */
00339    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
00340 
00341    hw_verts = draw->render->allocate_vertices( draw->render,
00342                                                (ushort)feme->translate->key.output_stride,
00343                                                (ushort)count );
00344    if (!hw_verts) 
00345       return FALSE;
00346 
00347    /* Single routine to fetch vertices and emit HW verts.
00348     */
00349    feme->translate->run( feme->translate,
00350                          start,
00351                          count,
00352                          hw_verts );
00353 
00354    /* XXX: Draw arrays path to avoid re-emitting index list again and
00355     * again.
00356     */
00357    draw->render->draw( draw->render, 
00358                        draw_elts, 
00359                        draw_count );
00360 
00361    /* Done -- that was easy, wasn't it:
00362     */
00363    draw->render->release_vertices( draw->render,
00364                                    hw_verts,
00365                                    feme->translate->key.output_stride,
00366                                    count );
00367 
00368    return TRUE;
00369 }
00370 
00371 
00372 
00373 
00374 static void fetch_emit_finish( struct draw_pt_middle_end *middle )
00375 {
00376    /* nothing to do */
00377 }
00378 
00379 static void fetch_emit_destroy( struct draw_pt_middle_end *middle )
00380 {
00381    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
00382 
00383    if (feme->cache)
00384       translate_cache_destroy(feme->cache);
00385 
00386    FREE(middle);
00387 }
00388 
00389 
00390 struct draw_pt_middle_end *draw_pt_fetch_emit( struct draw_context *draw )
00391 {
00392    struct fetch_emit_middle_end *fetch_emit = CALLOC_STRUCT( fetch_emit_middle_end );
00393    if (fetch_emit == NULL)
00394       return NULL;
00395 
00396    fetch_emit->cache = translate_cache_create();
00397    if (!fetch_emit->cache) {
00398       FREE(fetch_emit);
00399       return NULL;
00400    }
00401 
00402    fetch_emit->base.prepare    = fetch_emit_prepare;
00403    fetch_emit->base.run        = fetch_emit_run;
00404    fetch_emit->base.run_linear = fetch_emit_run_linear;
00405    fetch_emit->base.run_linear_elts = fetch_emit_run_linear_elts;
00406    fetch_emit->base.finish     = fetch_emit_finish;
00407    fetch_emit->base.destroy    = fetch_emit_destroy;
00408 
00409    fetch_emit->draw = draw;
00410      
00411    return &fetch_emit->base;
00412 }
00413 

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