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/* Authors:  Keith Whitwell <keithw@vmware.com>
29 */
30
31#include "util/u_memory.h"
32#include "util/u_math.h"
33#include "util/u_prim.h"
34#include "pipe/p_defines.h"
35#include "draw_private.h"
36#include "draw_pipe.h"
37#include "draw_context.h"
38#include "draw_vbuf.h"
39
40
41/**
42 * Default version of a function to check if we need any special
43 * pipeline stages, or whether prims/verts can go through untouched.
44 * Don't test for bypass clipping or vs modes, this function is just
45 * about the primitive pipeline stages.
46 *
47 * This can be overridden by the driver.
48 */
49boolean
50draw_need_pipeline(const struct draw_context *draw,
51                   const struct pipe_rasterizer_state *rasterizer,
52                   enum pipe_prim_type prim)
53{
54   unsigned reduced_prim = u_reduced_prim(prim);
55
56   /* If the driver has overridden this, use that version:
57    */
58   if (draw->render && draw->render->need_pipeline) {
59      return draw->render->need_pipeline(draw->render, rasterizer, prim);
60   }
61
62   /* Don't have to worry about triangles turning into lines/points
63    * and triggering the pipeline, because we have to trigger the
64    * pipeline *anyway* if unfilled mode is active.
65    */
66   if (reduced_prim == PIPE_PRIM_LINES) {
67      /* line stipple */
68      if (rasterizer->line_stipple_enable && draw->pipeline.line_stipple)
69         return TRUE;
70
71      /* wide lines */
72      if (roundf(rasterizer->line_width) > draw->pipeline.wide_line_threshold)
73         return TRUE;
74
75      /* AA lines */
76      if ((!rasterizer->multisample && rasterizer->line_smooth) && draw->pipeline.aaline)
77         return TRUE;
78
79      if (draw_current_shader_num_written_culldistances(draw))
80         return TRUE;
81   } else if (reduced_prim == PIPE_PRIM_POINTS) {
82      /* large points */
83      if (rasterizer->point_size > draw->pipeline.wide_point_threshold)
84         return TRUE;
85
86      /* sprite points */
87      if (rasterizer->point_quad_rasterization
88          && draw->pipeline.wide_point_sprites)
89         return TRUE;
90
91      /* AA points */
92      if ((!rasterizer->multisample && rasterizer->point_smooth) && draw->pipeline.aapoint)
93         return TRUE;
94
95      /* point sprites */
96      if (rasterizer->sprite_coord_enable && draw->pipeline.point_sprite)
97         return TRUE;
98
99      if (draw_current_shader_num_written_culldistances(draw))
100         return TRUE;
101   } else if (reduced_prim == PIPE_PRIM_TRIANGLES) {
102      /* polygon stipple */
103      if (rasterizer->poly_stipple_enable && draw->pipeline.pstipple)
104         return TRUE;
105
106      /* unfilled polygons */
107      if (rasterizer->fill_front != PIPE_POLYGON_MODE_FILL ||
108          rasterizer->fill_back != PIPE_POLYGON_MODE_FILL)
109         return TRUE;
110
111      /* polygon offset */
112      if (rasterizer->offset_point ||
113          rasterizer->offset_line ||
114          rasterizer->offset_tri)
115         return TRUE;
116
117      /* two-side lighting */
118      if (rasterizer->light_twoside)
119         return TRUE;
120
121      if (draw_current_shader_num_written_culldistances(draw))
122         return TRUE;
123   }
124
125   /* polygon cull - this is difficult - hardware can cull just fine
126    * most of the time (though sometimes CULL_NEITHER is unsupported.
127    *
128    * Generally this isn't a reason to require the pipeline, though.
129    *
130   if (rasterizer->cull_mode)
131      return TRUE;
132   */
133
134   return FALSE;
135}
136
137
138
139/**
140 * Rebuild the rendering pipeline.
141 */
142static struct draw_stage *
143validate_pipeline(struct draw_stage *stage)
144{
145   struct draw_context *draw = stage->draw;
146   struct draw_stage *next = draw->pipeline.rasterize;
147   boolean need_det = FALSE;
148   boolean precalc_flat = FALSE;
149   boolean wide_lines, wide_points;
150   const struct pipe_rasterizer_state *rast = draw->rasterizer;
151
152   /* Set the validate's next stage to the rasterize stage, so that it
153    * can be found later if needed for flushing.
154    */
155   stage->next = next;
156
157   /* drawing wide, non-AA lines? */
158   wide_lines = rast->line_width != 1.0f &&
159                roundf(rast->line_width) > draw->pipeline.wide_line_threshold &&
160                (!rast->line_smooth || rast->multisample);
161
162   /* drawing large/sprite points (but not AA points)? */
163   if (rast->sprite_coord_enable && draw->pipeline.point_sprite)
164      wide_points = TRUE;
165   else if ((!rast->multisample && rast->point_smooth) && draw->pipeline.aapoint)
166      wide_points = FALSE;
167   else if (rast->point_size > draw->pipeline.wide_point_threshold)
168      wide_points = TRUE;
169   else if (rast->point_quad_rasterization && draw->pipeline.wide_point_sprites)
170      wide_points = TRUE;
171   else
172      wide_points = FALSE;
173
174   /*
175    * NOTE: we build up the pipeline in end-to-start order.
176    *
177    * TODO: make the current primitive part of the state and build
178    * shorter pipelines for lines & points.
179    */
180
181   if ((!rast->multisample && rast->line_smooth) && draw->pipeline.aaline) {
182      draw->pipeline.aaline->next = next;
183      next = draw->pipeline.aaline;
184      precalc_flat = TRUE;
185   }
186
187   if ((!rast->multisample && rast->point_smooth) && draw->pipeline.aapoint) {
188      draw->pipeline.aapoint->next = next;
189      next = draw->pipeline.aapoint;
190   }
191
192   if (wide_lines) {
193      draw->pipeline.wide_line->next = next;
194      next = draw->pipeline.wide_line;
195      precalc_flat = TRUE;
196   }
197
198   if (wide_points) {
199      draw->pipeline.wide_point->next = next;
200      next = draw->pipeline.wide_point;
201   }
202
203   if (rast->line_stipple_enable && draw->pipeline.line_stipple) {
204      draw->pipeline.stipple->next = next;
205      next = draw->pipeline.stipple;
206      precalc_flat = TRUE;		/* only needed for lines really */
207   }
208
209   if (rast->poly_stipple_enable
210       && draw->pipeline.pstipple) {
211      draw->pipeline.pstipple->next = next;
212      next = draw->pipeline.pstipple;
213   }
214
215   if (rast->fill_front != PIPE_POLYGON_MODE_FILL ||
216       rast->fill_back != PIPE_POLYGON_MODE_FILL) {
217      draw->pipeline.unfilled->next = next;
218      next = draw->pipeline.unfilled;
219      precalc_flat = TRUE;		/* only needed for triangles really */
220      need_det = TRUE;
221   }
222
223   if (precalc_flat) {
224      /*
225       * could only run the stage if either rast->flatshade is true
226       * or there's constant interpolated values.
227       */
228      draw->pipeline.flatshade->next = next;
229      next = draw->pipeline.flatshade;
230   }
231
232   if (rast->offset_point ||
233       rast->offset_line ||
234       rast->offset_tri) {
235      draw->pipeline.offset->next = next;
236      next = draw->pipeline.offset;
237      need_det = TRUE;
238   }
239
240   if (rast->light_twoside) {
241      draw->pipeline.twoside->next = next;
242      next = draw->pipeline.twoside;
243      need_det = TRUE;
244   }
245
246   /* Always run the cull stage as we calculate determinant there
247    * also.
248    *
249    * This can actually be a win as culling out the triangles can lead
250    * to less work emitting vertices, smaller vertex buffers, etc.
251    * It's difficult to say whether this will be true in general.
252    */
253   if (need_det || rast->cull_face != PIPE_FACE_NONE) {
254      draw->pipeline.cull->next = next;
255      next = draw->pipeline.cull;
256   }
257
258   /* Clip stage
259    */
260   if (draw->clip_xy || draw->clip_z || draw->clip_user) {
261      draw->pipeline.clip->next = next;
262      next = draw->pipeline.clip;
263   }
264
265   if (draw_current_shader_num_written_culldistances(draw)) {
266      draw->pipeline.user_cull->next = next;
267      next = draw->pipeline.user_cull;
268   }
269
270   draw->pipeline.first = next;
271
272   if (0) {
273      debug_printf("draw pipeline:\n");
274      for (next = draw->pipeline.first; next ; next = next->next)
275         debug_printf("   %s\n", next->name);
276      debug_printf("\n");
277   }
278
279   return draw->pipeline.first;
280}
281
282
283static void
284validate_tri(struct draw_stage *stage,
285             struct prim_header *header)
286{
287   struct draw_stage *pipeline = validate_pipeline(stage);
288   pipeline->tri(pipeline, header);
289}
290
291
292static void
293validate_line(struct draw_stage *stage,
294              struct prim_header *header)
295{
296   struct draw_stage *pipeline = validate_pipeline(stage);
297   pipeline->line(pipeline, header);
298}
299
300
301static void
302validate_point(struct draw_stage *stage,
303               struct prim_header *header)
304{
305   struct draw_stage *pipeline = validate_pipeline(stage);
306   pipeline->point(pipeline, header);
307}
308
309
310static void
311validate_reset_stipple_counter(struct draw_stage *stage)
312{
313   struct draw_stage *pipeline = validate_pipeline(stage);
314   pipeline->reset_stipple_counter(pipeline);
315}
316
317
318static void
319validate_flush(struct draw_stage *stage,
320               unsigned flags)
321{
322   /* May need to pass a backend flush on to the rasterize stage.
323    */
324   if (stage->next)
325      stage->next->flush(stage->next, flags);
326}
327
328
329static void
330validate_destroy(struct draw_stage *stage)
331{
332   FREE(stage);
333}
334
335
336/**
337 * Create validate pipeline stage.
338 */
339struct draw_stage *
340draw_validate_stage(struct draw_context *draw)
341{
342   struct draw_stage *stage = CALLOC_STRUCT(draw_stage);
343   if (!stage)
344      return NULL;
345
346   stage->draw = draw;
347   stage->name = "validate";
348   stage->next = NULL;
349   stage->point = validate_point;
350   stage->line = validate_line;
351   stage->tri = validate_tri;
352   stage->flush = validate_flush;
353   stage->reset_stipple_counter = validate_reset_stipple_counter;
354   stage->destroy = validate_destroy;
355
356   return stage;
357}
358