Home | History | Annotate | Download | only in draw
      1 /**************************************************************************
      2  *
      3  * Copyright 2010 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 VMWARE 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/draw_private.h"
     29 #include "draw/draw_vs.h"
     30 #include "draw/draw_gs.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 
     36 #include "pipe/p_state.h"
     37 
     38 #include "util/u_math.h"
     39 #include "util/u_memory.h"
     40 
     41 struct pt_so_emit {
     42    struct draw_context *draw;
     43 
     44    unsigned input_vertex_stride;
     45    const float (*inputs)[4];
     46    const float *pre_clip_pos;
     47    boolean has_so;
     48    boolean use_pre_clip_pos;
     49    int pos_idx;
     50    unsigned emitted_primitives;
     51    unsigned generated_primitives;
     52 };
     53 
     54 static const struct pipe_stream_output_info *
     55 draw_so_info(const struct draw_context *draw)
     56 {
     57    const struct pipe_stream_output_info *state = NULL;
     58 
     59    if (draw->gs.geometry_shader) {
     60       state = &draw->gs.geometry_shader->state.stream_output;
     61    } else {
     62       state = &draw->vs.vertex_shader->state.stream_output;
     63    }
     64 
     65    return state;
     66 }
     67 
     68 static inline boolean
     69 draw_has_so(const struct draw_context *draw)
     70 {
     71    const struct pipe_stream_output_info *state = draw_so_info(draw);
     72 
     73    if (state && state->num_outputs > 0)
     74       return TRUE;
     75 
     76    return FALSE;
     77 }
     78 
     79 void draw_pt_so_emit_prepare(struct pt_so_emit *emit, boolean use_pre_clip_pos)
     80 {
     81    struct draw_context *draw = emit->draw;
     82 
     83    emit->use_pre_clip_pos = use_pre_clip_pos;
     84    emit->has_so = draw_has_so(draw);
     85    if (use_pre_clip_pos)
     86       emit->pos_idx = draw_current_shader_position_output(draw);
     87 
     88    /* if we have a state with outputs make sure we have
     89     * buffers to output to */
     90    if (emit->has_so) {
     91       boolean has_valid_buffer = FALSE;
     92       unsigned i;
     93       for (i = 0; i < draw->so.num_targets; ++i) {
     94          if (draw->so.targets[i]) {
     95             has_valid_buffer = TRUE;
     96             break;
     97          }
     98       }
     99       emit->has_so = has_valid_buffer;
    100    }
    101 
    102    if (!emit->has_so)
    103       return;
    104 
    105    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
    106     */
    107    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
    108 }
    109 
    110 static void so_emit_prim(struct pt_so_emit *so,
    111                          unsigned *indices,
    112                          unsigned num_vertices)
    113 {
    114    unsigned slot, i;
    115    unsigned input_vertex_stride = so->input_vertex_stride;
    116    struct draw_context *draw = so->draw;
    117    const float (*input_ptr)[4];
    118    const float *pcp_ptr = NULL;
    119    const struct pipe_stream_output_info *state = draw_so_info(draw);
    120    float *buffer;
    121    int buffer_total_bytes[PIPE_MAX_SO_BUFFERS];
    122    boolean buffer_written[PIPE_MAX_SO_BUFFERS] = {0};
    123 
    124    input_ptr = so->inputs;
    125    if (so->use_pre_clip_pos)
    126       pcp_ptr = so->pre_clip_pos;
    127 
    128    ++so->generated_primitives;
    129 
    130    for (i = 0; i < draw->so.num_targets; i++) {
    131       struct draw_so_target *target = draw->so.targets[i];
    132       if (target) {
    133          buffer_total_bytes[i] = target->internal_offset;
    134       } else {
    135          buffer_total_bytes[i] = 0;
    136       }
    137    }
    138 
    139    /* check have we space to emit prim first - if not don't do anything */
    140    for (i = 0; i < num_vertices; ++i) {
    141       unsigned ob;
    142       for (slot = 0; slot < state->num_outputs; ++slot) {
    143          unsigned num_comps = state->output[slot].num_components;
    144          int ob = state->output[slot].output_buffer;
    145          unsigned dst_offset = state->output[slot].dst_offset * sizeof(float);
    146          unsigned write_size = num_comps * sizeof(float);
    147          /* If a buffer is missing then that's equivalent to
    148           * an overflow */
    149          if (!draw->so.targets[ob]) {
    150             return;
    151          }
    152          if ((buffer_total_bytes[ob] + write_size + dst_offset) >
    153              draw->so.targets[ob]->target.buffer_size) {
    154             return;
    155          }
    156       }
    157       for (ob = 0; ob < draw->so.num_targets; ++ob) {
    158          buffer_total_bytes[ob] += state->stride[ob] * sizeof(float);
    159       }
    160    }
    161 
    162    for (i = 0; i < num_vertices; ++i) {
    163       const float (*input)[4];
    164       const float *pre_clip_pos = NULL;
    165       unsigned  ob;
    166 
    167       input = (const float (*)[4])(
    168          (const char *)input_ptr + (indices[i] * input_vertex_stride));
    169 
    170       if (pcp_ptr)
    171          pre_clip_pos = (const float *)(
    172          (const char *)pcp_ptr + (indices[i] * input_vertex_stride));
    173 
    174       for (slot = 0; slot < state->num_outputs; ++slot) {
    175          unsigned idx = state->output[slot].register_index;
    176          unsigned start_comp = state->output[slot].start_component;
    177          unsigned num_comps = state->output[slot].num_components;
    178 
    179          ob = state->output[slot].output_buffer;
    180          buffer_written[ob] = TRUE;
    181 
    182          buffer = (float *)((char *)draw->so.targets[ob]->mapping +
    183                             draw->so.targets[ob]->target.buffer_offset +
    184                             draw->so.targets[ob]->internal_offset) +
    185             state->output[slot].dst_offset;
    186 
    187          if (idx == so->pos_idx && pcp_ptr)
    188             memcpy(buffer, &pre_clip_pos[start_comp],
    189                    num_comps * sizeof(float));
    190          else
    191             memcpy(buffer, &input[idx][start_comp],
    192                    num_comps * sizeof(float));
    193 #if 0
    194          {
    195             int j;
    196             debug_printf("VERT[%d], offset = %d, slot[%d] sc = %d, num_c = %d, idx = %d = [",
    197                          i,
    198                          draw->so.targets[ob]->internal_offset,
    199                          slot, start_comp, num_comps, idx);
    200             for (j = 0; j < num_comps; ++j) {
    201                unsigned *ubuffer = (unsigned*)buffer;
    202                debug_printf("%d (0x%x), ", ubuffer[j], ubuffer[j]);
    203             }
    204             debug_printf("]\n");
    205          }
    206 #endif
    207       }
    208       for (ob = 0; ob < draw->so.num_targets; ++ob) {
    209          struct draw_so_target *target = draw->so.targets[ob];
    210          if (target && buffer_written[ob]) {
    211             target->internal_offset += state->stride[ob] * sizeof(float);
    212          }
    213       }
    214    }
    215    ++so->emitted_primitives;
    216 }
    217 
    218 static void so_point(struct pt_so_emit *so, int idx)
    219 {
    220    unsigned indices[1];
    221 
    222    indices[0] = idx;
    223 
    224    so_emit_prim(so, indices, 1);
    225 }
    226 
    227 static void so_line(struct pt_so_emit *so, int i0, int i1)
    228 {
    229    unsigned indices[2];
    230 
    231    indices[0] = i0;
    232    indices[1] = i1;
    233 
    234    so_emit_prim(so, indices, 2);
    235 }
    236 
    237 static void so_tri(struct pt_so_emit *so, int i0, int i1, int i2)
    238 {
    239    unsigned indices[3];
    240 
    241    indices[0] = i0;
    242    indices[1] = i1;
    243    indices[2] = i2;
    244 
    245    so_emit_prim(so, indices, 3);
    246 }
    247 
    248 
    249 #define FUNC         so_run_linear
    250 #define GET_ELT(idx) (start + (idx))
    251 #include "draw_so_emit_tmp.h"
    252 
    253 
    254 #define FUNC         so_run_elts
    255 #define LOCAL_VARS   const ushort *elts = input_prims->elts;
    256 #define GET_ELT(idx) (elts[start + (idx)])
    257 #include "draw_so_emit_tmp.h"
    258 
    259 
    260 void draw_pt_so_emit( struct pt_so_emit *emit,
    261                       const struct draw_vertex_info *input_verts,
    262                       const struct draw_prim_info *input_prims )
    263 {
    264    struct draw_context *draw = emit->draw;
    265    struct vbuf_render *render = draw->render;
    266    unsigned start, i;
    267 
    268    if (!emit->has_so)
    269       return;
    270 
    271    if (!draw->so.num_targets)
    272       return;
    273 
    274    emit->emitted_primitives = 0;
    275    emit->generated_primitives = 0;
    276    emit->input_vertex_stride = input_verts->stride;
    277    if (emit->use_pre_clip_pos)
    278       emit->pre_clip_pos = input_verts->verts->clip_pos;
    279 
    280    emit->inputs = (const float (*)[4])input_verts->verts->data;
    281 
    282    /* XXX: need to flush to get prim_vbuf.c to release its allocation??*/
    283    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
    284 
    285    for (start = i = 0; i < input_prims->primitive_count;
    286         start += input_prims->primitive_lengths[i], i++)
    287    {
    288       unsigned count = input_prims->primitive_lengths[i];
    289 
    290       if (input_prims->linear) {
    291          so_run_linear(emit, input_prims, input_verts,
    292                        start, count);
    293       } else {
    294          so_run_elts(emit, input_prims, input_verts,
    295                      start, count);
    296       }
    297    }
    298 
    299    render->set_stream_output_info(render,
    300                                   emit->emitted_primitives,
    301                                   emit->generated_primitives);
    302 }
    303 
    304 
    305 struct pt_so_emit *draw_pt_so_emit_create( struct draw_context *draw )
    306 {
    307    struct pt_so_emit *emit = CALLOC_STRUCT(pt_so_emit);
    308    if (!emit)
    309       return NULL;
    310 
    311    emit->draw = draw;
    312 
    313    return emit;
    314 }
    315 
    316 void draw_pt_so_emit_destroy( struct pt_so_emit *emit )
    317 {
    318    FREE(emit);
    319 }
    320