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 
     34 #include "util/u_math.h"
     35 #include "util/u_memory.h"
     36 #include "draw/draw_context.h"
     37 #include "draw/draw_private.h"
     38 #include "draw/draw_vbuf.h"
     39 #include "draw/draw_vertex.h"
     40 #include "draw/draw_pt.h"
     41 #include "draw/draw_vs.h"
     42 
     43 
     44 struct fetch_shade_emit;
     45 
     46 
     47 /* Prototype fetch, shade, emit-hw-verts all in one go.
     48  */
     49 struct fetch_shade_emit {
     50    struct draw_pt_middle_end base;
     51    struct draw_context *draw;
     52 
     53    /* Temporaries:
     54     */
     55    const float *constants;
     56    unsigned pitch[PIPE_MAX_ATTRIBS];
     57    const ubyte *src[PIPE_MAX_ATTRIBS];
     58    unsigned prim;
     59 
     60    struct draw_vs_variant_key key;
     61    struct draw_vs_variant *active;
     62 
     63    const struct vertex_info *vinfo;
     64 };
     65 
     66 
     67 
     68 static void
     69 fse_prepare(struct draw_pt_middle_end *middle,
     70             unsigned prim,
     71             unsigned opt,
     72             unsigned *max_vertices)
     73 {
     74    struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
     75    struct draw_context *draw = fse->draw;
     76    unsigned num_vs_inputs = draw->vs.vertex_shader->info.num_inputs;
     77    const struct vertex_info *vinfo;
     78    unsigned i;
     79    unsigned nr_vbs = 0;
     80 
     81    /* Can't support geometry shader on this path.
     82     */
     83    assert(!draw->gs.geometry_shader);
     84 
     85    draw->render->set_primitive(draw->render, prim);
     86 
     87    /* Must do this after set_primitive() above:
     88     */
     89    fse->vinfo = vinfo = draw->render->get_vertex_info(draw->render);
     90 
     91    fse->key.output_stride = vinfo->size * 4;
     92    fse->key.nr_outputs = vinfo->num_attribs;
     93    fse->key.nr_inputs = num_vs_inputs;
     94 
     95    fse->key.nr_elements = MAX2(fse->key.nr_outputs,     /* outputs - translate to hw format */
     96                                fse->key.nr_inputs);     /* inputs - fetch from api format */
     97 
     98    fse->key.viewport = !draw->identity_viewport;
     99    fse->key.clip = draw->clip_xy || draw->clip_z || draw->clip_user;
    100    fse->key.const_vbuffers = 0;
    101 
    102    memset(fse->key.element, 0,
    103           fse->key.nr_elements * sizeof(fse->key.element[0]));
    104 
    105    for (i = 0; i < num_vs_inputs; i++) {
    106       const struct pipe_vertex_element *src = &draw->pt.vertex_element[i];
    107       fse->key.element[i].in.format = src->src_format;
    108 
    109       /* Consider ignoring these, ie make generated programs
    110        * independent of this state:
    111        */
    112       fse->key.element[i].in.buffer = src->vertex_buffer_index;
    113       fse->key.element[i].in.offset = src->src_offset;
    114       nr_vbs = MAX2(nr_vbs, src->vertex_buffer_index + 1);
    115    }
    116 
    117    for (i = 0; i < 5 && i < nr_vbs; i++) {
    118       if (draw->pt.vertex_buffer[i].stride == 0)
    119          fse->key.const_vbuffers |= (1<<i);
    120    }
    121 
    122    if (0) debug_printf("%s: lookup const_vbuffers: %x\n", __FUNCTION__, fse->key.const_vbuffers);
    123 
    124    {
    125       unsigned dst_offset = 0;
    126 
    127       for (i = 0; i < vinfo->num_attribs; i++) {
    128          unsigned emit_sz = draw_translate_vinfo_size(vinfo->attrib[i].emit);
    129 
    130          /* doesn't handle EMIT_OMIT */
    131          assert(emit_sz != 0);
    132 
    133          /* The elements in the key correspond to vertex shader output
    134           * numbers, not to positions in the hw vertex description --
    135           * that's handled by the output_offset field.
    136           */
    137          fse->key.element[i].out.format = vinfo->attrib[i].emit;
    138          fse->key.element[i].out.vs_output = vinfo->attrib[i].src_index;
    139          fse->key.element[i].out.offset = dst_offset;
    140 
    141          dst_offset += emit_sz;
    142          assert(fse->key.output_stride >= dst_offset);
    143       }
    144    }
    145 
    146    fse->active = draw_vs_lookup_variant( draw->vs.vertex_shader,
    147                                          &fse->key );
    148 
    149    if (!fse->active) {
    150       assert(0);
    151       return ;
    152    }
    153 
    154    if (0) debug_printf("%s: found const_vbuffers: %x\n", __FUNCTION__,
    155                        fse->active->key.const_vbuffers);
    156 
    157    /* Now set buffer pointers:
    158     */
    159    for (i = 0; i < draw->pt.nr_vertex_buffers; i++) {
    160       fse->active->set_buffer( fse->active,
    161                                i,
    162                                ((const ubyte *) draw->pt.user.vbuffer[i] +
    163                                 draw->pt.vertex_buffer[i].buffer_offset),
    164                               draw->pt.vertex_buffer[i].stride,
    165                               draw->pt.max_index );
    166    }
    167 
    168    *max_vertices = (draw->render->max_vertex_buffer_bytes /
    169                     (vinfo->size * 4));
    170 
    171    /* Probably need to do this somewhere (or fix exec shader not to
    172     * need it):
    173     */
    174    if (1) {
    175       struct draw_vertex_shader *vs = draw->vs.vertex_shader;
    176       vs->prepare(vs, draw);
    177    }
    178 }
    179 
    180 
    181 
    182 static void
    183 fse_run_linear(struct draw_pt_middle_end *middle,
    184                unsigned start,
    185                unsigned count,
    186                unsigned prim_flags)
    187 {
    188    struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
    189    struct draw_context *draw = fse->draw;
    190    char *hw_verts;
    191 
    192    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
    193     */
    194    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
    195 
    196    if (!draw->render->allocate_vertices( draw->render,
    197                                          (ushort)fse->key.output_stride,
    198                                          (ushort)count ))
    199       goto fail;
    200 
    201    hw_verts = draw->render->map_vertices( draw->render );
    202    if (!hw_verts)
    203       goto fail;
    204 
    205    /* Single routine to fetch vertices, run shader and emit HW verts.
    206     * Clipping is done elsewhere -- either by the API or on hardware,
    207     * or for some other reason not required...
    208     */
    209    fse->active->run_linear( fse->active,
    210                             start, count,
    211                             hw_verts );
    212 
    213    if (0) {
    214       unsigned i;
    215       for (i = 0; i < count; i++) {
    216          debug_printf("\n\n%s vertex %d: (stride %d, offset %d)\n", __FUNCTION__, i,
    217                       fse->key.output_stride,
    218                       fse->key.output_stride * i);
    219 
    220          draw_dump_emitted_vertex( fse->vinfo,
    221                                    (const uint8_t *)hw_verts + fse->key.output_stride * i );
    222       }
    223    }
    224 
    225    draw->render->unmap_vertices( draw->render, 0, (ushort)(count - 1) );
    226 
    227    /* Draw arrays path to avoid re-emitting index list again and
    228     * again.
    229     */
    230    draw->render->draw_arrays( draw->render,
    231                               0,
    232                               count );
    233 
    234    draw->render->release_vertices( draw->render );
    235 
    236    return;
    237 
    238 fail:
    239    debug_warn_once("allocate or map of vertex buffer failed (out of memory?)");
    240    return;
    241 }
    242 
    243 
    244 static void
    245 fse_run(struct draw_pt_middle_end *middle,
    246         const unsigned *fetch_elts,
    247         unsigned fetch_count,
    248         const ushort *draw_elts,
    249         unsigned draw_count,
    250         unsigned prim_flags )
    251 {
    252    struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
    253    struct draw_context *draw = fse->draw;
    254    void *hw_verts;
    255 
    256    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
    257     */
    258    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
    259 
    260    if (!draw->render->allocate_vertices( draw->render,
    261                                          (ushort)fse->key.output_stride,
    262                                          (ushort)fetch_count ))
    263       goto fail;
    264 
    265    hw_verts = draw->render->map_vertices( draw->render );
    266    if (!hw_verts)
    267       goto fail;
    268 
    269    /* Single routine to fetch vertices, run shader and emit HW verts.
    270     */
    271    fse->active->run_elts( fse->active,
    272                           fetch_elts,
    273                           fetch_count,
    274                           hw_verts );
    275 
    276    if (0) {
    277       unsigned i;
    278       for (i = 0; i < fetch_count; i++) {
    279          debug_printf("\n\n%s vertex %d:\n", __FUNCTION__, i);
    280          draw_dump_emitted_vertex( fse->vinfo,
    281                                    (const uint8_t *)hw_verts +
    282                                    fse->key.output_stride * i );
    283       }
    284    }
    285 
    286    draw->render->unmap_vertices( draw->render, 0, (ushort)(fetch_count - 1) );
    287 
    288    draw->render->draw_elements( draw->render,
    289                                 draw_elts,
    290                                 draw_count );
    291 
    292    draw->render->release_vertices( draw->render );
    293    return;
    294 
    295 fail:
    296    debug_warn_once("allocate or map of vertex buffer failed (out of memory?)");
    297    return;
    298 }
    299 
    300 
    301 
    302 static boolean
    303 fse_run_linear_elts(struct draw_pt_middle_end *middle,
    304                     unsigned start,
    305                     unsigned count,
    306                     const ushort *draw_elts,
    307                     unsigned draw_count,
    308                     unsigned prim_flags)
    309 {
    310    struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
    311    struct draw_context *draw = fse->draw;
    312    char *hw_verts;
    313 
    314    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
    315     */
    316    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
    317 
    318    if (!draw->render->allocate_vertices( draw->render,
    319                                          (ushort)fse->key.output_stride,
    320                                          (ushort)count ))
    321       return FALSE;
    322 
    323    hw_verts = draw->render->map_vertices( draw->render );
    324    if (!hw_verts)
    325       return FALSE;
    326 
    327    /* Single routine to fetch vertices, run shader and emit HW verts.
    328     * Clipping is done elsewhere -- either by the API or on hardware,
    329     * or for some other reason not required...
    330     */
    331    fse->active->run_linear( fse->active,
    332                             start, count,
    333                             hw_verts );
    334 
    335    draw->render->draw_elements( draw->render,
    336                                 draw_elts,
    337                                 draw_count );
    338 
    339    draw->render->unmap_vertices( draw->render, 0, (ushort)(count - 1) );
    340 
    341    draw->render->release_vertices( draw->render );
    342 
    343    return TRUE;
    344 }
    345 
    346 
    347 
    348 static void
    349 fse_finish(struct draw_pt_middle_end *middle)
    350 {
    351 }
    352 
    353 
    354 static void
    355 fse_destroy(struct draw_pt_middle_end *middle)
    356 {
    357    FREE(middle);
    358 }
    359 
    360 
    361 struct draw_pt_middle_end *
    362 draw_pt_middle_fse(struct draw_context *draw)
    363 {
    364    struct fetch_shade_emit *fse = CALLOC_STRUCT(fetch_shade_emit);
    365    if (!fse)
    366       return NULL;
    367 
    368    fse->base.prepare = fse_prepare;
    369    fse->base.run = fse_run;
    370    fse->base.run_linear = fse_run_linear;
    371    fse->base.run_linear_elts = fse_run_linear_elts;
    372    fse->base.finish = fse_finish;
    373    fse->base.destroy = fse_destroy;
    374    fse->draw = draw;
    375 
    376    return &fse->base;
    377 }
    378