Home | History | Annotate | Download | only in draw
      1 /**************************************************************************
      2  *
      3  * Copyright 2007 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 /* Authors:  Keith Whitwell <keithw (at) vmware.com>
     29  */
     30 
     31 /**
     32  * Notes on wide points and sprite mode:
     33  *
     34  * In wide point/sprite mode we effectively need to convert each incoming
     35  * vertex into four outgoing vertices specifying the corners of a quad.
     36  * Since we don't (yet) have geometry shaders, we have to handle this here
     37  * in the draw module.
     38  *
     39  * For sprites, it also means that this is where we have to handle texcoords
     40  * for the vertices of the quad.  OpenGL's GL_COORD_REPLACE state specifies
     41  * if/how enabled texcoords are automatically generated for sprites.  We pass
     42  * that info through gallium in the pipe_rasterizer_state::sprite_coord_mode
     43  * array.
     44  *
     45  * Additionally, GLSL's gl_PointCoord fragment attribute has to be handled
     46  * here as well.  This is basically an additional texture/generic attribute
     47  * that varies .x from 0 to 1 horizontally across the point and varies .y
     48  * vertically from 0 to 1 down the sprite.
     49  *
     50  * With geometry shaders, the state tracker could create a GS to do
     51  * most/all of this.
     52  */
     53 
     54 
     55 #include "pipe/p_screen.h"
     56 #include "pipe/p_context.h"
     57 #include "util/u_math.h"
     58 #include "util/u_memory.h"
     59 #include "pipe/p_defines.h"
     60 #include "pipe/p_shader_tokens.h"
     61 #include "draw_fs.h"
     62 #include "draw_vs.h"
     63 #include "draw_pipe.h"
     64 
     65 
     66 struct widepoint_stage {
     67    struct draw_stage stage;  /**< base class */
     68 
     69    float half_point_size;
     70 
     71    float xbias;
     72    float ybias;
     73 
     74    /** for automatic texcoord generation/replacement */
     75    uint num_texcoord_gen;
     76    uint texcoord_gen_slot[PIPE_MAX_SHADER_OUTPUTS];
     77 
     78    /* TGSI_SEMANTIC to which sprite_coord_enable applies */
     79    unsigned sprite_coord_semantic;
     80 
     81    int psize_slot;
     82 };
     83 
     84 
     85 
     86 static inline struct widepoint_stage *
     87 widepoint_stage( struct draw_stage *stage )
     88 {
     89    return (struct widepoint_stage *)stage;
     90 }
     91 
     92 
     93 /**
     94  * Set the vertex texcoords for sprite mode.
     95  * Coords may be left untouched or set to a right-side-up or upside-down
     96  * orientation.
     97  */
     98 static void set_texcoords(const struct widepoint_stage *wide,
     99                           struct vertex_header *v, const float tc[4])
    100 {
    101    const struct draw_context *draw = wide->stage.draw;
    102    const struct pipe_rasterizer_state *rast = draw->rasterizer;
    103    const uint texcoord_mode = rast->sprite_coord_mode;
    104    uint i;
    105 
    106    for (i = 0; i < wide->num_texcoord_gen; i++) {
    107       const uint slot = wide->texcoord_gen_slot[i];
    108       v->data[slot][0] = tc[0];
    109       if (texcoord_mode == PIPE_SPRITE_COORD_LOWER_LEFT)
    110          v->data[slot][1] = 1.0f - tc[1];
    111       else
    112          v->data[slot][1] = tc[1];
    113       v->data[slot][2] = tc[2];
    114       v->data[slot][3] = tc[3];
    115    }
    116 }
    117 
    118 
    119 /* If there are lots of sprite points (and why wouldn't there be?) it
    120  * would probably be more sensible to change hardware setup to
    121  * optimize this rather than doing the whole thing in software like
    122  * this.
    123  */
    124 static void widepoint_point( struct draw_stage *stage,
    125                              struct prim_header *header )
    126 {
    127    const struct widepoint_stage *wide = widepoint_stage(stage);
    128    const unsigned pos = draw_current_shader_position_output(stage->draw);
    129    const boolean sprite = (boolean) stage->draw->rasterizer->point_quad_rasterization;
    130    float half_size;
    131    float left_adj, right_adj, bot_adj, top_adj;
    132 
    133    struct prim_header tri;
    134 
    135    /* four dups of original vertex */
    136    struct vertex_header *v0 = dup_vert(stage, header->v[0], 0);
    137    struct vertex_header *v1 = dup_vert(stage, header->v[0], 1);
    138    struct vertex_header *v2 = dup_vert(stage, header->v[0], 2);
    139    struct vertex_header *v3 = dup_vert(stage, header->v[0], 3);
    140 
    141    float *pos0 = v0->data[pos];
    142    float *pos1 = v1->data[pos];
    143    float *pos2 = v2->data[pos];
    144    float *pos3 = v3->data[pos];
    145 
    146    /* point size is either per-vertex or fixed size */
    147    if (wide->psize_slot >= 0) {
    148       half_size = header->v[0]->data[wide->psize_slot][0];
    149       half_size *= 0.5f;
    150    }
    151    else {
    152       half_size = wide->half_point_size;
    153    }
    154 
    155    left_adj = -half_size + wide->xbias;
    156    right_adj = half_size + wide->xbias;
    157    bot_adj = half_size + wide->ybias;
    158    top_adj = -half_size + wide->ybias;
    159 
    160    pos0[0] += left_adj;
    161    pos0[1] += top_adj;
    162 
    163    pos1[0] += left_adj;
    164    pos1[1] += bot_adj;
    165 
    166    pos2[0] += right_adj;
    167    pos2[1] += top_adj;
    168 
    169    pos3[0] += right_adj;
    170    pos3[1] += bot_adj;
    171 
    172    if (sprite) {
    173       static const float tex00[4] = { 0, 0, 0, 1 };
    174       static const float tex01[4] = { 0, 1, 0, 1 };
    175       static const float tex11[4] = { 1, 1, 0, 1 };
    176       static const float tex10[4] = { 1, 0, 0, 1 };
    177       set_texcoords( wide, v0, tex00 );
    178       set_texcoords( wide, v1, tex01 );
    179       set_texcoords( wide, v2, tex10 );
    180       set_texcoords( wide, v3, tex11 );
    181    }
    182 
    183    tri.det = header->det;  /* only the sign matters */
    184    tri.v[0] = v0;
    185    tri.v[1] = v2;
    186    tri.v[2] = v3;
    187    stage->next->tri( stage->next, &tri );
    188 
    189    tri.v[0] = v0;
    190    tri.v[1] = v3;
    191    tri.v[2] = v1;
    192    stage->next->tri( stage->next, &tri );
    193 }
    194 
    195 
    196 static void
    197 widepoint_first_point(struct draw_stage *stage,
    198                       struct prim_header *header)
    199 {
    200    struct widepoint_stage *wide = widepoint_stage(stage);
    201    struct draw_context *draw = stage->draw;
    202    struct pipe_context *pipe = draw->pipe;
    203    const struct pipe_rasterizer_state *rast = draw->rasterizer;
    204    void *r;
    205 
    206    wide->half_point_size = 0.5f * rast->point_size;
    207    wide->xbias = 0.0;
    208    wide->ybias = 0.0;
    209 
    210    if (rast->half_pixel_center) {
    211       wide->xbias = 0.125;
    212       wide->ybias = -0.125;
    213    }
    214 
    215    /* Disable triangle culling, stippling, unfilled mode etc. */
    216    r = draw_get_rasterizer_no_cull(draw, rast->scissor, rast->flatshade);
    217    draw->suspend_flushing = TRUE;
    218    pipe->bind_rasterizer_state(pipe, r);
    219    draw->suspend_flushing = FALSE;
    220 
    221    /* XXX we won't know the real size if it's computed by the vertex shader! */
    222    if ((rast->point_size > draw->pipeline.wide_point_threshold) ||
    223        (rast->point_quad_rasterization && draw->pipeline.point_sprite)) {
    224       stage->point = widepoint_point;
    225    }
    226    else {
    227       stage->point = draw_pipe_passthrough_point;
    228    }
    229 
    230    draw_remove_extra_vertex_attribs(draw);
    231 
    232    if (rast->point_quad_rasterization) {
    233       const struct draw_fragment_shader *fs = draw->fs.fragment_shader;
    234       uint i;
    235 
    236       assert(fs);
    237 
    238       wide->num_texcoord_gen = 0;
    239 
    240       /* Loop over fragment shader inputs looking for the PCOORD input or inputs
    241        * for which bit 'k' in sprite_coord_enable is set.
    242        */
    243       for (i = 0; i < fs->info.num_inputs; i++) {
    244          int slot;
    245          const unsigned sn = fs->info.input_semantic_name[i];
    246          const unsigned si = fs->info.input_semantic_index[i];
    247 
    248          if (sn == wide->sprite_coord_semantic) {
    249             /* Note that sprite_coord_enable is a bitfield of 32 bits. */
    250             if (si >= 32 || !(rast->sprite_coord_enable & (1 << si)))
    251                continue;
    252          } else if (sn != TGSI_SEMANTIC_PCOORD) {
    253             continue;
    254          }
    255 
    256          /* OK, this generic attribute needs to be replaced with a
    257           * sprite coord (see above).
    258           */
    259          slot = draw_alloc_extra_vertex_attrib(draw, sn, si);
    260 
    261          /* add this slot to the texcoord-gen list */
    262          wide->texcoord_gen_slot[wide->num_texcoord_gen++] = slot;
    263       }
    264    }
    265 
    266    wide->psize_slot = -1;
    267    if (rast->point_size_per_vertex) {
    268       /* find PSIZ vertex output */
    269       const struct draw_vertex_shader *vs = draw->vs.vertex_shader;
    270       uint i;
    271       for (i = 0; i < vs->info.num_outputs; i++) {
    272          if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_PSIZE) {
    273             wide->psize_slot = i;
    274             break;
    275          }
    276       }
    277    }
    278 
    279    stage->point( stage, header );
    280 }
    281 
    282 
    283 static void widepoint_flush( struct draw_stage *stage, unsigned flags )
    284 {
    285    struct draw_context *draw = stage->draw;
    286    struct pipe_context *pipe = draw->pipe;
    287 
    288    stage->point = widepoint_first_point;
    289    stage->next->flush( stage->next, flags );
    290 
    291    draw_remove_extra_vertex_attribs(draw);
    292 
    293    /* restore original rasterizer state */
    294    if (draw->rast_handle) {
    295       draw->suspend_flushing = TRUE;
    296       pipe->bind_rasterizer_state(pipe, draw->rast_handle);
    297       draw->suspend_flushing = FALSE;
    298    }
    299 }
    300 
    301 
    302 static void widepoint_reset_stipple_counter( struct draw_stage *stage )
    303 {
    304    stage->next->reset_stipple_counter( stage->next );
    305 }
    306 
    307 
    308 static void widepoint_destroy( struct draw_stage *stage )
    309 {
    310    draw_free_temp_verts( stage );
    311    FREE( stage );
    312 }
    313 
    314 
    315 struct draw_stage *draw_wide_point_stage( struct draw_context *draw )
    316 {
    317    struct widepoint_stage *wide = CALLOC_STRUCT(widepoint_stage);
    318    if (!wide)
    319       goto fail;
    320 
    321    wide->stage.draw = draw;
    322    wide->stage.name = "wide-point";
    323    wide->stage.next = NULL;
    324    wide->stage.point = widepoint_first_point;
    325    wide->stage.line = draw_pipe_passthrough_line;
    326    wide->stage.tri = draw_pipe_passthrough_tri;
    327    wide->stage.flush = widepoint_flush;
    328    wide->stage.reset_stipple_counter = widepoint_reset_stipple_counter;
    329    wide->stage.destroy = widepoint_destroy;
    330 
    331    if (!draw_alloc_temp_verts( &wide->stage, 4 ))
    332       goto fail;
    333 
    334    wide->sprite_coord_semantic =
    335       draw->pipe->screen->get_param(draw->pipe->screen, PIPE_CAP_TGSI_TEXCOORD)
    336       ?
    337       TGSI_SEMANTIC_TEXCOORD : TGSI_SEMANTIC_GENERIC;
    338 
    339    return &wide->stage;
    340 
    341  fail:
    342    if (wide)
    343       wide->stage.destroy( &wide->stage );
    344 
    345    return NULL;
    346 }
    347