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#include "main/varray.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#include "st_program.h" 51#include "st_util.h" 52 53#include "pipe/p_context.h" 54#include "pipe/p_defines.h" 55 56#include "draw/draw_context.h" 57#include "draw/draw_pipe.h" 58 59 60/** 61 * This is actually used for both feedback and selection. 62 */ 63struct 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 75static inline struct feedback_stage * 76feedback_stage( struct draw_stage *stage ) 77{ 78 return (struct feedback_stage *)stage; 79} 80 81 82static void 83feedback_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 win[0] = v->data[0][0]; 92 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) 93 win[1] = ctx->DrawBuffer->Height - v->data[0][1]; 94 else 95 win[1] = v->data[0][1]; 96 win[2] = v->data[0][2]; 97 win[3] = 1.0F / v->data[0][3]; 98 99 /* XXX 100 * When we compute vertex layout, save info about position of the 101 * color and texcoord attribs to use here. 102 */ 103 104 slot = st->vp->result_to_output[VARYING_SLOT_COL0]; 105 if (slot != ~0U) 106 color = v->data[slot]; 107 else 108 color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; 109 110 slot = st->vp->result_to_output[VARYING_SLOT_TEX0]; 111 if (slot != ~0U) 112 texcoord = v->data[slot]; 113 else 114 texcoord = ctx->Current.Attrib[VERT_ATTRIB_TEX0]; 115 116 _mesa_feedback_vertex(ctx, win, color, texcoord); 117} 118 119 120static void 121feedback_tri( struct draw_stage *stage, struct prim_header *prim ) 122{ 123 struct feedback_stage *fs = feedback_stage(stage); 124 struct draw_context *draw = stage->draw; 125 _mesa_feedback_token(fs->ctx, (GLfloat) GL_POLYGON_TOKEN); 126 _mesa_feedback_token(fs->ctx, (GLfloat) 3); /* three vertices */ 127 feedback_vertex(fs->ctx, draw, prim->v[0]); 128 feedback_vertex(fs->ctx, draw, prim->v[1]); 129 feedback_vertex(fs->ctx, draw, prim->v[2]); 130} 131 132 133static void 134feedback_line( struct draw_stage *stage, struct prim_header *prim ) 135{ 136 struct feedback_stage *fs = feedback_stage(stage); 137 struct draw_context *draw = stage->draw; 138 if (fs->reset_stipple_counter) { 139 _mesa_feedback_token(fs->ctx, (GLfloat) GL_LINE_RESET_TOKEN); 140 fs->reset_stipple_counter = GL_FALSE; 141 } 142 else { 143 _mesa_feedback_token(fs->ctx, (GLfloat) GL_LINE_TOKEN); 144 } 145 feedback_vertex(fs->ctx, draw, prim->v[0]); 146 feedback_vertex(fs->ctx, draw, prim->v[1]); 147} 148 149 150static void 151feedback_point( struct draw_stage *stage, struct prim_header *prim ) 152{ 153 struct feedback_stage *fs = feedback_stage(stage); 154 struct draw_context *draw = stage->draw; 155 _mesa_feedback_token(fs->ctx, (GLfloat) GL_POINT_TOKEN); 156 feedback_vertex(fs->ctx, draw, prim->v[0]); 157} 158 159 160static void 161feedback_flush( struct draw_stage *stage, unsigned flags ) 162{ 163 /* no-op */ 164} 165 166 167static void 168feedback_reset_stipple_counter( struct draw_stage *stage ) 169{ 170 struct feedback_stage *fs = feedback_stage(stage); 171 fs->reset_stipple_counter = GL_TRUE; 172} 173 174 175static void 176feedback_destroy( struct draw_stage *stage ) 177{ 178 /* no-op */ 179} 180 181/** 182 * Create GL feedback drawing stage. 183 */ 184static struct draw_stage * 185draw_glfeedback_stage(struct gl_context *ctx, struct draw_context *draw) 186{ 187 struct feedback_stage *fs = ST_CALLOC_STRUCT(feedback_stage); 188 189 fs->stage.draw = draw; 190 fs->stage.next = NULL; 191 fs->stage.point = feedback_point; 192 fs->stage.line = feedback_line; 193 fs->stage.tri = feedback_tri; 194 fs->stage.flush = feedback_flush; 195 fs->stage.reset_stipple_counter = feedback_reset_stipple_counter; 196 fs->stage.destroy = feedback_destroy; 197 fs->ctx = ctx; 198 199 return &fs->stage; 200} 201 202 203 204/********************************************************************** 205 * GL Selection functions 206 **********************************************************************/ 207 208static void 209select_tri( struct draw_stage *stage, struct prim_header *prim ) 210{ 211 struct feedback_stage *fs = feedback_stage(stage); 212 _mesa_update_hitflag( fs->ctx, prim->v[0]->data[0][2] ); 213 _mesa_update_hitflag( fs->ctx, prim->v[1]->data[0][2] ); 214 _mesa_update_hitflag( fs->ctx, prim->v[2]->data[0][2] ); 215} 216 217static void 218select_line( struct draw_stage *stage, struct prim_header *prim ) 219{ 220 struct feedback_stage *fs = feedback_stage(stage); 221 _mesa_update_hitflag( fs->ctx, prim->v[0]->data[0][2] ); 222 _mesa_update_hitflag( fs->ctx, prim->v[1]->data[0][2] ); 223} 224 225 226static void 227select_point( struct draw_stage *stage, struct prim_header *prim ) 228{ 229 struct feedback_stage *fs = feedback_stage(stage); 230 _mesa_update_hitflag( fs->ctx, prim->v[0]->data[0][2] ); 231} 232 233 234static void 235select_flush( struct draw_stage *stage, unsigned flags ) 236{ 237 /* no-op */ 238} 239 240 241static void 242select_reset_stipple_counter( struct draw_stage *stage ) 243{ 244 /* no-op */ 245} 246 247static void 248select_destroy( struct draw_stage *stage ) 249{ 250 /* no-op */ 251} 252 253 254/** 255 * Create GL selection mode drawing stage. 256 */ 257static struct draw_stage * 258draw_glselect_stage(struct gl_context *ctx, struct draw_context *draw) 259{ 260 struct feedback_stage *fs = ST_CALLOC_STRUCT(feedback_stage); 261 262 fs->stage.draw = draw; 263 fs->stage.next = NULL; 264 fs->stage.point = select_point; 265 fs->stage.line = select_line; 266 fs->stage.tri = select_tri; 267 fs->stage.flush = select_flush; 268 fs->stage.reset_stipple_counter = select_reset_stipple_counter; 269 fs->stage.destroy = select_destroy; 270 fs->ctx = ctx; 271 272 return &fs->stage; 273} 274 275 276static void 277st_RenderMode(struct gl_context *ctx, GLenum newMode ) 278{ 279 struct st_context *st = st_context(ctx); 280 struct draw_context *draw = st_get_draw_context(st); 281 282 if (!st->draw) 283 return; 284 285 if (newMode == GL_RENDER) { 286 /* restore normal VBO draw function */ 287 st_init_draw_functions(&ctx->Driver); 288 } 289 else if (newMode == GL_SELECT) { 290 if (!st->selection_stage) 291 st->selection_stage = draw_glselect_stage(ctx, draw); 292 draw_set_rasterize_stage(draw, st->selection_stage); 293 /* Plug in new vbo draw function */ 294 ctx->Driver.Draw = st_feedback_draw_vbo; 295 } 296 else { 297 struct gl_program *vp = st->ctx->VertexProgram._Current; 298 299 if (!st->feedback_stage) 300 st->feedback_stage = draw_glfeedback_stage(ctx, draw); 301 draw_set_rasterize_stage(draw, st->feedback_stage); 302 /* Plug in new vbo draw function */ 303 ctx->Driver.Draw = st_feedback_draw_vbo; 304 /* need to generate/use a vertex program that emits pos/color/tex */ 305 if (vp) 306 st->dirty |= ST_NEW_VERTEX_PROGRAM(st, st_vertex_program(vp)); 307 } 308} 309 310 311 312void st_init_feedback_functions(struct dd_function_table *functions) 313{ 314 functions->RenderMode = st_RenderMode; 315} 316