Home | History | Annotate | Download | only in draw
      1 /**************************************************************************
      2  *
      3  * Copyright 2009 VMware, Inc.
      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 "draw_gs.h"
     29 
     30 #include "draw_private.h"
     31 #include "draw_context.h"
     32 
     33 #include "tgsi/tgsi_parse.h"
     34 #include "tgsi/tgsi_exec.h"
     35 
     36 #include "pipe/p_shader_tokens.h"
     37 
     38 #include "util/u_math.h"
     39 #include "util/u_memory.h"
     40 #include "util/u_prim.h"
     41 
     42 /* fixme: move it from here */
     43 #define MAX_PRIMITIVES 64
     44 
     45 boolean
     46 draw_gs_init( struct draw_context *draw )
     47 {
     48    draw->gs.tgsi.machine = tgsi_exec_machine_create();
     49    if (!draw->gs.tgsi.machine)
     50       return FALSE;
     51 
     52    draw->gs.tgsi.machine->Primitives = align_malloc(
     53       MAX_PRIMITIVES * sizeof(struct tgsi_exec_vector), 16);
     54    if (!draw->gs.tgsi.machine->Primitives)
     55       return FALSE;
     56    memset(draw->gs.tgsi.machine->Primitives, 0,
     57           MAX_PRIMITIVES * sizeof(struct tgsi_exec_vector));
     58 
     59    return TRUE;
     60 }
     61 
     62 void draw_gs_destroy( struct draw_context *draw )
     63 {
     64    if (!draw->gs.tgsi.machine)
     65       return;
     66 
     67    align_free(draw->gs.tgsi.machine->Primitives);
     68 
     69    tgsi_exec_machine_destroy(draw->gs.tgsi.machine);
     70 }
     71 
     72 void
     73 draw_gs_set_constants(struct draw_context *draw,
     74                       unsigned slot,
     75                       const void *constants,
     76                       unsigned size)
     77 {
     78    /* noop. added here for symmetry with the VS
     79     * code and in case we'll ever want to allign
     80     * the constants, e.g. when we'll change to a
     81     * different interpreter */
     82 }
     83 
     84 
     85 struct draw_geometry_shader *
     86 draw_create_geometry_shader(struct draw_context *draw,
     87                             const struct pipe_shader_state *state)
     88 {
     89    struct draw_geometry_shader *gs;
     90    int i;
     91 
     92    gs = CALLOC_STRUCT(draw_geometry_shader);
     93 
     94    if (!gs)
     95       return NULL;
     96 
     97    gs->draw = draw;
     98    gs->state = *state;
     99    gs->state.tokens = tgsi_dup_tokens(state->tokens);
    100    if (!gs->state.tokens) {
    101       FREE(gs);
    102       return NULL;
    103    }
    104 
    105    tgsi_scan_shader(state->tokens, &gs->info);
    106 
    107    /* setup the defaults */
    108    gs->input_primitive = PIPE_PRIM_TRIANGLES;
    109    gs->output_primitive = PIPE_PRIM_TRIANGLE_STRIP;
    110    gs->max_output_vertices = 32;
    111 
    112    for (i = 0; i < gs->info.num_properties; ++i) {
    113       if (gs->info.properties[i].name ==
    114           TGSI_PROPERTY_GS_INPUT_PRIM)
    115          gs->input_primitive = gs->info.properties[i].data[0];
    116       else if (gs->info.properties[i].name ==
    117                TGSI_PROPERTY_GS_OUTPUT_PRIM)
    118          gs->output_primitive = gs->info.properties[i].data[0];
    119       else if (gs->info.properties[i].name ==
    120                TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES)
    121          gs->max_output_vertices = gs->info.properties[i].data[0];
    122    }
    123 
    124    gs->machine = draw->gs.tgsi.machine;
    125 
    126    if (gs)
    127    {
    128       uint i;
    129       for (i = 0; i < gs->info.num_outputs; i++) {
    130          if (gs->info.output_semantic_name[i] == TGSI_SEMANTIC_POSITION &&
    131              gs->info.output_semantic_index[i] == 0)
    132             gs->position_output = i;
    133       }
    134    }
    135 
    136    return gs;
    137 }
    138 
    139 void draw_bind_geometry_shader(struct draw_context *draw,
    140                                struct draw_geometry_shader *dgs)
    141 {
    142    draw_do_flush(draw, DRAW_FLUSH_STATE_CHANGE);
    143 
    144    if (dgs) {
    145       draw->gs.geometry_shader = dgs;
    146       draw->gs.num_gs_outputs = dgs->info.num_outputs;
    147       draw->gs.position_output = dgs->position_output;
    148       draw_geometry_shader_prepare(dgs, draw);
    149    }
    150    else {
    151       draw->gs.geometry_shader = NULL;
    152       draw->gs.num_gs_outputs = 0;
    153    }
    154 }
    155 
    156 void draw_delete_geometry_shader(struct draw_context *draw,
    157                                  struct draw_geometry_shader *dgs)
    158 {
    159    FREE(dgs);
    160 }
    161 
    162 /*#define DEBUG_OUTPUTS 1*/
    163 static INLINE void
    164 draw_geometry_fetch_outputs(struct draw_geometry_shader *shader,
    165                             int num_primitives,
    166                             float (**p_output)[4])
    167 {
    168    struct tgsi_exec_machine *machine = shader->machine;
    169    unsigned prim_idx, j, slot;
    170    float (*output)[4];
    171 
    172    output = *p_output;
    173 
    174    /* Unswizzle all output results.
    175     */
    176 
    177    for (prim_idx = 0; prim_idx < num_primitives; ++prim_idx) {
    178       unsigned num_verts_per_prim = machine->Primitives[prim_idx];
    179       shader->primitive_lengths[prim_idx +   shader->emitted_primitives] =
    180          machine->Primitives[prim_idx];
    181       shader->emitted_vertices += num_verts_per_prim;
    182       for (j = 0; j < num_verts_per_prim; j++) {
    183          int idx = (prim_idx * num_verts_per_prim + j) *
    184                    shader->info.num_outputs;
    185 #ifdef DEBUG_OUTPUTS
    186          debug_printf("%d) Output vert:\n", idx / shader->info.num_outputs);
    187 #endif
    188          for (slot = 0; slot < shader->info.num_outputs; slot++) {
    189             output[slot][0] = machine->Outputs[idx + slot].xyzw[0].f[0];
    190             output[slot][1] = machine->Outputs[idx + slot].xyzw[1].f[0];
    191             output[slot][2] = machine->Outputs[idx + slot].xyzw[2].f[0];
    192             output[slot][3] = machine->Outputs[idx + slot].xyzw[3].f[0];
    193 #ifdef DEBUG_OUTPUTS
    194             debug_printf("\t%d: %f %f %f %f\n", slot,
    195                          output[slot][0],
    196                          output[slot][1],
    197                          output[slot][2],
    198                          output[slot][3]);
    199 #endif
    200             debug_assert(!util_is_inf_or_nan(output[slot][0]));
    201          }
    202          output = (float (*)[4])((char *)output + shader->vertex_size);
    203       }
    204    }
    205    *p_output = output;
    206          shader->emitted_primitives += num_primitives;
    207 }
    208 
    209 /*#define DEBUG_INPUTS 1*/
    210 static void draw_fetch_gs_input(struct draw_geometry_shader *shader,
    211                                 unsigned *indices,
    212                                 unsigned num_vertices,
    213                                 unsigned prim_idx)
    214 {
    215    struct tgsi_exec_machine *machine = shader->machine;
    216    unsigned slot, vs_slot, i;
    217    unsigned input_vertex_stride = shader->input_vertex_stride;
    218    const float (*input_ptr)[4];
    219 
    220    input_ptr = shader->input;
    221 
    222    for (i = 0; i < num_vertices; ++i) {
    223       const float (*input)[4];
    224 #if DEBUG_INPUTS
    225       debug_printf("%d) vertex index = %d (prim idx = %d)\n",
    226                    i, indices[i], prim_idx);
    227 #endif
    228       input = (const float (*)[4])(
    229          (const char *)input_ptr + (indices[i] * input_vertex_stride));
    230       for (slot = 0, vs_slot = 0; slot < shader->info.num_inputs; ++slot) {
    231          unsigned idx = i * TGSI_EXEC_MAX_INPUT_ATTRIBS + slot;
    232          if (shader->info.input_semantic_name[slot] == TGSI_SEMANTIC_PRIMID) {
    233             machine->Inputs[idx].xyzw[0].f[prim_idx] =
    234                (float)shader->in_prim_idx;
    235             machine->Inputs[idx].xyzw[1].f[prim_idx] =
    236                (float)shader->in_prim_idx;
    237             machine->Inputs[idx].xyzw[2].f[prim_idx] =
    238                (float)shader->in_prim_idx;
    239             machine->Inputs[idx].xyzw[3].f[prim_idx] =
    240                (float)shader->in_prim_idx;
    241          } else {
    242 #if DEBUG_INPUTS
    243             debug_printf("\tSlot = %d, vs_slot = %d, idx = %d:\n",
    244                          slot, vs_slot, idx);
    245 #endif
    246 #if 1
    247             assert(!util_is_inf_or_nan(input[vs_slot][0]));
    248             assert(!util_is_inf_or_nan(input[vs_slot][1]));
    249             assert(!util_is_inf_or_nan(input[vs_slot][2]));
    250             assert(!util_is_inf_or_nan(input[vs_slot][3]));
    251 #endif
    252             machine->Inputs[idx].xyzw[0].f[prim_idx] = input[vs_slot][0];
    253             machine->Inputs[idx].xyzw[1].f[prim_idx] = input[vs_slot][1];
    254             machine->Inputs[idx].xyzw[2].f[prim_idx] = input[vs_slot][2];
    255             machine->Inputs[idx].xyzw[3].f[prim_idx] = input[vs_slot][3];
    256 #if DEBUG_INPUTS
    257             debug_printf("\t\t%f %f %f %f\n",
    258                          machine->Inputs[idx].xyzw[0].f[prim_idx],
    259                          machine->Inputs[idx].xyzw[1].f[prim_idx],
    260                          machine->Inputs[idx].xyzw[2].f[prim_idx],
    261                          machine->Inputs[idx].xyzw[3].f[prim_idx]);
    262 #endif
    263             ++vs_slot;
    264          }
    265       }
    266    }
    267 }
    268 
    269 static void gs_flush(struct draw_geometry_shader *shader,
    270                      unsigned input_primitives)
    271 {
    272    unsigned out_prim_count;
    273    struct tgsi_exec_machine *machine = shader->machine;
    274 
    275    debug_assert(input_primitives > 0 &&
    276                 input_primitives < 4);
    277 
    278    tgsi_set_exec_mask(machine,
    279                       1,
    280                       input_primitives > 1,
    281                       input_primitives > 2,
    282                       input_primitives > 3);
    283 
    284    /* run interpreter */
    285    tgsi_exec_machine_run(machine);
    286 
    287    out_prim_count =
    288       machine->Temps[TGSI_EXEC_TEMP_PRIMITIVE_I].xyzw[TGSI_EXEC_TEMP_PRIMITIVE_C].u[0];
    289 
    290 #if 0
    291    debug_printf("PRIM emitted prims = %d (verts=%d), cur prim count = %d\n",
    292                 shader->emitted_primitives, shader->emitted_vertices,
    293                 out_prim_count);
    294 #endif
    295    draw_geometry_fetch_outputs(shader, out_prim_count,
    296                                &shader->tmp_output);
    297 }
    298 
    299 static void gs_point(struct draw_geometry_shader *shader,
    300                      int idx)
    301 {
    302    unsigned indices[1];
    303 
    304    indices[0] = idx;
    305 
    306    draw_fetch_gs_input(shader, indices, 1, 0);
    307    ++shader->in_prim_idx;
    308 
    309    gs_flush(shader, 1);
    310 }
    311 
    312 static void gs_line(struct draw_geometry_shader *shader,
    313                     int i0, int i1)
    314 {
    315    unsigned indices[2];
    316 
    317    indices[0] = i0;
    318    indices[1] = i1;
    319 
    320    draw_fetch_gs_input(shader, indices, 2, 0);
    321    ++shader->in_prim_idx;
    322 
    323    gs_flush(shader, 1);
    324 }
    325 
    326 static void gs_line_adj(struct draw_geometry_shader *shader,
    327                         int i0, int i1, int i2, int i3)
    328 {
    329    unsigned indices[4];
    330 
    331    indices[0] = i0;
    332    indices[1] = i1;
    333    indices[2] = i2;
    334    indices[3] = i3;
    335 
    336    draw_fetch_gs_input(shader, indices, 4, 0);
    337    ++shader->in_prim_idx;
    338 
    339    gs_flush(shader, 1);
    340 }
    341 
    342 static void gs_tri(struct draw_geometry_shader *shader,
    343                    int i0, int i1, int i2)
    344 {
    345    unsigned indices[3];
    346 
    347    indices[0] = i0;
    348    indices[1] = i1;
    349    indices[2] = i2;
    350 
    351    draw_fetch_gs_input(shader, indices, 3, 0);
    352    ++shader->in_prim_idx;
    353 
    354    gs_flush(shader, 1);
    355 }
    356 
    357 static void gs_tri_adj(struct draw_geometry_shader *shader,
    358                        int i0, int i1, int i2,
    359                        int i3, int i4, int i5)
    360 {
    361    unsigned indices[6];
    362 
    363    indices[0] = i0;
    364    indices[1] = i1;
    365    indices[2] = i2;
    366    indices[3] = i3;
    367    indices[4] = i4;
    368    indices[5] = i5;
    369 
    370    draw_fetch_gs_input(shader, indices, 6, 0);
    371    ++shader->in_prim_idx;
    372 
    373    gs_flush(shader, 1);
    374 }
    375 
    376 #define FUNC         gs_run
    377 #define GET_ELT(idx) (idx)
    378 #include "draw_gs_tmp.h"
    379 
    380 
    381 #define FUNC         gs_run_elts
    382 #define LOCAL_VARS   const ushort *elts = input_prims->elts;
    383 #define GET_ELT(idx) (elts[idx])
    384 #include "draw_gs_tmp.h"
    385 
    386 
    387 /**
    388  * Execute geometry shader using TGSI interpreter.
    389  */
    390 int draw_geometry_shader_run(struct draw_geometry_shader *shader,
    391                              const void *constants[PIPE_MAX_CONSTANT_BUFFERS],
    392                              const unsigned constants_size[PIPE_MAX_CONSTANT_BUFFERS],
    393                              const struct draw_vertex_info *input_verts,
    394                              const struct draw_prim_info *input_prim,
    395                              struct draw_vertex_info *output_verts,
    396                              struct draw_prim_info *output_prims )
    397 {
    398    const float (*input)[4] = (const float (*)[4])input_verts->verts->data;
    399    unsigned input_stride = input_verts->vertex_size;
    400    unsigned vertex_size = input_verts->vertex_size;
    401    struct tgsi_exec_machine *machine = shader->machine;
    402    unsigned num_input_verts = input_prim->linear ?
    403                               input_verts->count :
    404                               input_prim->count;
    405    unsigned num_in_primitives =
    406       MAX2(u_gs_prims_for_vertices(input_prim->prim, num_input_verts),
    407            u_gs_prims_for_vertices(shader->input_primitive, num_input_verts));
    408    unsigned max_out_prims = u_gs_prims_for_vertices(shader->output_primitive,
    409                                                     shader->max_output_vertices)
    410                             * num_in_primitives;
    411 
    412    output_verts->vertex_size = input_verts->vertex_size;
    413    output_verts->stride = input_verts->vertex_size;
    414    output_verts->verts =
    415       (struct vertex_header *)MALLOC(input_verts->vertex_size *
    416                                      num_in_primitives *
    417                                      shader->max_output_vertices);
    418 
    419 
    420 #if 0
    421    debug_printf("%s count = %d (in prims # = %d)\n",
    422                 __FUNCTION__, num_input_verts, num_in_primitives);
    423    debug_printf("\tlinear = %d, prim_info->count = %d\n",
    424                 input_prim->linear, input_prim->count);
    425    debug_printf("\tprimt pipe = %d, shader in = %d, shader out = %d, max out = %d\n",
    426                 input_prim->prim, shader->input_primitive,
    427                 shader->output_primitive,
    428                 shader->max_output_vertices);
    429 #endif
    430 
    431    shader->emitted_vertices = 0;
    432    shader->emitted_primitives = 0;
    433    shader->vertex_size = vertex_size;
    434    shader->tmp_output = (float (*)[4])output_verts->verts->data;
    435    shader->in_prim_idx = 0;
    436    shader->input_vertex_stride = input_stride;
    437    shader->input = input;
    438    if (shader->primitive_lengths) {
    439       FREE(shader->primitive_lengths);
    440    }
    441    shader->primitive_lengths = MALLOC(max_out_prims * sizeof(unsigned));
    442 
    443    tgsi_exec_set_constant_buffers(machine, PIPE_MAX_CONSTANT_BUFFERS,
    444                                   constants, constants_size);
    445 
    446    if (input_prim->linear)
    447       gs_run(shader, input_prim, input_verts,
    448              output_prims, output_verts);
    449    else
    450       gs_run_elts(shader, input_prim, input_verts,
    451                   output_prims, output_verts);
    452 
    453    /* Update prim_info:
    454     */
    455    output_prims->linear = TRUE;
    456    output_prims->elts = NULL;
    457    output_prims->start = 0;
    458    output_prims->count = shader->emitted_vertices;
    459    output_prims->prim = shader->output_primitive;
    460    output_prims->flags = 0x0;
    461    output_prims->primitive_lengths = shader->primitive_lengths;
    462    output_prims->primitive_count = shader->emitted_primitives;
    463    output_verts->count = shader->emitted_vertices;
    464 
    465 #if 0
    466    debug_printf("GS finished, prims = %d, verts = %d\n",
    467                 output_prims->primitive_count,
    468                 output_verts->count);
    469 #endif
    470 
    471    return shader->emitted_vertices;
    472 }
    473 
    474 void draw_geometry_shader_delete(struct draw_geometry_shader *shader)
    475 {
    476    FREE((void*) shader->state.tokens);
    477    FREE(shader);
    478 }
    479 
    480 void draw_geometry_shader_prepare(struct draw_geometry_shader *shader,
    481                                   struct draw_context *draw)
    482 {
    483    if (shader && shader->machine->Tokens != shader->state.tokens) {
    484       tgsi_exec_machine_bind_shader(shader->machine,
    485                                     shader->state.tokens,
    486                                     draw->gs.tgsi.num_samplers,
    487                                     draw->gs.tgsi.samplers);
    488    }
    489 }
    490