1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2007 VMware, Inc.
4bf215546Sopenharmony_ci * All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the
8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
12bf215546Sopenharmony_ci * the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
16bf215546Sopenharmony_ci * of the Software.
17bf215546Sopenharmony_ci *
18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci **************************************************************************/
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci/**
29bf215546Sopenharmony_ci * GL_SELECT and GL_FEEDBACK render modes.
30bf215546Sopenharmony_ci * Basically, we use a private instance of the 'draw' module for doing
31bf215546Sopenharmony_ci * selection/feedback.  It would be nice to use the transform_feedback
32bf215546Sopenharmony_ci * hardware feature, but it's defined as happening pre-clip and we want
33bf215546Sopenharmony_ci * post-clipped primitives.  Also, there's concerns about the efficiency
34bf215546Sopenharmony_ci * of using the hardware for this anyway.
35bf215546Sopenharmony_ci *
36bf215546Sopenharmony_ci * Authors:
37bf215546Sopenharmony_ci *   Brian Paul
38bf215546Sopenharmony_ci */
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_ci#include "main/context.h"
42bf215546Sopenharmony_ci#include "main/feedback.h"
43bf215546Sopenharmony_ci#include "main/framebuffer.h"
44bf215546Sopenharmony_ci#include "main/varray.h"
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci#include "util/u_memory.h"
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_ci#include "vbo/vbo.h"
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci#include "st_context.h"
51bf215546Sopenharmony_ci#include "st_draw.h"
52bf215546Sopenharmony_ci#include "st_cb_feedback.h"
53bf215546Sopenharmony_ci#include "st_program.h"
54bf215546Sopenharmony_ci#include "st_util.h"
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci#include "pipe/p_context.h"
57bf215546Sopenharmony_ci#include "pipe/p_defines.h"
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci#include "draw/draw_context.h"
60bf215546Sopenharmony_ci#include "draw/draw_pipe.h"
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_ci/**
64bf215546Sopenharmony_ci * This is actually used for both feedback and selection.
65bf215546Sopenharmony_ci */
66bf215546Sopenharmony_cistruct feedback_stage
67bf215546Sopenharmony_ci{
68bf215546Sopenharmony_ci   struct draw_stage stage;   /**< Base class */
69bf215546Sopenharmony_ci   struct gl_context *ctx;            /**< Rendering context */
70bf215546Sopenharmony_ci   GLboolean reset_stipple_counter;
71bf215546Sopenharmony_ci};
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_ci/**********************************************************************
75bf215546Sopenharmony_ci * GL Feedback functions
76bf215546Sopenharmony_ci **********************************************************************/
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_cistatic inline struct feedback_stage *
79bf215546Sopenharmony_cifeedback_stage( struct draw_stage *stage )
80bf215546Sopenharmony_ci{
81bf215546Sopenharmony_ci   return (struct feedback_stage *)stage;
82bf215546Sopenharmony_ci}
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci
85bf215546Sopenharmony_cistatic void
86bf215546Sopenharmony_cifeedback_vertex(struct gl_context *ctx, const struct draw_context *draw,
87bf215546Sopenharmony_ci                const struct vertex_header *v)
88bf215546Sopenharmony_ci{
89bf215546Sopenharmony_ci   const struct st_context *st = st_context(ctx);
90bf215546Sopenharmony_ci   struct gl_vertex_program *stvp = (struct gl_vertex_program *)st->vp;
91bf215546Sopenharmony_ci   GLfloat win[4];
92bf215546Sopenharmony_ci   const GLfloat *color, *texcoord;
93bf215546Sopenharmony_ci   ubyte slot;
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci   win[0] = v->data[0][0];
96bf215546Sopenharmony_ci   if (_mesa_fb_orientation(ctx->DrawBuffer) == Y_0_TOP)
97bf215546Sopenharmony_ci      win[1] = ctx->DrawBuffer->Height - v->data[0][1];
98bf215546Sopenharmony_ci   else
99bf215546Sopenharmony_ci      win[1] = v->data[0][1];
100bf215546Sopenharmony_ci   win[2] = v->data[0][2];
101bf215546Sopenharmony_ci   win[3] = 1.0F / v->data[0][3];
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci   /* XXX
104bf215546Sopenharmony_ci    * When we compute vertex layout, save info about position of the
105bf215546Sopenharmony_ci    * color and texcoord attribs to use here.
106bf215546Sopenharmony_ci    */
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_ci   slot = stvp->result_to_output[VARYING_SLOT_COL0];
109bf215546Sopenharmony_ci   if (slot != 0xff)
110bf215546Sopenharmony_ci      color = v->data[slot];
111bf215546Sopenharmony_ci   else
112bf215546Sopenharmony_ci      color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci   slot = stvp->result_to_output[VARYING_SLOT_TEX0];
115bf215546Sopenharmony_ci   if (slot != 0xff)
116bf215546Sopenharmony_ci      texcoord = v->data[slot];
117bf215546Sopenharmony_ci   else
118bf215546Sopenharmony_ci      texcoord = ctx->Current.Attrib[VERT_ATTRIB_TEX0];
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_ci   _mesa_feedback_vertex(ctx, win, color, texcoord);
121bf215546Sopenharmony_ci}
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_cistatic void
125bf215546Sopenharmony_cifeedback_tri( struct draw_stage *stage, struct prim_header *prim )
126bf215546Sopenharmony_ci{
127bf215546Sopenharmony_ci   struct feedback_stage *fs = feedback_stage(stage);
128bf215546Sopenharmony_ci   struct draw_context *draw = stage->draw;
129bf215546Sopenharmony_ci   _mesa_feedback_token(fs->ctx, (GLfloat) GL_POLYGON_TOKEN);
130bf215546Sopenharmony_ci   _mesa_feedback_token(fs->ctx, (GLfloat) 3); /* three vertices */
131bf215546Sopenharmony_ci   feedback_vertex(fs->ctx, draw, prim->v[0]);
132bf215546Sopenharmony_ci   feedback_vertex(fs->ctx, draw, prim->v[1]);
133bf215546Sopenharmony_ci   feedback_vertex(fs->ctx, draw, prim->v[2]);
134bf215546Sopenharmony_ci}
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_cistatic void
138bf215546Sopenharmony_cifeedback_line( struct draw_stage *stage, struct prim_header *prim )
139bf215546Sopenharmony_ci{
140bf215546Sopenharmony_ci   struct feedback_stage *fs = feedback_stage(stage);
141bf215546Sopenharmony_ci   struct draw_context *draw = stage->draw;
142bf215546Sopenharmony_ci   if (fs->reset_stipple_counter) {
143bf215546Sopenharmony_ci      _mesa_feedback_token(fs->ctx, (GLfloat) GL_LINE_RESET_TOKEN);
144bf215546Sopenharmony_ci      fs->reset_stipple_counter = GL_FALSE;
145bf215546Sopenharmony_ci   }
146bf215546Sopenharmony_ci   else {
147bf215546Sopenharmony_ci      _mesa_feedback_token(fs->ctx, (GLfloat) GL_LINE_TOKEN);
148bf215546Sopenharmony_ci   }
149bf215546Sopenharmony_ci   feedback_vertex(fs->ctx, draw, prim->v[0]);
150bf215546Sopenharmony_ci   feedback_vertex(fs->ctx, draw, prim->v[1]);
151bf215546Sopenharmony_ci}
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_cistatic void
155bf215546Sopenharmony_cifeedback_point( struct draw_stage *stage, struct prim_header *prim )
156bf215546Sopenharmony_ci{
157bf215546Sopenharmony_ci   struct feedback_stage *fs = feedback_stage(stage);
158bf215546Sopenharmony_ci   struct draw_context *draw = stage->draw;
159bf215546Sopenharmony_ci   _mesa_feedback_token(fs->ctx, (GLfloat) GL_POINT_TOKEN);
160bf215546Sopenharmony_ci   feedback_vertex(fs->ctx, draw, prim->v[0]);
161bf215546Sopenharmony_ci}
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_ci
164bf215546Sopenharmony_cistatic void
165bf215546Sopenharmony_cifeedback_flush( struct draw_stage *stage, unsigned flags )
166bf215546Sopenharmony_ci{
167bf215546Sopenharmony_ci   /* no-op */
168bf215546Sopenharmony_ci}
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_cistatic void
172bf215546Sopenharmony_cifeedback_reset_stipple_counter( struct draw_stage *stage )
173bf215546Sopenharmony_ci{
174bf215546Sopenharmony_ci   struct feedback_stage *fs = feedback_stage(stage);
175bf215546Sopenharmony_ci   fs->reset_stipple_counter = GL_TRUE;
176bf215546Sopenharmony_ci}
177bf215546Sopenharmony_ci
178bf215546Sopenharmony_ci
179bf215546Sopenharmony_cistatic void
180bf215546Sopenharmony_cifeedback_destroy( struct draw_stage *stage )
181bf215546Sopenharmony_ci{
182bf215546Sopenharmony_ci   FREE(stage);
183bf215546Sopenharmony_ci}
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci/**
186bf215546Sopenharmony_ci * Create GL feedback drawing stage.
187bf215546Sopenharmony_ci */
188bf215546Sopenharmony_cistatic struct draw_stage *
189bf215546Sopenharmony_cidraw_glfeedback_stage(struct gl_context *ctx, struct draw_context *draw)
190bf215546Sopenharmony_ci{
191bf215546Sopenharmony_ci   struct feedback_stage *fs = CALLOC_STRUCT(feedback_stage);
192bf215546Sopenharmony_ci
193bf215546Sopenharmony_ci   fs->stage.draw = draw;
194bf215546Sopenharmony_ci   fs->stage.next = NULL;
195bf215546Sopenharmony_ci   fs->stage.point = feedback_point;
196bf215546Sopenharmony_ci   fs->stage.line = feedback_line;
197bf215546Sopenharmony_ci   fs->stage.tri = feedback_tri;
198bf215546Sopenharmony_ci   fs->stage.flush = feedback_flush;
199bf215546Sopenharmony_ci   fs->stage.reset_stipple_counter = feedback_reset_stipple_counter;
200bf215546Sopenharmony_ci   fs->stage.destroy = feedback_destroy;
201bf215546Sopenharmony_ci   fs->ctx = ctx;
202bf215546Sopenharmony_ci
203bf215546Sopenharmony_ci   return &fs->stage;
204bf215546Sopenharmony_ci}
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci/**********************************************************************
209bf215546Sopenharmony_ci * GL Selection functions
210bf215546Sopenharmony_ci **********************************************************************/
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_cistatic void
213bf215546Sopenharmony_ciselect_tri( struct draw_stage *stage, struct prim_header *prim )
214bf215546Sopenharmony_ci{
215bf215546Sopenharmony_ci   struct feedback_stage *fs = feedback_stage(stage);
216bf215546Sopenharmony_ci   _mesa_update_hitflag( fs->ctx, prim->v[0]->data[0][2] );
217bf215546Sopenharmony_ci   _mesa_update_hitflag( fs->ctx, prim->v[1]->data[0][2] );
218bf215546Sopenharmony_ci   _mesa_update_hitflag( fs->ctx, prim->v[2]->data[0][2] );
219bf215546Sopenharmony_ci}
220bf215546Sopenharmony_ci
221bf215546Sopenharmony_cistatic void
222bf215546Sopenharmony_ciselect_line( struct draw_stage *stage, struct prim_header *prim )
223bf215546Sopenharmony_ci{
224bf215546Sopenharmony_ci   struct feedback_stage *fs = feedback_stage(stage);
225bf215546Sopenharmony_ci   _mesa_update_hitflag( fs->ctx, prim->v[0]->data[0][2] );
226bf215546Sopenharmony_ci   _mesa_update_hitflag( fs->ctx, prim->v[1]->data[0][2] );
227bf215546Sopenharmony_ci}
228bf215546Sopenharmony_ci
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_cistatic void
231bf215546Sopenharmony_ciselect_point( struct draw_stage *stage, struct prim_header *prim )
232bf215546Sopenharmony_ci{
233bf215546Sopenharmony_ci   struct feedback_stage *fs = feedback_stage(stage);
234bf215546Sopenharmony_ci   _mesa_update_hitflag( fs->ctx, prim->v[0]->data[0][2] );
235bf215546Sopenharmony_ci}
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_cistatic void
239bf215546Sopenharmony_ciselect_flush( struct draw_stage *stage, unsigned flags )
240bf215546Sopenharmony_ci{
241bf215546Sopenharmony_ci   /* no-op */
242bf215546Sopenharmony_ci}
243bf215546Sopenharmony_ci
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_cistatic void
246bf215546Sopenharmony_ciselect_reset_stipple_counter( struct draw_stage *stage )
247bf215546Sopenharmony_ci{
248bf215546Sopenharmony_ci   /* no-op */
249bf215546Sopenharmony_ci}
250bf215546Sopenharmony_ci
251bf215546Sopenharmony_cistatic void
252bf215546Sopenharmony_ciselect_destroy( struct draw_stage *stage )
253bf215546Sopenharmony_ci{
254bf215546Sopenharmony_ci   FREE(stage);
255bf215546Sopenharmony_ci}
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci
258bf215546Sopenharmony_ci/**
259bf215546Sopenharmony_ci * Create GL selection mode drawing stage.
260bf215546Sopenharmony_ci */
261bf215546Sopenharmony_cistatic struct draw_stage *
262bf215546Sopenharmony_cidraw_glselect_stage(struct gl_context *ctx, struct draw_context *draw)
263bf215546Sopenharmony_ci{
264bf215546Sopenharmony_ci   struct feedback_stage *fs = CALLOC_STRUCT(feedback_stage);
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_ci   fs->stage.draw = draw;
267bf215546Sopenharmony_ci   fs->stage.next = NULL;
268bf215546Sopenharmony_ci   fs->stage.point = select_point;
269bf215546Sopenharmony_ci   fs->stage.line = select_line;
270bf215546Sopenharmony_ci   fs->stage.tri = select_tri;
271bf215546Sopenharmony_ci   fs->stage.flush = select_flush;
272bf215546Sopenharmony_ci   fs->stage.reset_stipple_counter = select_reset_stipple_counter;
273bf215546Sopenharmony_ci   fs->stage.destroy = select_destroy;
274bf215546Sopenharmony_ci   fs->ctx = ctx;
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci   return &fs->stage;
277bf215546Sopenharmony_ci}
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_ci
280bf215546Sopenharmony_civoid
281bf215546Sopenharmony_cist_RenderMode(struct gl_context *ctx, GLenum newMode )
282bf215546Sopenharmony_ci{
283bf215546Sopenharmony_ci   struct st_context *st = st_context(ctx);
284bf215546Sopenharmony_ci   struct draw_context *draw = st_get_draw_context(st);
285bf215546Sopenharmony_ci
286bf215546Sopenharmony_ci   if (!st->draw)
287bf215546Sopenharmony_ci      return;
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci   if (newMode == GL_RENDER) {
290bf215546Sopenharmony_ci      /* restore normal VBO draw function */
291bf215546Sopenharmony_ci      st_init_draw_functions(st->screen, &ctx->Driver);
292bf215546Sopenharmony_ci   }
293bf215546Sopenharmony_ci   else if (newMode == GL_SELECT) {
294bf215546Sopenharmony_ci      if (ctx->Const.HardwareAcceleratedSelect)
295bf215546Sopenharmony_ci         st_init_hw_select_draw_functions(st->screen, &ctx->Driver);
296bf215546Sopenharmony_ci      else {
297bf215546Sopenharmony_ci         if (!st->selection_stage)
298bf215546Sopenharmony_ci            st->selection_stage = draw_glselect_stage(ctx, draw);
299bf215546Sopenharmony_ci         draw_set_rasterize_stage(draw, st->selection_stage);
300bf215546Sopenharmony_ci         /* Plug in new vbo draw function */
301bf215546Sopenharmony_ci         ctx->Driver.DrawGallium = _mesa_draw_gallium_fallback;
302bf215546Sopenharmony_ci         ctx->Driver.DrawGalliumMultiMode = _mesa_draw_gallium_multimode_fallback;
303bf215546Sopenharmony_ci      }
304bf215546Sopenharmony_ci   }
305bf215546Sopenharmony_ci   else {
306bf215546Sopenharmony_ci      struct gl_program *vp = st->ctx->VertexProgram._Current;
307bf215546Sopenharmony_ci
308bf215546Sopenharmony_ci      if (!st->feedback_stage)
309bf215546Sopenharmony_ci         st->feedback_stage = draw_glfeedback_stage(ctx, draw);
310bf215546Sopenharmony_ci      draw_set_rasterize_stage(draw, st->feedback_stage);
311bf215546Sopenharmony_ci      /* Plug in new vbo draw function */
312bf215546Sopenharmony_ci      ctx->Driver.DrawGallium = _mesa_draw_gallium_fallback;
313bf215546Sopenharmony_ci      ctx->Driver.DrawGalliumMultiMode = _mesa_draw_gallium_multimode_fallback;
314bf215546Sopenharmony_ci      /* need to generate/use a vertex program that emits pos/color/tex */
315bf215546Sopenharmony_ci      if (vp)
316bf215546Sopenharmony_ci         st->dirty |= ST_NEW_VERTEX_PROGRAM(st, vp);
317bf215546Sopenharmony_ci   }
318bf215546Sopenharmony_ci
319bf215546Sopenharmony_ci   /* Restore geometry shader states when leaving GL_SELECT mode. */
320bf215546Sopenharmony_ci   if (ctx->RenderMode == GL_SELECT && ctx->Const.HardwareAcceleratedSelect)
321bf215546Sopenharmony_ci      st->dirty |= ST_NEW_GS_SSBOS | ST_NEW_GS_CONSTANTS | ST_NEW_GS_STATE;
322bf215546Sopenharmony_ci}
323