Home | History | Annotate | Download | only in state_tracker
      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 /**
     29  * GL_SELECT and GL_FEEDBACK render modes.
     30  * Basically, we use a private instance of the 'draw' module for doing
     31  * selection/feedback.  It would be nice to use the transform_feedback
     32  * hardware feature, but it's defined as happening pre-clip and we want
     33  * post-clipped primitives.  Also, there's concerns about the efficiency
     34  * of using the hardware for this anyway.
     35  *
     36  * Authors:
     37  *   Brian Paul
     38  */
     39 
     40 #include "main/imports.h"
     41 #include "main/context.h"
     42 #include "main/feedback.h"
     43 
     44 #include "vbo/vbo.h"
     45 
     46 #include "st_context.h"
     47 #include "st_draw.h"
     48 #include "st_cb_feedback.h"
     49 #include "st_program.h"
     50 
     51 #include "pipe/p_context.h"
     52 #include "pipe/p_defines.h"
     53 
     54 #include "draw/draw_context.h"
     55 #include "draw/draw_pipe.h"
     56 
     57 
     58 /**
     59  * This is actually used for both feedback and selection.
     60  */
     61 struct feedback_stage
     62 {
     63    struct draw_stage stage;   /**< Base class */
     64    struct gl_context *ctx;            /**< Rendering context */
     65    GLboolean reset_stipple_counter;
     66 };
     67 
     68 
     69 /**********************************************************************
     70  * GL Feedback functions
     71  **********************************************************************/
     72 
     73 static inline struct feedback_stage *
     74 feedback_stage( struct draw_stage *stage )
     75 {
     76    return (struct feedback_stage *)stage;
     77 }
     78 
     79 
     80 static void
     81 feedback_vertex(struct gl_context *ctx, const struct draw_context *draw,
     82                 const struct vertex_header *v)
     83 {
     84    const struct st_context *st = st_context(ctx);
     85    GLfloat win[4];
     86    const GLfloat *color, *texcoord;
     87    GLuint slot;
     88 
     89    win[0] = v->data[0][0];
     90    if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP)
     91       win[1] = ctx->DrawBuffer->Height - v->data[0][1];
     92    else
     93       win[1] = v->data[0][1];
     94    win[2] = v->data[0][2];
     95    win[3] = 1.0F / v->data[0][3];
     96 
     97    /* XXX
     98     * When we compute vertex layout, save info about position of the
     99     * color and texcoord attribs to use here.
    100     */
    101 
    102    slot = st->vertex_result_to_slot[VARYING_SLOT_COL0];
    103    if (slot != ~0U)
    104       color = v->data[slot];
    105    else
    106       color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
    107 
    108    slot = st->vertex_result_to_slot[VARYING_SLOT_TEX0];
    109    if (slot != ~0U)
    110       texcoord = v->data[slot];
    111    else
    112       texcoord = ctx->Current.Attrib[VERT_ATTRIB_TEX0];
    113 
    114    _mesa_feedback_vertex(ctx, win, color, texcoord);
    115 }
    116 
    117 
    118 static void
    119 feedback_tri( struct draw_stage *stage, struct prim_header *prim )
    120 {
    121    struct feedback_stage *fs = feedback_stage(stage);
    122    struct draw_context *draw = stage->draw;
    123    _mesa_feedback_token(fs->ctx, (GLfloat) GL_POLYGON_TOKEN);
    124    _mesa_feedback_token(fs->ctx, (GLfloat) 3); /* three vertices */
    125    feedback_vertex(fs->ctx, draw, prim->v[0]);
    126    feedback_vertex(fs->ctx, draw, prim->v[1]);
    127    feedback_vertex(fs->ctx, draw, prim->v[2]);
    128 }
    129 
    130 
    131 static void
    132 feedback_line( struct draw_stage *stage, struct prim_header *prim )
    133 {
    134    struct feedback_stage *fs = feedback_stage(stage);
    135    struct draw_context *draw = stage->draw;
    136    if (fs->reset_stipple_counter) {
    137       _mesa_feedback_token(fs->ctx, (GLfloat) GL_LINE_RESET_TOKEN);
    138       fs->reset_stipple_counter = GL_FALSE;
    139    }
    140    else {
    141       _mesa_feedback_token(fs->ctx, (GLfloat) GL_LINE_TOKEN);
    142    }
    143    feedback_vertex(fs->ctx, draw, prim->v[0]);
    144    feedback_vertex(fs->ctx, draw, prim->v[1]);
    145 }
    146 
    147 
    148 static void
    149 feedback_point( struct draw_stage *stage, struct prim_header *prim )
    150 {
    151    struct feedback_stage *fs = feedback_stage(stage);
    152    struct draw_context *draw = stage->draw;
    153    _mesa_feedback_token(fs->ctx, (GLfloat) GL_POINT_TOKEN);
    154    feedback_vertex(fs->ctx, draw, prim->v[0]);
    155 }
    156 
    157 
    158 static void
    159 feedback_flush( struct draw_stage *stage, unsigned flags )
    160 {
    161    /* no-op */
    162 }
    163 
    164 
    165 static void
    166 feedback_reset_stipple_counter( struct draw_stage *stage )
    167 {
    168    struct feedback_stage *fs = feedback_stage(stage);
    169    fs->reset_stipple_counter = GL_TRUE;
    170 }
    171 
    172 
    173 static void
    174 feedback_destroy( struct draw_stage *stage )
    175 {
    176    /* no-op */
    177 }
    178 
    179 /**
    180  * Create GL feedback drawing stage.
    181  */
    182 static struct draw_stage *
    183 draw_glfeedback_stage(struct gl_context *ctx, struct draw_context *draw)
    184 {
    185    struct feedback_stage *fs = ST_CALLOC_STRUCT(feedback_stage);
    186 
    187    fs->stage.draw = draw;
    188    fs->stage.next = NULL;
    189    fs->stage.point = feedback_point;
    190    fs->stage.line = feedback_line;
    191    fs->stage.tri = feedback_tri;
    192    fs->stage.flush = feedback_flush;
    193    fs->stage.reset_stipple_counter = feedback_reset_stipple_counter;
    194    fs->stage.destroy = feedback_destroy;
    195    fs->ctx = ctx;
    196 
    197    return &fs->stage;
    198 }
    199 
    200 
    201 
    202 /**********************************************************************
    203  * GL Selection functions
    204  **********************************************************************/
    205 
    206 static void
    207 select_tri( struct draw_stage *stage, struct prim_header *prim )
    208 {
    209    struct feedback_stage *fs = feedback_stage(stage);
    210    _mesa_update_hitflag( fs->ctx, prim->v[0]->data[0][2] );
    211    _mesa_update_hitflag( fs->ctx, prim->v[1]->data[0][2] );
    212    _mesa_update_hitflag( fs->ctx, prim->v[2]->data[0][2] );
    213 }
    214 
    215 static void
    216 select_line( struct draw_stage *stage, struct prim_header *prim )
    217 {
    218    struct feedback_stage *fs = feedback_stage(stage);
    219    _mesa_update_hitflag( fs->ctx, prim->v[0]->data[0][2] );
    220    _mesa_update_hitflag( fs->ctx, prim->v[1]->data[0][2] );
    221 }
    222 
    223 
    224 static void
    225 select_point( struct draw_stage *stage, struct prim_header *prim )
    226 {
    227    struct feedback_stage *fs = feedback_stage(stage);
    228    _mesa_update_hitflag( fs->ctx, prim->v[0]->data[0][2] );
    229 }
    230 
    231 
    232 static void
    233 select_flush( struct draw_stage *stage, unsigned flags )
    234 {
    235    /* no-op */
    236 }
    237 
    238 
    239 static void
    240 select_reset_stipple_counter( struct draw_stage *stage )
    241 {
    242    /* no-op */
    243 }
    244 
    245 static void
    246 select_destroy( struct draw_stage *stage )
    247 {
    248    /* no-op */
    249 }
    250 
    251 
    252 /**
    253  * Create GL selection mode drawing stage.
    254  */
    255 static struct draw_stage *
    256 draw_glselect_stage(struct gl_context *ctx, struct draw_context *draw)
    257 {
    258    struct feedback_stage *fs = ST_CALLOC_STRUCT(feedback_stage);
    259 
    260    fs->stage.draw = draw;
    261    fs->stage.next = NULL;
    262    fs->stage.point = select_point;
    263    fs->stage.line = select_line;
    264    fs->stage.tri = select_tri;
    265    fs->stage.flush = select_flush;
    266    fs->stage.reset_stipple_counter = select_reset_stipple_counter;
    267    fs->stage.destroy = select_destroy;
    268    fs->ctx = ctx;
    269 
    270    return &fs->stage;
    271 }
    272 
    273 
    274 static void
    275 st_RenderMode(struct gl_context *ctx, GLenum newMode )
    276 {
    277    struct st_context *st = st_context(ctx);
    278    struct draw_context *draw = st_get_draw_context(st);
    279 
    280    if (!st->draw)
    281       return;
    282 
    283    if (newMode == GL_RENDER) {
    284       /* restore normal VBO draw function */
    285       vbo_set_draw_func(ctx, st_draw_vbo);
    286    }
    287    else if (newMode == GL_SELECT) {
    288       if (!st->selection_stage)
    289          st->selection_stage = draw_glselect_stage(ctx, draw);
    290       draw_set_rasterize_stage(draw, st->selection_stage);
    291       /* Plug in new vbo draw function */
    292       vbo_set_draw_func(ctx, st_feedback_draw_vbo);
    293    }
    294    else {
    295       struct gl_program *vp = st->ctx->VertexProgram._Current;
    296 
    297       if (!st->feedback_stage)
    298          st->feedback_stage = draw_glfeedback_stage(ctx, draw);
    299       draw_set_rasterize_stage(draw, st->feedback_stage);
    300       /* Plug in new vbo draw function */
    301       vbo_set_draw_func(ctx, st_feedback_draw_vbo);
    302       /* need to generate/use a vertex program that emits pos/color/tex */
    303       if (vp)
    304          st->dirty |= ST_NEW_VERTEX_PROGRAM(st, st_vertex_program(vp));
    305    }
    306 }
    307 
    308 
    309 
    310 void st_init_feedback_functions(struct dd_function_table *functions)
    311 {
    312    functions->RenderMode = st_RenderMode;
    313 }
    314