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 /** 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 #include "main/mfeatures.h" 44 45 #include "vbo/vbo.h" 46 47 #include "st_context.h" 48 #include "st_draw.h" 49 #include "st_cb_feedback.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 #if FEATURE_feedback 59 60 /** 61 * This is actually used for both feedback and selection. 62 */ 63 struct feedback_stage 64 { 65 struct draw_stage stage; /**< Base class */ 66 struct gl_context *ctx; /**< Rendering context */ 67 GLboolean reset_stipple_counter; 68 }; 69 70 71 /********************************************************************** 72 * GL Feedback functions 73 **********************************************************************/ 74 75 static INLINE struct feedback_stage * 76 feedback_stage( struct draw_stage *stage ) 77 { 78 return (struct feedback_stage *)stage; 79 } 80 81 82 static void 83 feedback_vertex(struct gl_context *ctx, const struct draw_context *draw, 84 const struct vertex_header *v) 85 { 86 const struct st_context *st = st_context(ctx); 87 GLfloat win[4]; 88 const GLfloat *color, *texcoord; 89 GLuint slot; 90 91 /* Recall that Y=0=Top of window for Gallium wincoords */ 92 win[0] = v->data[0][0]; 93 win[1] = ctx->DrawBuffer->Height - 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[VERT_RESULT_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[VERT_RESULT_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->draw; 279 280 if (newMode == GL_RENDER) { 281 /* restore normal VBO draw function */ 282 vbo_set_draw_func(ctx, st_draw_vbo); 283 } 284 else if (newMode == GL_SELECT) { 285 if (!st->selection_stage) 286 st->selection_stage = draw_glselect_stage(ctx, draw); 287 draw_set_rasterize_stage(draw, st->selection_stage); 288 /* Plug in new vbo draw function */ 289 vbo_set_draw_func(ctx, st_feedback_draw_vbo); 290 } 291 else { 292 if (!st->feedback_stage) 293 st->feedback_stage = draw_glfeedback_stage(ctx, draw); 294 draw_set_rasterize_stage(draw, st->feedback_stage); 295 /* Plug in new vbo draw function */ 296 vbo_set_draw_func(ctx, st_feedback_draw_vbo); 297 /* need to generate/use a vertex program that emits pos/color/tex */ 298 st->dirty.st |= ST_NEW_VERTEX_PROGRAM; 299 } 300 } 301 302 303 304 void st_init_feedback_functions(struct dd_function_table *functions) 305 { 306 functions->RenderMode = st_RenderMode; 307 } 308 309 #endif /* FEATURE_feedback */ 310