u_blitter: add a msaa parameter to util_blitter_clear
[mesa.git] / src / gallium / drivers / svga / svga_pipe_rasterizer.c
index e97b4e57415b9ceec803ef1c6c277fcbf080da9a..7d5936fa1ece2aedf1c75ef7748922bb4dfe625d 100644 (file)
  *
  **********************************************************/
 
+#include "pipe/p_defines.h"
 #include "draw/draw_context.h"
+#include "util/u_bitmask.h"
 #include "util/u_inlines.h"
-#include "pipe/p_defines.h"
 #include "util/u_math.h"
 #include "util/u_memory.h"
 
+#include "svga_cmd.h"
 #include "svga_context.h"
-
 #include "svga_hw_reg.h"
+#include "svga_screen.h"
+
 
 /* Hardware frontwinding is always set up as SVGA3D_FRONTWINDING_CW.
  */
-static SVGA3dFace svga_translate_cullmode( unsigned mode,
-                                           unsigned front_ccw )
+static SVGA3dFace
+svga_translate_cullmode(unsigned mode, unsigned front_ccw)
 {
    const int hw_front_ccw = 0;  /* hardware is always CW */
    switch (mode) {
@@ -54,68 +57,202 @@ static SVGA3dFace svga_translate_cullmode( unsigned mode,
    }
 }
 
-static SVGA3dShadeMode svga_translate_flatshade( unsigned mode )
+static SVGA3dShadeMode
+svga_translate_flatshade(unsigned mode)
 {
    return mode ? SVGA3D_SHADEMODE_FLAT : SVGA3D_SHADEMODE_SMOOTH;
 }
 
 
+static unsigned
+translate_fill_mode(unsigned fill)
+{
+   switch (fill) {
+   case PIPE_POLYGON_MODE_POINT:
+      return SVGA3D_FILLMODE_POINT;
+   case PIPE_POLYGON_MODE_LINE:
+      return SVGA3D_FILLMODE_LINE;
+   case PIPE_POLYGON_MODE_FILL:
+      return SVGA3D_FILLMODE_FILL;
+   default:
+      assert(!"Bad fill mode");
+      return SVGA3D_FILLMODE_FILL;
+   }
+}
+
+
+static unsigned
+translate_cull_mode(unsigned cull)
+{
+   switch (cull) {
+   case PIPE_FACE_NONE:
+      return SVGA3D_CULL_NONE;
+   case PIPE_FACE_FRONT:
+      return SVGA3D_CULL_FRONT;
+   case PIPE_FACE_BACK:
+      return SVGA3D_CULL_BACK;
+   case PIPE_FACE_FRONT_AND_BACK:
+      /* NOTE: we simply no-op polygon drawing in svga_draw_vbo() */
+      return SVGA3D_CULL_NONE;
+   default:
+      assert(!"Bad cull mode");
+      return SVGA3D_CULL_NONE;
+   }
+}
+
+
+static void
+define_rasterizer_object(struct svga_context *svga,
+                         struct svga_rasterizer_state *rast)
+{
+   struct svga_screen *svgascreen = svga_screen(svga->pipe.screen);
+   unsigned fill_mode = translate_fill_mode(rast->templ.fill_front);
+   const unsigned cull_mode = translate_cull_mode(rast->templ.cull_face);
+   const int depth_bias = rast->templ.offset_units;
+   const float slope_scaled_depth_bias = rast->templ.offset_scale;
+   /* PIPE_CAP_POLYGON_OFFSET_CLAMP not supported: */
+   const float depth_bias_clamp = 0.0;
+   const float line_width = rast->templ.line_width > 0.0f ?
+      rast->templ.line_width : 1.0f;
+   const uint8 line_factor = rast->templ.line_stipple_enable ?
+      rast->templ.line_stipple_factor : 0;
+   const uint16 line_pattern = rast->templ.line_stipple_enable ?
+      rast->templ.line_stipple_pattern : 0;
+   unsigned try;
+
+   rast->id = util_bitmask_add(svga->rast_object_id_bm);
+
+   if (rast->templ.fill_front != rast->templ.fill_back) {
+      /* The VGPU10 device can't handle different front/back fill modes.
+       * We'll handle that with a swtnl/draw fallback.  But we need to
+       * make sure we always fill triangles in that case.
+       */
+      fill_mode = SVGA3D_FILLMODE_FILL;
+   }
+
+   for (try = 0; try < 2; try++) {
+      const uint8 pv_last = !rast->templ.flatshade_first &&
+         svgascreen->haveProvokingVertex;
+      enum pipe_error ret =
+         SVGA3D_vgpu10_DefineRasterizerState(svga->swc,
+                                             rast->id,
+                                             fill_mode,
+                                             cull_mode,
+                                             rast->templ.front_ccw,
+                                             depth_bias,
+                                             depth_bias_clamp,
+                                             slope_scaled_depth_bias,
+                                             rast->templ.depth_clip_near,
+                                             rast->templ.scissor,
+                                             rast->templ.multisample,
+                                             rast->templ.line_smooth,
+                                             line_width,
+                                             rast->templ.line_stipple_enable,
+                                             line_factor,
+                                             line_pattern,
+                                             pv_last);
+      if (ret == PIPE_OK)
+         return;
+      svga_context_flush(svga, NULL);
+   }
+}
+
+
 static void *
 svga_create_rasterizer_state(struct pipe_context *pipe,
                              const struct pipe_rasterizer_state *templ)
 {
-   struct svga_rasterizer_state *rast = CALLOC_STRUCT( svga_rasterizer_state );
+   struct svga_context *svga = svga_context(pipe);
+   struct svga_rasterizer_state *rast = CALLOC_STRUCT(svga_rasterizer_state);
+   struct svga_screen *screen = svga_screen(pipe->screen);
+
+   if (!rast)
+      return NULL;
+
    /* need this for draw module. */
    rast->templ = *templ;
 
-   /* light_twoside          - XXX: need fragment shader variant */
-   /* poly_smooth            - XXX: no fallback available */
-   /* poly_stipple_enable    - draw module */
-   /* sprite_coord_enable    - ? */
-   /* point_quad_rasterization - ? */
-   /* point_size_per_vertex  - ? */
-   /* sprite_coord_mode      - ??? */
-   /* bypass_vs_viewport_and_clip        - handled by viewport setup */
-   /* flatshade_first        - handled by index translation */
-   /* gl_rasterization_rules - XXX - viewport code */
-   /* line_width             - draw module */
-   /* fill_cw, fill_ccw      - draw module or index translation */
-
-   rast->shademode = svga_translate_flatshade( templ->flatshade );
-   rast->cullmode = svga_translate_cullmode( templ->cull_face, 
-                                             templ->front_ccw );
+   rast->shademode = svga_translate_flatshade(templ->flatshade);
+   rast->cullmode = svga_translate_cullmode(templ->cull_face, templ->front_ccw);
    rast->scissortestenable = templ->scissor;
    rast->multisampleantialias = templ->multisample;
    rast->antialiasedlineenable = templ->line_smooth;
    rast->lastpixel = templ->line_last_pixel;
-   rast->pointsize = templ->point_size;
-   rast->hw_unfilled = PIPE_POLYGON_MODE_FILL;
+   rast->pointsprite = templ->point_quad_rasterization;
+
+   if (rast->templ.multisample) {
+      /* The OpenGL 3.0 spec says points are always drawn as circles when
+       * MSAA is enabled.  Note that our implementation isn't 100% correct,
+       * though.  Our smooth point implementation involves drawing a square,
+       * computing fragment distance from point center, then attenuating
+       * the fragment alpha value.  We should not attenuate alpha if msaa
+       * is enabled.  We should kill fragments entirely outside the circle
+       * and let the GPU compute per-fragment coverage.
+       * But as-is, our implementation gives acceptable results and passes
+       * Piglit's MSAA point smooth test.
+       */
+      rast->templ.point_smooth = TRUE;
+   }
+
+   if (templ->point_smooth) {
+      /* For smooth points we need to generate fragments for at least
+       * a 2x2 region.  Otherwise the quad we draw may be too small and
+       * we may generate no fragments at all.
+       */
+      rast->pointsize = MAX2(2.0f, templ->point_size);
+   }
+   else {
+      rast->pointsize = templ->point_size;
+   }
+
+   rast->hw_fillmode = PIPE_POLYGON_MODE_FILL;
 
    /* Use swtnl + decomposition implement these:
     */
-   if (templ->poly_stipple_enable)
-      rast->need_pipeline |= SVGA_PIPELINE_FLAG_TRIS;
 
-   if (templ->line_width != 1.0 &&
-       templ->line_width != 0.0)
+   if (templ->line_width <= screen->maxLineWidth) {
+      /* pass line width to device */
+      rast->linewidth = MAX2(1.0F, templ->line_width);
+   }
+   else if (svga->debug.no_line_width) {
+      /* nothing */
+   }
+   else {
+      /* use 'draw' pipeline for wide line */
       rast->need_pipeline |= SVGA_PIPELINE_FLAG_LINES;
+      rast->need_pipeline_lines_str = "line width";
+   }
 
    if (templ->line_stipple_enable) {
-      /* LinePattern not implemented on all backends. 
-       */
-      if (0) {
+      if (screen->haveLineStipple || svga->debug.force_hw_line_stipple) {
          SVGA3dLinePattern lp;
          lp.repeat = templ->line_stipple_factor + 1;
          lp.pattern = templ->line_stipple_pattern;
          rast->linepattern = lp.uintValue;
       }
       else {
+         /* use 'draw' module to decompose into short line segments */
          rast->need_pipeline |= SVGA_PIPELINE_FLAG_LINES;
+         rast->need_pipeline_lines_str = "line stipple";
       }
-   } 
+   }
 
-   if (templ->point_smooth)
+   if (!svga_have_vgpu10(svga) && templ->point_smooth) {
       rast->need_pipeline |= SVGA_PIPELINE_FLAG_POINTS;
+      rast->need_pipeline_points_str = "smooth points";
+   }
+
+   if (templ->line_smooth && !screen->haveLineSmooth) {
+      /*
+       * XXX: Enabling the pipeline slows down performance immensely, so ignore
+       * line smooth state, where there is very little visual improvement.
+       * Smooth lines will still be drawn for wide lines.
+       */
+#if 0
+      rast->need_pipeline |= SVGA_PIPELINE_FLAG_LINES;
+      rast->need_pipeline_lines_str = "smooth lines";
+#endif
+   }
 
    {
       int fill_front = templ->fill_front;
@@ -123,31 +260,32 @@ svga_create_rasterizer_state(struct pipe_context *pipe,
       int fill = PIPE_POLYGON_MODE_FILL;
       boolean offset_front = util_get_offset(templ, fill_front);
       boolean offset_back = util_get_offset(templ, fill_back);
-      boolean offset  = 0;
+      boolean offset = FALSE;
 
       switch (templ->cull_face) {
       case PIPE_FACE_FRONT_AND_BACK:
-         offset = 0;
+         offset = FALSE;
          fill = PIPE_POLYGON_MODE_FILL;
          break;
 
       case PIPE_FACE_FRONT:
-         offset = offset_front;
-         fill = fill_front;
+         offset = offset_back;
+         fill = fill_back;
          break;
 
       case PIPE_FACE_BACK:
-         offset = offset_back;
-         fill = fill_back;
+         offset = offset_front;
+         fill = fill_front;
          break;
 
       case PIPE_FACE_NONE:
-         if (fill_front != fill_back || offset_front != offset_back) 
-         {
+         if (fill_front != fill_back || offset_front != offset_back) {
             /* Always need the draw module to work out different
              * front/back fill modes:
              */
             rast->need_pipeline |= SVGA_PIPELINE_FLAG_TRIS;
+            rast->need_pipeline_tris_str = "different front/back fillmodes";
+            fill = PIPE_POLYGON_MODE_FILL;
          }
          else {
             offset = offset_front;
@@ -167,30 +305,29 @@ svga_create_rasterizer_state(struct pipe_context *pipe,
       if (fill != PIPE_POLYGON_MODE_FILL &&
           (templ->flatshade ||
            templ->light_twoside ||
-           offset ||
-           templ->cull_face != PIPE_FACE_NONE)) 
-      {
+           offset)) {
          fill = PIPE_POLYGON_MODE_FILL;
          rast->need_pipeline |= SVGA_PIPELINE_FLAG_TRIS;
+         rast->need_pipeline_tris_str = "unfilled primitives with no index manipulation";
       }
 
       /* If we are decomposing to lines, and lines need the pipeline,
        * then we also need the pipeline for tris.
        */
       if (fill == PIPE_POLYGON_MODE_LINE &&
-          (rast->need_pipeline & SVGA_PIPELINE_FLAG_LINES))
-      {
+          (rast->need_pipeline & SVGA_PIPELINE_FLAG_LINES)) {
          fill = PIPE_POLYGON_MODE_FILL;
          rast->need_pipeline |= SVGA_PIPELINE_FLAG_TRIS;
+         rast->need_pipeline_tris_str = "decomposing lines";
       }
 
       /* Similarly for points:
        */
       if (fill == PIPE_POLYGON_MODE_POINT &&
-          (rast->need_pipeline & SVGA_PIPELINE_FLAG_POINTS))
-      {
+          (rast->need_pipeline & SVGA_PIPELINE_FLAG_POINTS)) {
          fill = PIPE_POLYGON_MODE_FILL;
          rast->need_pipeline |= SVGA_PIPELINE_FLAG_TRIS;
+         rast->need_pipeline_tris_str = "decomposing points";
       }
 
       if (offset) {
@@ -198,53 +335,97 @@ svga_create_rasterizer_state(struct pipe_context *pipe,
          rast->depthbias = templ->offset_units;
       }
 
-      rast->hw_unfilled = fill;
+      rast->hw_fillmode = fill;
    }
 
-
-
-
    if (rast->need_pipeline & SVGA_PIPELINE_FLAG_TRIS) {
       /* Turn off stuff which will get done in the draw module:
        */
-      rast->hw_unfilled = PIPE_POLYGON_MODE_FILL;
+      rast->hw_fillmode = PIPE_POLYGON_MODE_FILL;
       rast->slopescaledepthbias = 0;
       rast->depthbias = 0;
    }
 
+   if (0 && rast->need_pipeline) {
+      debug_printf("svga: rast need_pipeline = 0x%x\n", rast->need_pipeline);
+      debug_printf(" pnts: %s \n", rast->need_pipeline_points_str);
+      debug_printf(" lins: %s \n", rast->need_pipeline_lines_str);
+      debug_printf(" tris: %s \n", rast->need_pipeline_tris_str);
+   }
+
+   if (svga_have_vgpu10(svga)) {
+      define_rasterizer_object(svga, rast);
+   }
+
+   if (templ->poly_smooth) {
+      pipe_debug_message(&svga->debug.callback, CONFORMANCE,
+                         "GL_POLYGON_SMOOTH not supported");
+   }
+
+   svga->hud.num_rasterizer_objects++;
+   SVGA_STATS_COUNT_INC(svga_screen(svga->pipe.screen)->sws,
+                        SVGA_STATS_COUNT_RASTERIZERSTATE);
+
    return rast;
 }
 
-static void svga_bind_rasterizer_state( struct pipe_context *pipe,
-                                        void *state )
+
+static void
+svga_bind_rasterizer_state(struct pipe_context *pipe, void *state)
 {
    struct svga_context *svga = svga_context(pipe);
    struct svga_rasterizer_state *raster = (struct svga_rasterizer_state *)state;
 
+   if (!raster || !svga->curr.rast) {
+      svga->dirty |= SVGA_NEW_STIPPLE | SVGA_NEW_DEPTH_STENCIL_ALPHA;
+   }
+   else {
+      if (raster->templ.poly_stipple_enable !=
+          svga->curr.rast->templ.poly_stipple_enable) {
+         svga->dirty |= SVGA_NEW_STIPPLE;
+      }
+      if (raster->templ.rasterizer_discard !=
+          svga->curr.rast->templ.rasterizer_discard) {
+         svga->dirty |= SVGA_NEW_DEPTH_STENCIL_ALPHA;
+      }
+   }
+
    svga->curr.rast = raster;
 
-   draw_set_rasterizer_state(svga->swtnl.draw, raster ? &raster->templ : NULL,
-                             state);
-   
    svga->dirty |= SVGA_NEW_RAST;
 }
 
-static void svga_delete_rasterizer_state(struct pipe_context *pipe,
-                                         void *raster)
+
+static void
+svga_delete_rasterizer_state(struct pipe_context *pipe, void *state)
 {
-   FREE(raster);
+   struct svga_context *svga = svga_context(pipe);
+   struct svga_rasterizer_state *raster =
+      (struct svga_rasterizer_state *) state;
+
+   if (svga_have_vgpu10(svga)) {
+      enum pipe_error ret =
+         SVGA3D_vgpu10_DestroyRasterizerState(svga->swc, raster->id);
+      if (ret != PIPE_OK) {
+         svga_context_flush(svga, NULL);
+         ret = SVGA3D_vgpu10_DestroyRasterizerState(svga->swc, raster->id);
+      }
+
+      if (raster->id == svga->state.hw_draw.rasterizer_id)
+         svga->state.hw_draw.rasterizer_id = SVGA3D_INVALID_ID;
+
+      util_bitmask_clear(svga->rast_object_id_bm, raster->id);
+   }
+
+   FREE(state);
+   svga->hud.num_rasterizer_objects--;
 }
 
 
-void svga_init_rasterizer_functions( struct svga_context *svga )
+void
+svga_init_rasterizer_functions(struct svga_context *svga)
 {
    svga->pipe.create_rasterizer_state = svga_create_rasterizer_state;
    svga->pipe.bind_rasterizer_state = svga_bind_rasterizer_state;
    svga->pipe.delete_rasterizer_state = svga_delete_rasterizer_state;
 }
-
-
-/***********************************************************************
- * Hardware state update
- */
-