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