st/vega: Fix degenerate paints.
authorChia-I Wu <olv@lunarg.com>
Wed, 1 Dec 2010 03:54:58 +0000 (11:54 +0800)
committerChia-I Wu <olv@lunarg.com>
Wed, 1 Dec 2010 08:46:01 +0000 (16:46 +0800)
Fix the case that the two points of a linear gradient coincide, or the
case that the radius of a radial gradient is equal to or less than 0.

src/gallium/state_trackers/vega/asm_fill.h
src/gallium/state_trackers/vega/paint.c
src/gallium/state_trackers/vega/paint.h
src/gallium/state_trackers/vega/shader.c
src/gallium/state_trackers/vega/shaders_cache.c
src/gallium/state_trackers/vega/shaders_cache.h

index 0e29aab88a6295d8961ee3653a22010146bb2688..fcc953ced8e0dcbd6aec16dc744b166a2b81b356 100644 (file)
@@ -179,6 +179,18 @@ pattern( struct ureg_program *ureg,
    ureg_TEX(ureg, *out, TGSI_TEXTURE_2D, ureg_src(temp[1]), sampler[0]);
 }
 
+static INLINE void
+paint_degenerate( struct ureg_program *ureg,
+                  struct ureg_dst *out,
+                  struct ureg_src *in,
+                  struct ureg_src *sampler,
+                  struct ureg_dst *temp,
+                  struct ureg_src *constant)
+{
+   ureg_MOV(ureg, temp[1], ureg_scalar(constant[3], TGSI_SWIZZLE_Y));
+   ureg_TEX(ureg, *out, TGSI_TEXTURE_1D, ureg_src(temp[1]), sampler[0]);
+}
+
 static INLINE void
 color_transform( struct ureg_program *ureg,
                  struct ureg_dst *out,
@@ -436,7 +448,9 @@ static const struct shader_asm_info shaders_paint_asm[] = {
    {VEGA_RADIAL_GRADIENT_SHADER, radial_grad,
     VG_TRUE,  2, 5, 0, 1, 0, 6},
    {VEGA_PATTERN_SHADER, pattern,
-    VG_TRUE,  3, 4, 0, 1, 0, 5}
+    VG_TRUE,  3, 4, 0, 1, 0, 5},
+   {VEGA_PAINT_DEGENERATE_SHADER, paint_degenerate,
+    VG_FALSE,  3, 1, 0, 1, 0, 2}
 };
 
 /* image draw modes */
index 467d39297548b3b4961aa97f065df33377a80aec..cf9a85d95dbfba3947b3334c77c6a072634edf87 100644 (file)
@@ -266,10 +266,13 @@ static INLINE void paint_linear_gradient_buffer(struct vg_paint *paint,
                                                 void *buffer)
 {
    VGfloat *map = (VGfloat*)buffer;
+   VGfloat dd;
 
    map[0] = paint->gradient.linear.coords[2] - paint->gradient.linear.coords[0];
    map[1] = paint->gradient.linear.coords[3] - paint->gradient.linear.coords[1];
-   map[2] = 1.f / (map[0] * map[0] + map[1] * map[1]);
+   dd = (map[0] * map[0] + map[1] * map[1]);
+
+   map[2] = (dd > 0.0f) ? 1.f / dd : 0.f;
    map[3] = 1.f;
 
    map[4] = 0.f;
@@ -298,14 +301,33 @@ static INLINE void paint_radial_gradient_buffer(struct vg_paint *paint,
                                                 const struct matrix *inv,
                                                 void *buffer)
 {
-   VGfloat *radialCoords = paint->gradient.radial.vals;
-
+   const VGfloat *center = &paint->gradient.radial.vals[0];
+   const VGfloat *focal = &paint->gradient.radial.vals[2];
+   VGfloat rr = paint->gradient.radial.vals[4];
    VGfloat *map = (VGfloat*)buffer;
+   VGfloat dd, new_focal[2];
+
+   rr *= rr;
+
+   map[0] = center[0] - focal[0];
+   map[1] = center[1] - focal[1];
+   dd = map[0] * map[0] + map[1] * map[1];
+
+   /* focal point must lie inside the circle */
+   if (0.998f * rr < dd) {
+      VGfloat scale;
+
+      scale = (dd > 0.0f) ? sqrt(0.998f * rr / dd) : 0.0f;
+      map[0] *= scale;
+      map[1] *= scale;
 
-   map[0] = radialCoords[0] - radialCoords[2];
-   map[1] = radialCoords[1] - radialCoords[3];
-   map[2] = -map[0] * map[0] - map[1] * map[1] +
-            radialCoords[4] * radialCoords[4];
+      new_focal[0] = center[0] - map[0];
+      new_focal[1] = center[1] - map[1];
+      dd = map[0] * map[0] + map[1] * map[1];
+      focal = new_focal;
+   }
+
+   map[2] = (rr > dd) ? rr - dd : 1.0f;
    map[3] = 1.f;
 
    map[4] = 0.f;
@@ -316,7 +338,7 @@ static INLINE void paint_radial_gradient_buffer(struct vg_paint *paint,
    {
       struct matrix mat;
       matrix_load_identity(&mat);
-      matrix_translate(&mat, -radialCoords[2], -radialCoords[3]);
+      matrix_translate(&mat, -focal[0], -focal[1]);
       matrix_mult(&mat, inv);
 
       map[8]  = mat.m[0]; map[9]  = mat.m[3]; map[10] = mat.m[6]; map[11] = 0.f;
@@ -654,6 +676,34 @@ void paint_resolve_type(struct vg_paint *paint)
    }
 }
 
+VGboolean paint_is_degenerate(struct vg_paint *paint)
+{
+   VGboolean degen;
+   VGfloat *vals;
+
+
+   switch (paint->type) {
+   case VG_PAINT_TYPE_LINEAR_GRADIENT:
+      vals = paint->gradient.linear.coords;
+      /* two points are coincident */
+      degen = (floatsEqual(vals[0], vals[2]) &&
+               floatsEqual(vals[1], vals[3]));
+      break;
+   case VG_PAINT_TYPE_RADIAL_GRADIENT:
+      vals = paint->gradient.radial.vals;
+      /* radius <= 0 */
+      degen = (vals[4] <= 0.0f);
+      break;
+   case VG_PAINT_TYPE_COLOR:
+   case VG_PAINT_TYPE_PATTERN:
+   default:
+      degen = VG_FALSE;
+      break;
+   }
+
+   return degen;
+}
+
 VGint paint_constant_buffer_size(struct vg_paint *paint)
 {
    switch(paint->type) {
index 2e09b839a4ad731082ae8f80fb2ca3cdc74fafa8..3de3bbe12eda91fc9c00fd03df54ecdab09a5359 100644 (file)
@@ -110,6 +110,8 @@ VGboolean paint_color_ramp_premultiplied(struct vg_paint *paint);
 VGint paint_bind_samplers(struct vg_paint *paint, struct pipe_sampler_state **samplers,
                           struct pipe_sampler_view **sampler_views);
 
+VGboolean paint_is_degenerate(struct vg_paint *paint);
+
 VGint paint_constant_buffer_size(struct vg_paint *paint);
 
 void paint_fill_constant_buffer(struct vg_paint *paint,
index a77587c6bfff472eb01bf23ef0ebf45f560abc60..483ff15098fbcb00836d6f504cacfe3ea6a9d7ea 100644 (file)
@@ -233,6 +233,9 @@ static void setup_shader_program(struct shader *shader)
       default:
          abort();
       }
+
+      if (paint_is_degenerate(shader->paint))
+         shader_id = VEGA_PAINT_DEGENERATE_SHADER;
    }
 
    /* second stage image */
index 732d57de9a06a6d10adf050c6e5b860a5384c4e8..d1ebe7e67797d6b65ea85352fbc3a115bee3c624 100644 (file)
@@ -261,6 +261,7 @@ create_shader(struct pipe_context *pipe,
    case VEGA_LINEAR_GRADIENT_SHADER:
    case VEGA_RADIAL_GRADIENT_SHADER:
    case VEGA_PATTERN_SHADER:
+   case VEGA_PAINT_DEGENERATE_SHADER:
       shaders[idx] = &shaders_paint_asm[(sh >> SHADERS_PAINT_SHIFT) - 1];
       assert(shaders[idx]->id == sh);
       idx++;
index 9c5ede6a2440dde0be18600a3734968099565718..b626045f9af5cd6f1bc6bd385987914dcd7d78c9 100644 (file)
@@ -65,6 +65,7 @@ enum VegaShaderType {
    VEGA_LINEAR_GRADIENT_SHADER    = 2 << SHADERS_PAINT_SHIFT,
    VEGA_RADIAL_GRADIENT_SHADER    = 3 << SHADERS_PAINT_SHIFT,
    VEGA_PATTERN_SHADER            = 4 << SHADERS_PAINT_SHIFT,
+   VEGA_PAINT_DEGENERATE_SHADER   = 5 << SHADERS_PAINT_SHIFT,
 
    VEGA_IMAGE_NORMAL_SHADER       = 1 << SHADERS_IMAGE_SHIFT,
    VEGA_IMAGE_MULTIPLY_SHADER     = 2 << SHADERS_IMAGE_SHIFT,