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 #include "util/u_math.h"
     29 #include "util/u_memory.h"
     30 #include "util/u_prim.h"
     31 #include "draw/draw_context.h"
     32 #include "draw/draw_vbuf.h"
     33 #include "draw/draw_vertex.h"
     34 #include "draw/draw_pt.h"
     35 #include "draw/draw_vs.h"
     36 #include "draw/draw_gs.h"
     37 
     38 
     39 struct fetch_pipeline_middle_end {
     40    struct draw_pt_middle_end base;
     41    struct draw_context *draw;
     42 
     43    struct pt_emit *emit;
     44    struct pt_so_emit *so_emit;
     45    struct pt_fetch *fetch;
     46    struct pt_post_vs *post_vs;
     47 
     48    unsigned vertex_data_offset;
     49    unsigned vertex_size;
     50    unsigned input_prim;
     51    unsigned opt;
     52 };
     53 
     54 static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle,
     55                                     unsigned prim,
     56 				    unsigned opt,
     57                                     unsigned *max_vertices )
     58 {
     59    struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
     60    struct draw_context *draw = fpme->draw;
     61    struct draw_vertex_shader *vs = draw->vs.vertex_shader;
     62    unsigned i;
     63    unsigned instance_id_index = ~0;
     64 
     65    unsigned gs_out_prim = (draw->gs.geometry_shader ?
     66                            draw->gs.geometry_shader->output_primitive :
     67                            prim);
     68 
     69    /* Add one to num_outputs because the pipeline occasionally tags on
     70     * an additional texcoord, eg for AA lines.
     71     */
     72    unsigned nr = MAX2( vs->info.num_inputs,
     73 		       vs->info.num_outputs + 1 );
     74 
     75    /* Scan for instanceID system value.
     76     */
     77    for (i = 0; i < vs->info.num_inputs; i++) {
     78       if (vs->info.input_semantic_name[i] == TGSI_SEMANTIC_INSTANCEID) {
     79          instance_id_index = i;
     80          break;
     81       }
     82    }
     83 
     84    fpme->input_prim = prim;
     85    fpme->opt = opt;
     86 
     87    /* Always leave room for the vertex header whether we need it or
     88     * not.  It's hard to get rid of it in particular because of the
     89     * viewport code in draw_pt_post_vs.c.
     90     */
     91    fpme->vertex_size = sizeof(struct vertex_header) + nr * 4 * sizeof(float);
     92 
     93 
     94 
     95    draw_pt_fetch_prepare( fpme->fetch,
     96                           vs->info.num_inputs,
     97                           fpme->vertex_size,
     98                           instance_id_index );
     99    /* XXX: it's not really gl rasterization rules we care about here,
    100     * but gl vs dx9 clip spaces.
    101     */
    102    draw_pt_post_vs_prepare( fpme->post_vs,
    103 			    draw->clip_xy,
    104 			    draw->clip_z,
    105 			    draw->clip_user,
    106                             draw->guard_band_xy,
    107 			    draw->identity_viewport,
    108 			    (boolean)draw->rasterizer->gl_rasterization_rules,
    109 			    (draw->vs.edgeflag_output ? TRUE : FALSE) );
    110 
    111    draw_pt_so_emit_prepare( fpme->so_emit );
    112 
    113    if (!(opt & PT_PIPELINE)) {
    114       draw_pt_emit_prepare( fpme->emit,
    115 			    gs_out_prim,
    116                             max_vertices );
    117 
    118       *max_vertices = MAX2( *max_vertices, 4096 );
    119    }
    120    else {
    121       /* limit max fetches by limiting max_vertices */
    122       *max_vertices = 4096;
    123    }
    124 
    125    /* No need to prepare the shader.
    126     */
    127    vs->prepare(vs, draw);
    128 }
    129 
    130 
    131 static void fetch( struct pt_fetch *fetch,
    132                    const struct draw_fetch_info *fetch_info,
    133                    char *output)
    134 {
    135    if (fetch_info->linear) {
    136       draw_pt_fetch_run_linear( fetch,
    137                                 fetch_info->start,
    138                                 fetch_info->count,
    139                                 output );
    140    }
    141    else {
    142       draw_pt_fetch_run( fetch,
    143                          fetch_info->elts,
    144                          fetch_info->count,
    145                          output );
    146    }
    147 }
    148 
    149 
    150 static void pipeline(struct fetch_pipeline_middle_end *fpme,
    151                      const struct draw_vertex_info *vert_info,
    152                      const struct draw_prim_info *prim_info)
    153 {
    154    if (prim_info->linear)
    155       draw_pipeline_run_linear( fpme->draw,
    156                                 vert_info,
    157                                 prim_info);
    158    else
    159       draw_pipeline_run( fpme->draw,
    160                          vert_info,
    161                          prim_info );
    162 }
    163 
    164 static void emit(struct pt_emit *emit,
    165                  const struct draw_vertex_info *vert_info,
    166                  const struct draw_prim_info *prim_info)
    167 {
    168    if (prim_info->linear) {
    169       draw_pt_emit_linear(emit, vert_info, prim_info);
    170    }
    171    else {
    172       draw_pt_emit(emit, vert_info, prim_info);
    173    }
    174 }
    175 
    176 
    177 static void draw_vertex_shader_run(struct draw_vertex_shader *vshader,
    178                                    const void *constants[PIPE_MAX_CONSTANT_BUFFERS],
    179                                    unsigned const_size[PIPE_MAX_CONSTANT_BUFFERS],
    180                                    const struct draw_vertex_info *input_verts,
    181                                    struct draw_vertex_info *output_verts )
    182 {
    183    output_verts->vertex_size = input_verts->vertex_size;
    184    output_verts->stride = input_verts->vertex_size;
    185    output_verts->count = input_verts->count;
    186    output_verts->verts =
    187       (struct vertex_header *)MALLOC(output_verts->vertex_size *
    188                                      align(output_verts->count, 4));
    189 
    190    vshader->run_linear(vshader,
    191                        (const float (*)[4])input_verts->verts->data,
    192                        (      float (*)[4])output_verts->verts->data,
    193                        constants,
    194                        const_size,
    195                        input_verts->count,
    196                        input_verts->vertex_size,
    197                        input_verts->vertex_size);
    198 }
    199 
    200 static void fetch_pipeline_generic( struct draw_pt_middle_end *middle,
    201                                     const struct draw_fetch_info *fetch_info,
    202                                     const struct draw_prim_info *prim_info )
    203 {
    204    struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
    205    struct draw_context *draw = fpme->draw;
    206    struct draw_vertex_shader *vshader = draw->vs.vertex_shader;
    207    struct draw_geometry_shader *gshader = draw->gs.geometry_shader;
    208    struct draw_prim_info gs_prim_info;
    209    struct draw_vertex_info fetched_vert_info;
    210    struct draw_vertex_info vs_vert_info;
    211    struct draw_vertex_info gs_vert_info;
    212    struct draw_vertex_info *vert_info;
    213    unsigned opt = fpme->opt;
    214 
    215    fetched_vert_info.count = fetch_info->count;
    216    fetched_vert_info.vertex_size = fpme->vertex_size;
    217    fetched_vert_info.stride = fpme->vertex_size;
    218    fetched_vert_info.verts =
    219       (struct vertex_header *)MALLOC(fpme->vertex_size *
    220                                      align(fetch_info->count,  4));
    221    if (!fetched_vert_info.verts) {
    222       assert(0);
    223       return;
    224    }
    225 
    226    /* Fetch into our vertex buffer.
    227     */
    228    fetch( fpme->fetch, fetch_info, (char *)fetched_vert_info.verts );
    229 
    230    /* Finished with fetch:
    231     */
    232    fetch_info = NULL;
    233    vert_info = &fetched_vert_info;
    234 
    235    /* Run the shader, note that this overwrites the data[] parts of
    236     * the pipeline verts.
    237     */
    238    if (fpme->opt & PT_SHADE) {
    239       draw_vertex_shader_run(vshader,
    240                              draw->pt.user.vs_constants,
    241                              draw->pt.user.vs_constants_size,
    242                              vert_info,
    243                              &vs_vert_info);
    244 
    245       FREE(vert_info->verts);
    246       vert_info = &vs_vert_info;
    247    }
    248 
    249    if ((fpme->opt & PT_SHADE) && gshader) {
    250       draw_geometry_shader_run(gshader,
    251                                draw->pt.user.gs_constants,
    252                                draw->pt.user.gs_constants_size,
    253                                vert_info,
    254                                prim_info,
    255                                &gs_vert_info,
    256                                &gs_prim_info);
    257 
    258       FREE(vert_info->verts);
    259       vert_info = &gs_vert_info;
    260       prim_info = &gs_prim_info;
    261    }
    262 
    263 
    264    /* Stream output needs to be done before clipping.
    265     *
    266     * XXX: Stream output surely needs to respect the prim_info->elt
    267     *      lists.
    268     */
    269    draw_pt_so_emit( fpme->so_emit,
    270                     vert_info,
    271                     prim_info );
    272 
    273    if (draw_pt_post_vs_run( fpme->post_vs,
    274                             vert_info ))
    275    {
    276       opt |= PT_PIPELINE;
    277    }
    278 
    279    /* Do we need to run the pipeline?
    280     */
    281    if (opt & PT_PIPELINE) {
    282       pipeline( fpme,
    283                 vert_info,
    284                 prim_info );
    285    }
    286    else {
    287       emit( fpme->emit,
    288             vert_info,
    289             prim_info );
    290    }
    291    FREE(vert_info->verts);
    292 }
    293 
    294 static void fetch_pipeline_run( struct draw_pt_middle_end *middle,
    295                                 const unsigned *fetch_elts,
    296                                 unsigned fetch_count,
    297                                 const ushort *draw_elts,
    298                                 unsigned draw_count,
    299                                 unsigned prim_flags )
    300 {
    301    struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
    302    struct draw_fetch_info fetch_info;
    303    struct draw_prim_info prim_info;
    304 
    305    fetch_info.linear = FALSE;
    306    fetch_info.start = 0;
    307    fetch_info.elts = fetch_elts;
    308    fetch_info.count = fetch_count;
    309 
    310    prim_info.linear = FALSE;
    311    prim_info.start = 0;
    312    prim_info.count = draw_count;
    313    prim_info.elts = draw_elts;
    314    prim_info.prim = fpme->input_prim;
    315    prim_info.flags = prim_flags;
    316    prim_info.primitive_count = 1;
    317    prim_info.primitive_lengths = &draw_count;
    318 
    319    fetch_pipeline_generic( middle, &fetch_info, &prim_info );
    320 }
    321 
    322 
    323 static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle,
    324                                        unsigned start,
    325                                        unsigned count,
    326                                        unsigned prim_flags)
    327 {
    328    struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
    329    struct draw_fetch_info fetch_info;
    330    struct draw_prim_info prim_info;
    331 
    332    fetch_info.linear = TRUE;
    333    fetch_info.start = start;
    334    fetch_info.count = count;
    335    fetch_info.elts = NULL;
    336 
    337    prim_info.linear = TRUE;
    338    prim_info.start = 0;
    339    prim_info.count = count;
    340    prim_info.elts = NULL;
    341    prim_info.prim = fpme->input_prim;
    342    prim_info.flags = prim_flags;
    343    prim_info.primitive_count = 1;
    344    prim_info.primitive_lengths = &count;
    345 
    346    fetch_pipeline_generic( middle, &fetch_info, &prim_info );
    347 }
    348 
    349 
    350 
    351 static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle,
    352                                                unsigned start,
    353                                                unsigned count,
    354                                                const ushort *draw_elts,
    355                                                unsigned draw_count,
    356                                                unsigned prim_flags )
    357 {
    358    struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
    359    struct draw_fetch_info fetch_info;
    360    struct draw_prim_info prim_info;
    361 
    362    fetch_info.linear = TRUE;
    363    fetch_info.start = start;
    364    fetch_info.count = count;
    365    fetch_info.elts = NULL;
    366 
    367    prim_info.linear = FALSE;
    368    prim_info.start = 0;
    369    prim_info.count = draw_count;
    370    prim_info.elts = draw_elts;
    371    prim_info.prim = fpme->input_prim;
    372    prim_info.flags = prim_flags;
    373    prim_info.primitive_count = 1;
    374    prim_info.primitive_lengths = &draw_count;
    375 
    376    fetch_pipeline_generic( middle, &fetch_info, &prim_info );
    377 
    378    return TRUE;
    379 }
    380 
    381 
    382 
    383 static void fetch_pipeline_finish( struct draw_pt_middle_end *middle )
    384 {
    385    /* nothing to do */
    386 }
    387 
    388 static void fetch_pipeline_destroy( struct draw_pt_middle_end *middle )
    389 {
    390    struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
    391 
    392    if (fpme->fetch)
    393       draw_pt_fetch_destroy( fpme->fetch );
    394 
    395    if (fpme->emit)
    396       draw_pt_emit_destroy( fpme->emit );
    397 
    398    if (fpme->so_emit)
    399       draw_pt_so_emit_destroy( fpme->so_emit );
    400 
    401    if (fpme->post_vs)
    402       draw_pt_post_vs_destroy( fpme->post_vs );
    403 
    404    FREE(middle);
    405 }
    406 
    407 
    408 struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit( struct draw_context *draw )
    409 {
    410    struct fetch_pipeline_middle_end *fpme = CALLOC_STRUCT( fetch_pipeline_middle_end );
    411    if (!fpme)
    412       goto fail;
    413 
    414    fpme->base.prepare        = fetch_pipeline_prepare;
    415    fpme->base.run            = fetch_pipeline_run;
    416    fpme->base.run_linear     = fetch_pipeline_linear_run;
    417    fpme->base.run_linear_elts = fetch_pipeline_linear_run_elts;
    418    fpme->base.finish         = fetch_pipeline_finish;
    419    fpme->base.destroy        = fetch_pipeline_destroy;
    420 
    421    fpme->draw = draw;
    422 
    423    fpme->fetch = draw_pt_fetch_create( draw );
    424    if (!fpme->fetch)
    425       goto fail;
    426 
    427    fpme->post_vs = draw_pt_post_vs_create( draw );
    428    if (!fpme->post_vs)
    429       goto fail;
    430 
    431    fpme->emit = draw_pt_emit_create( draw );
    432    if (!fpme->emit)
    433       goto fail;
    434 
    435    fpme->so_emit = draw_pt_so_emit_create( draw );
    436    if (!fpme->so_emit)
    437       goto fail;
    438 
    439    return &fpme->base;
    440 
    441  fail:
    442    if (fpme)
    443       fetch_pipeline_destroy( &fpme->base );
    444 
    445    return NULL;
    446 }
    447