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_context.h"
     31 #include "draw/draw_vbuf.h"
     32 #include "draw/draw_vertex.h"
     33 #include "draw/draw_pt.h"
     34 
     35 #include "pipe/p_state.h"
     36 
     37 #include "util/u_math.h"
     38 #include "util/u_memory.h"
     39 
     40 struct pt_so_emit {
     41    struct draw_context *draw;
     42 
     43    unsigned input_vertex_stride;
     44    const float (*inputs)[4];
     45 
     46    boolean has_so;
     47 
     48    unsigned emitted_primitives;
     49    unsigned emitted_vertices;
     50    unsigned generated_primitives;
     51 };
     52 
     53 
     54 void draw_pt_so_emit_prepare(struct pt_so_emit *emit)
     55 {
     56    struct draw_context *draw = emit->draw;
     57 
     58    emit->has_so = (draw->vs.vertex_shader->state.stream_output.num_outputs > 0);
     59 
     60    /* if we have a state with outputs make sure we have
     61     * buffers to output to */
     62    if (emit->has_so) {
     63       boolean has_valid_buffer = FALSE;
     64       unsigned i;
     65       for (i = 0; i < draw->so.num_targets; ++i) {
     66          if (draw->so.targets[i]) {
     67             has_valid_buffer = TRUE;
     68             break;
     69          }
     70       }
     71       emit->has_so = has_valid_buffer;
     72    }
     73 
     74    if (!emit->has_so)
     75       return;
     76 
     77    /* XXX: need to flush to get prim_vbuf.c to release its allocation??
     78     */
     79    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
     80 }
     81 
     82 static void so_emit_prim(struct pt_so_emit *so,
     83                          unsigned *indices,
     84                          unsigned num_vertices)
     85 {
     86    unsigned slot, i;
     87    unsigned input_vertex_stride = so->input_vertex_stride;
     88    struct draw_context *draw = so->draw;
     89    const float (*input_ptr)[4];
     90    const struct pipe_stream_output_info *state =
     91       &draw->vs.vertex_shader->state.stream_output;
     92    float *buffer;
     93    int buffer_total_bytes[PIPE_MAX_SO_BUFFERS];
     94 
     95    input_ptr = so->inputs;
     96 
     97    ++so->generated_primitives;
     98 
     99    for (i = 0; i < draw->so.num_targets; i++) {
    100       struct draw_so_target *target = draw->so.targets[i];
    101       buffer_total_bytes[i] = target->internal_offset;
    102    }
    103 
    104    /* check have we space to emit prim first - if not don't do anything */
    105    for (i = 0; i < num_vertices; ++i) {
    106       for (slot = 0; slot < state->num_outputs; ++slot) {
    107          unsigned num_comps = state->output[slot].num_components;
    108          int ob = state->output[slot].output_buffer;
    109 
    110          if ((buffer_total_bytes[ob] + num_comps * sizeof(float)) >
    111              draw->so.targets[ob]->target.buffer_size) {
    112             return;
    113          }
    114          buffer_total_bytes[ob] += num_comps * sizeof(float);
    115       }
    116    }
    117 
    118    for (i = 0; i < num_vertices; ++i) {
    119       const float (*input)[4];
    120       unsigned total_written_compos = 0;
    121       /*debug_printf("%d) vertex index = %d (prim idx = %d)\n", i, indices[i], prim_idx);*/
    122       input = (const float (*)[4])(
    123          (const char *)input_ptr + (indices[i] * input_vertex_stride));
    124 
    125       for (slot = 0; slot < state->num_outputs; ++slot) {
    126          unsigned idx = state->output[slot].register_index;
    127          unsigned start_comp = state->output[slot].start_component;
    128          unsigned num_comps = state->output[slot].num_components;
    129          int ob = state->output[slot].output_buffer;
    130 
    131          buffer = (float *)((char *)draw->so.targets[ob]->mapping +
    132                             draw->so.targets[ob]->target.buffer_offset +
    133                             draw->so.targets[ob]->internal_offset);
    134          memcpy(buffer, &input[idx][start_comp], num_comps * sizeof(float));
    135          draw->so.targets[ob]->internal_offset += num_comps * sizeof(float);
    136          total_written_compos += num_comps;
    137       }
    138    }
    139    so->emitted_vertices += num_vertices;
    140    ++so->emitted_primitives;
    141 }
    142 
    143 static void so_point(struct pt_so_emit *so, int idx)
    144 {
    145    unsigned indices[1];
    146 
    147    indices[0] = idx;
    148 
    149    so_emit_prim(so, indices, 1);
    150 }
    151 
    152 static void so_line(struct pt_so_emit *so, int i0, int i1)
    153 {
    154    unsigned indices[2];
    155 
    156    indices[0] = i0;
    157    indices[1] = i1;
    158 
    159    so_emit_prim(so, indices, 2);
    160 }
    161 
    162 static void so_tri(struct pt_so_emit *so, int i0, int i1, int i2)
    163 {
    164    unsigned indices[3];
    165 
    166    indices[0] = i0;
    167    indices[1] = i1;
    168    indices[2] = i2;
    169 
    170    so_emit_prim(so, indices, 3);
    171 }
    172 
    173 
    174 #define FUNC         so_run_linear
    175 #define GET_ELT(idx) (start + (idx))
    176 #include "draw_so_emit_tmp.h"
    177 
    178 
    179 #define FUNC         so_run_elts
    180 #define LOCAL_VARS   const ushort *elts = input_prims->elts;
    181 #define GET_ELT(idx) (elts[start + (idx)])
    182 #include "draw_so_emit_tmp.h"
    183 
    184 
    185 void draw_pt_so_emit( struct pt_so_emit *emit,
    186                       const struct draw_vertex_info *input_verts,
    187                       const struct draw_prim_info *input_prims )
    188 {
    189    struct draw_context *draw = emit->draw;
    190    struct vbuf_render *render = draw->render;
    191    unsigned start, i;
    192 
    193    if (!emit->has_so)
    194       return;
    195 
    196    emit->emitted_vertices = 0;
    197    emit->emitted_primitives = 0;
    198    emit->generated_primitives = 0;
    199    emit->input_vertex_stride = input_verts->stride;
    200    emit->inputs = (const float (*)[4])input_verts->verts->data;
    201 
    202    /* XXX: need to flush to get prim_vbuf.c to release its allocation??*/
    203    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
    204 
    205    for (start = i = 0; i < input_prims->primitive_count;
    206         start += input_prims->primitive_lengths[i], i++)
    207    {
    208       unsigned count = input_prims->primitive_lengths[i];
    209 
    210       if (input_prims->linear) {
    211          so_run_linear(emit, input_prims, input_verts,
    212                        start, count);
    213       } else {
    214          so_run_elts(emit, input_prims, input_verts,
    215                      start, count);
    216       }
    217    }
    218 
    219    render->set_stream_output_info(render,
    220                                   emit->emitted_primitives,
    221                                   emit->emitted_vertices,
    222                                   emit->generated_primitives);
    223 }
    224 
    225 
    226 struct pt_so_emit *draw_pt_so_emit_create( struct draw_context *draw )
    227 {
    228    struct pt_so_emit *emit = CALLOC_STRUCT(pt_so_emit);
    229    if (!emit)
    230       return NULL;
    231 
    232    emit->draw = draw;
    233 
    234    return emit;
    235 }
    236 
    237 void draw_pt_so_emit_destroy( struct pt_so_emit *emit )
    238 {
    239    FREE(emit);
    240 }
    241