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