From d7aa03b4feb7c30408b2ed3070e0fe33e2fd05ba Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Wed, 1 Dec 2010 11:54:58 +0800 Subject: st/vega: Fix degenerate paints. 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 | 16 +++++- src/gallium/state_trackers/vega/paint.c | 66 ++++++++++++++++++++++--- src/gallium/state_trackers/vega/paint.h | 2 + src/gallium/state_trackers/vega/shader.c | 3 ++ src/gallium/state_trackers/vega/shaders_cache.c | 1 + src/gallium/state_trackers/vega/shaders_cache.h | 1 + 6 files changed, 80 insertions(+), 9 deletions(-) diff --git a/src/gallium/state_trackers/vega/asm_fill.h b/src/gallium/state_trackers/vega/asm_fill.h index 0e29aab88a6..fcc953ced8e 100644 --- a/src/gallium/state_trackers/vega/asm_fill.h +++ b/src/gallium/state_trackers/vega/asm_fill.h @@ -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 */ diff --git a/src/gallium/state_trackers/vega/paint.c b/src/gallium/state_trackers/vega/paint.c index 467d3929754..cf9a85d95db 100644 --- a/src/gallium/state_trackers/vega/paint.c +++ b/src/gallium/state_trackers/vega/paint.c @@ -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) { diff --git a/src/gallium/state_trackers/vega/paint.h b/src/gallium/state_trackers/vega/paint.h index 2e09b839a4a..3de3bbe12ed 100644 --- a/src/gallium/state_trackers/vega/paint.h +++ b/src/gallium/state_trackers/vega/paint.h @@ -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, diff --git a/src/gallium/state_trackers/vega/shader.c b/src/gallium/state_trackers/vega/shader.c index a77587c6bff..483ff15098f 100644 --- a/src/gallium/state_trackers/vega/shader.c +++ b/src/gallium/state_trackers/vega/shader.c @@ -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 */ diff --git a/src/gallium/state_trackers/vega/shaders_cache.c b/src/gallium/state_trackers/vega/shaders_cache.c index 732d57de9a0..d1ebe7e6779 100644 --- a/src/gallium/state_trackers/vega/shaders_cache.c +++ b/src/gallium/state_trackers/vega/shaders_cache.c @@ -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++; diff --git a/src/gallium/state_trackers/vega/shaders_cache.h b/src/gallium/state_trackers/vega/shaders_cache.h index 9c5ede6a244..b626045f9af 100644 --- a/src/gallium/state_trackers/vega/shaders_cache.h +++ b/src/gallium/state_trackers/vega/shaders_cache.h @@ -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, -- cgit v1.2.3