Home | History | Annotate | Download | only in draw
      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   * Authors:
     30   *   Keith Whitwell <keith (at) tungstengraphics.com>
     31   */
     32 
     33 #include "util/u_memory.h"
     34 #include "draw/draw_context.h"
     35 #include "draw/draw_private.h"
     36 #include "draw/draw_vbuf.h"
     37 #include "draw/draw_vertex.h"
     38 #include "draw/draw_pt.h"
     39 #include "draw/draw_gs.h"
     40 #include "translate/translate.h"
     41 #include "translate/translate_cache.h"
     42 
     43 /* The simplest 'middle end' in the new vertex code.
     44  *
     45  * The responsibilities of a middle end are to:
     46  *  - perform vertex fetch using
     47  *       - draw vertex element/buffer state
     48  *       - a list of fetch indices we received as an input
     49  *  - run the vertex shader
     50  *  - cliptest,
     51  *  - clip coord calculation
     52  *  - viewport transformation
     53  *  - if necessary, run the primitive pipeline, passing it:
     54  *       - a linear array of vertex_header vertices constructed here
     55  *       - a set of draw indices we received as an input
     56  *  - otherwise, drive the hw backend,
     57  *       - allocate space for hardware format vertices
     58  *       - translate the vertex-shader output vertices to hw format
     59  *       - calling the backend draw functions.
     60  *
     61  * For convenience, we provide a helper function to drive the hardware
     62  * backend given similar inputs to those required to run the pipeline.
     63  *
     64  * In the case of passthrough mode, many of these actions are disabled
     65  * or noops, so we end up doing:
     66  *
     67  *  - perform vertex fetch
     68  *  - drive the hw backend
     69  *
     70  * IE, basically just vertex fetch to post-vs-format vertices,
     71  * followed by a call to the backend helper function.
     72  */
     73 
     74 
     75 struct fetch_emit_middle_end {
     76    struct draw_pt_middle_end base;
     77    struct draw_context *draw;
     78 
     79    struct translate *translate;
     80    const struct vertex_info *vinfo;
     81 
     82    /* Cache point size somewhere it's address won't change:
     83     */
     84    float point_size;
     85 
     86    struct translate_cache *cache;
     87 };
     88 
     89 
     90 static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
     91                                 unsigned prim,
     92 				unsigned opt,
     93                                 unsigned *max_vertices )
     94 {
     95    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
     96    struct draw_context *draw = feme->draw;
     97    const struct vertex_info *vinfo;
     98    unsigned i, dst_offset;
     99    struct translate_key key;
    100    unsigned gs_out_prim = (draw->gs.geometry_shader ?
    101                            draw->gs.geometry_shader->output_primitive :
    102                            prim);
    103 
    104    draw->render->set_primitive(draw->render, gs_out_prim);
    105 
    106    /* Must do this after set_primitive() above:
    107     */
    108    vinfo = feme->vinfo = draw->render->get_vertex_info(draw->render);
    109 
    110    /* Transform from API vertices to HW vertices, skipping the
    111     * pipeline_vertex intermediate step.
    112     */
    113    dst_offset = 0;
    114    memset(&key, 0, sizeof(key));
    115 
    116    for (i = 0; i < vinfo->num_attribs; i++) {
    117       const struct pipe_vertex_element *src = &draw->pt.vertex_element[vinfo->attrib[i].src_index];
    118 
    119       unsigned emit_sz = 0;
    120       unsigned input_format = src->src_format;
    121       unsigned input_buffer = src->vertex_buffer_index;
    122       unsigned input_offset = src->src_offset;
    123       unsigned output_format;
    124 
    125       output_format = draw_translate_vinfo_format(vinfo->attrib[i].emit);
    126       emit_sz = draw_translate_vinfo_size(vinfo->attrib[i].emit);
    127 
    128       if (vinfo->attrib[i].emit == EMIT_OMIT)
    129 	 continue;
    130 
    131       if (vinfo->attrib[i].emit == EMIT_1F_PSIZE) {
    132 	 input_format = PIPE_FORMAT_R32_FLOAT;
    133 	 input_buffer = draw->pt.nr_vertex_buffers;
    134 	 input_offset = 0;
    135       }
    136 
    137       key.element[i].type = TRANSLATE_ELEMENT_NORMAL;
    138       key.element[i].input_format = input_format;
    139       key.element[i].input_buffer = input_buffer;
    140       key.element[i].input_offset = input_offset;
    141       key.element[i].instance_divisor = src->instance_divisor;
    142       key.element[i].output_format = output_format;
    143       key.element[i].output_offset = dst_offset;
    144 
    145       dst_offset += emit_sz;
    146    }
    147 
    148    key.nr_elements = vinfo->num_attribs;
    149    key.output_stride = vinfo->size * 4;
    150 
    151    /* Don't bother with caching at this stage:
    152     */
    153    if (!feme->translate ||
    154        translate_key_compare(&feme->translate->key, &key) != 0)
    155    {
    156       translate_key_sanitize(&key);
    157       feme->translate = translate_cache_find(feme->cache,
    158                                              &key);
    159 
    160       feme->translate->set_buffer(feme->translate,
    161 				  draw->pt.nr_vertex_buffers,
    162 				  &feme->point_size,
    163 				  0,
    164 				  ~0);
    165    }
    166 
    167    feme->point_size = draw->rasterizer->point_size;
    168 
    169    for (i = 0; i < draw->pt.nr_vertex_buffers; i++) {
    170       feme->translate->set_buffer(feme->translate,
    171                                   i,
    172                                   ((char *)draw->pt.user.vbuffer[i] +
    173                                    draw->pt.vertex_buffer[i].buffer_offset),
    174                                   draw->pt.vertex_buffer[i].stride,
    175                                   draw->pt.max_index);
    176    }
    177 
    178    *max_vertices = (draw->render->max_vertex_buffer_bytes /
    179                     (vinfo->size * 4));
    180 }
    181 
    182 
    183 static void fetch_emit_run( struct draw_pt_middle_end *middle,
    184                             const unsigned *fetch_elts,
    185                             unsigned fetch_count,
    186                             const ushort *draw_elts,
    187                             unsigned draw_count,
    188                             unsigned prim_flags )
    189 {
    190    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
    191    struct draw_context *draw = feme->draw;
    192    void *hw_verts;
    193 
    194    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
    195     */
    196    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
    197 
    198    draw->render->allocate_vertices( draw->render,
    199                                     (ushort)feme->translate->key.output_stride,
    200                                     (ushort)fetch_count );
    201 
    202    hw_verts = draw->render->map_vertices( draw->render );
    203    if (!hw_verts) {
    204       debug_warn_once("vertex buffer allocation failed (out of memory?)");
    205       return;
    206    }
    207 
    208    /* Single routine to fetch vertices and emit HW verts.
    209     */
    210    feme->translate->run_elts( feme->translate,
    211 			      fetch_elts,
    212 			      fetch_count,
    213                               draw->instance_id,
    214 			      hw_verts );
    215 
    216    if (0) {
    217       unsigned i;
    218       for (i = 0; i < fetch_count; i++) {
    219          debug_printf("\n\nvertex %d:\n", i);
    220          draw_dump_emitted_vertex( feme->vinfo,
    221                                    (const uint8_t *)hw_verts + feme->vinfo->size * 4 * i );
    222       }
    223    }
    224 
    225    draw->render->unmap_vertices( draw->render,
    226                                  0,
    227                                  (ushort)(fetch_count - 1) );
    228 
    229    /* XXX: Draw arrays path to avoid re-emitting index list again and
    230     * again.
    231     */
    232    draw->render->draw_elements( draw->render,
    233                                 draw_elts,
    234                                 draw_count );
    235 
    236    /* Done -- that was easy, wasn't it:
    237     */
    238    draw->render->release_vertices( draw->render );
    239 
    240 }
    241 
    242 
    243 static void fetch_emit_run_linear( struct draw_pt_middle_end *middle,
    244                                    unsigned start,
    245                                    unsigned count,
    246                                    unsigned prim_flags )
    247 {
    248    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
    249    struct draw_context *draw = feme->draw;
    250    void *hw_verts;
    251 
    252    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
    253     */
    254    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
    255 
    256    if (!draw->render->allocate_vertices( draw->render,
    257                                          (ushort)feme->translate->key.output_stride,
    258                                          (ushort)count ))
    259       goto fail;
    260 
    261    hw_verts = draw->render->map_vertices( draw->render );
    262    if (!hw_verts)
    263       goto fail;
    264 
    265    /* Single routine to fetch vertices and emit HW verts.
    266     */
    267    feme->translate->run( feme->translate,
    268                          start,
    269                          count,
    270                          draw->instance_id,
    271                          hw_verts );
    272 
    273    if (0) {
    274       unsigned i;
    275       for (i = 0; i < count; i++) {
    276          debug_printf("\n\nvertex %d:\n", i);
    277          draw_dump_emitted_vertex( feme->vinfo,
    278                                    (const uint8_t *)hw_verts + feme->vinfo->size * 4 * i );
    279       }
    280    }
    281 
    282    draw->render->unmap_vertices( draw->render, 0, count - 1 );
    283 
    284    /* XXX: Draw arrays path to avoid re-emitting index list again and
    285     * again.
    286     */
    287    draw->render->draw_arrays( draw->render, 0, count );
    288 
    289    /* Done -- that was easy, wasn't it:
    290     */
    291    draw->render->release_vertices( draw->render );
    292    return;
    293 
    294 fail:
    295    debug_warn_once("allocate or map of vertex buffer failed (out of memory?)");
    296    return;
    297 }
    298 
    299 
    300 static boolean fetch_emit_run_linear_elts( struct draw_pt_middle_end *middle,
    301                                         unsigned start,
    302                                         unsigned count,
    303                                         const ushort *draw_elts,
    304                                         unsigned draw_count,
    305                                         unsigned prim_flags )
    306 {
    307    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
    308    struct draw_context *draw = feme->draw;
    309    void *hw_verts;
    310 
    311    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
    312     */
    313    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
    314 
    315    if (!draw->render->allocate_vertices( draw->render,
    316                                          (ushort)feme->translate->key.output_stride,
    317                                          (ushort)count ))
    318       return FALSE;
    319 
    320    hw_verts = draw->render->map_vertices( draw->render );
    321    if (!hw_verts)
    322       return FALSE;
    323 
    324    /* Single routine to fetch vertices and emit HW verts.
    325     */
    326    feme->translate->run( feme->translate,
    327                          start,
    328                          count,
    329                          draw->instance_id,
    330                          hw_verts );
    331 
    332    draw->render->unmap_vertices( draw->render, 0, (ushort)(count - 1) );
    333 
    334    /* XXX: Draw arrays path to avoid re-emitting index list again and
    335     * again.
    336     */
    337    draw->render->draw_elements( draw->render,
    338                                 draw_elts,
    339                                 draw_count );
    340 
    341    /* Done -- that was easy, wasn't it:
    342     */
    343    draw->render->release_vertices( draw->render );
    344 
    345    return TRUE;
    346 }
    347 
    348 
    349 static void fetch_emit_finish( struct draw_pt_middle_end *middle )
    350 {
    351    /* nothing to do */
    352 }
    353 
    354 
    355 static void fetch_emit_destroy( struct draw_pt_middle_end *middle )
    356 {
    357    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
    358 
    359    if (feme->cache)
    360       translate_cache_destroy(feme->cache);
    361 
    362    FREE(middle);
    363 }
    364 
    365 
    366 struct draw_pt_middle_end *draw_pt_fetch_emit( struct draw_context *draw )
    367 {
    368    struct fetch_emit_middle_end *fetch_emit = CALLOC_STRUCT( fetch_emit_middle_end );
    369    if (fetch_emit == NULL)
    370       return NULL;
    371 
    372    fetch_emit->cache = translate_cache_create();
    373    if (!fetch_emit->cache) {
    374       FREE(fetch_emit);
    375       return NULL;
    376    }
    377 
    378    fetch_emit->base.prepare    = fetch_emit_prepare;
    379    fetch_emit->base.run        = fetch_emit_run;
    380    fetch_emit->base.run_linear = fetch_emit_run_linear;
    381    fetch_emit->base.run_linear_elts = fetch_emit_run_linear_elts;
    382    fetch_emit->base.finish     = fetch_emit_finish;
    383    fetch_emit->base.destroy    = fetch_emit_destroy;
    384 
    385    fetch_emit->draw = draw;
    386 
    387    return &fetch_emit->base;
    388 }
    389 
    390