Skip to content

Commit

Permalink
gl: Avoid using gl_FragCoord for linear gradients.
Browse files Browse the repository at this point in the history
The issue is that we store our data flipped based on whether we're
rendering to an FBO or to a window.  By not flipping our gl_FragCoord
usage based on that (either with math or ARB_frag_coord_conventions),
this caused linear gradients to be flipped when rendering either to a
window or to an FBO.  To avoid this, pass in appropriate texcoords.
And, if we're passing in texcoords, just do the projection to the
linear gradient factor on the CPU side per vertex instead of providing
a bunch of uniforms to do the math per fragment.

Fixes 18 testcases.
  • Loading branch information
Eric Anholt committed Nov 15, 2010
1 parent 7237eb6 commit 31e116f
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 39 deletions.
74 changes: 45 additions & 29 deletions src/cairo-gl-composite.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,31 +161,39 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,

if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
double x0, y0, x1, y1;

x0 = _cairo_fixed_to_double (linear->p1.x);
x1 = _cairo_fixed_to_double (linear->p2.x);
y0 = _cairo_fixed_to_double (linear->p1.y);
y1 = _cairo_fixed_to_double (linear->p2.y);
double x0, y0;
float dx, dy, sf, offset;

status = _cairo_gl_create_gradient_texture (dst,
gradient,
&operand->linear.gradient);
if (unlikely (status))
return status;

/* Translation matrix from the destination fragment coordinates
* (pixels from lower left = 0,0) to the coordinates in the
*/
cairo_matrix_init_translate (&operand->linear.m, -x0, -y0);
cairo_matrix_multiply (&operand->linear.m,
&pattern->matrix,
&operand->linear.m);
cairo_matrix_translate (&operand->linear.m, 0, dst->height);
cairo_matrix_scale (&operand->linear.m, 1.0, -1.0);
dx = _cairo_fixed_to_double (linear->p2.x - linear->p1.x);
dy = _cairo_fixed_to_double (linear->p2.y - linear->p1.y);
sf = 1.0 / (dx * dx + dy * dy);
dx *= sf;
dy *= sf;

operand->linear.segment_x = x1 - x0;
operand->linear.segment_y = y1 - y0;
x0 = _cairo_fixed_to_double (linear->p1.x);
y0 = _cairo_fixed_to_double (linear->p1.y);
offset = dx * x0 + dy * y0;

if (_cairo_matrix_is_identity (&linear->base.base.matrix)) {
operand->linear.m.xx = dx;
operand->linear.m.xy = dy;
operand->linear.m.x0 = -offset;
} else {
cairo_matrix_t m;

cairo_matrix_init (&m, dx, 0, dy, 0, -offset, 0);
cairo_matrix_multiply (&operand->linear.m,
&linear->base.base.matrix, &m);
}
operand->linear.m.yx = 0.0;
operand->linear.m.yy = 1.0;
operand->linear.m.y0 = 0.0;

operand->linear.extend = pattern->extend;

Expand Down Expand Up @@ -368,15 +376,6 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
operand->constant.color[3]);
break;
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
strcpy (custom_part, "_matrix");
_cairo_gl_shader_bind_matrix (ctx,
uniform_name,
&operand->linear.m);
strcpy (custom_part, "_segment");
_cairo_gl_shader_bind_vec2 (ctx,
uniform_name,
operand->linear.segment_x,
operand->linear.segment_y);
strcpy (custom_part, "_sampler");
_cairo_gl_shader_bind_texture(ctx,
uniform_name,
Expand Down Expand Up @@ -640,7 +639,12 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
_cairo_gl_texture_set_extend (ctx, GL_TEXTURE_1D, operand->linear.extend);
_cairo_gl_texture_set_filter (ctx, GL_TEXTURE_1D, CAIRO_FILTER_BILINEAR);
glEnable (GL_TEXTURE_1D);
break;

glClientActiveTexture (GL_TEXTURE0 + tex_unit);
glTexCoordPointer (2, GL_FLOAT, vertex_size,
(void *) (uintptr_t) vertex_offset);
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
break;
case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
_cairo_gl_gradient_reference (operand->radial.gradient);
glActiveTexture (GL_TEXTURE0 + tex_unit);
Expand Down Expand Up @@ -686,6 +690,8 @@ _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
_cairo_gl_gradient_destroy (ctx->operands[tex_unit].linear.gradient);
glActiveTexture (GL_TEXTURE0 + tex_unit);
glDisable (GL_TEXTURE_1D);
glClientActiveTexture (GL_TEXTURE0 + tex_unit);
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
break;
case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
_cairo_gl_gradient_destroy (ctx->operands[tex_unit].radial.gradient);
Expand Down Expand Up @@ -784,12 +790,12 @@ _cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type)
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
case CAIRO_GL_OPERAND_CONSTANT:
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
return 0;
case CAIRO_GL_OPERAND_SPANS:
return 4 * sizeof (GLbyte);
case CAIRO_GL_OPERAND_TEXTURE:
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
return 2 * sizeof (GLfloat);
}
}
Expand Down Expand Up @@ -1075,7 +1081,6 @@ _cairo_gl_operand_emit (cairo_gl_operand_t *operand,
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
case CAIRO_GL_OPERAND_CONSTANT:
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
break;
case CAIRO_GL_OPERAND_SPANS:
Expand All @@ -1092,6 +1097,17 @@ _cairo_gl_operand_emit (cairo_gl_operand_t *operand,
*(*vb)++ = fi.f;
}
break;
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
{
double s = x;
double t = y;

cairo_matrix_transform_point (&operand->linear.m, &s, &t);

*(*vb)++ = s;
*(*vb)++ = 0.0;
}
break;
case CAIRO_GL_OPERAND_TEXTURE:
{
cairo_surface_attributes_t *src_attributes = &operand->texture.attributes;
Expand Down
4 changes: 2 additions & 2 deletions src/cairo-gl-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ typedef struct cairo_gl_operand {
struct {
cairo_gl_gradient_t *gradient;
cairo_matrix_t m;
float segment_x;
float segment_y;
float x0, y0, dx, dy;
float scale;
cairo_extend_t extend;
} linear;
struct {
Expand Down
12 changes: 4 additions & 8 deletions src/cairo-gl-shaders.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,9 +568,9 @@ cairo_gl_operand_get_var_type (cairo_gl_operand_type_t type)
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
case CAIRO_GL_OPERAND_CONSTANT:
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
return CAIRO_GL_VAR_NONE;
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
case CAIRO_GL_OPERAND_TEXTURE:
return CAIRO_GL_VAR_TEXCOORDS;
case CAIRO_GL_OPERAND_SPANS:
Expand Down Expand Up @@ -700,18 +700,14 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
break;
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
_cairo_output_stream_printf (stream,
"varying vec2 %s_texcoords;\n"
"uniform sampler1D %s_sampler;\n"
"uniform mat3 %s_matrix;\n"
"uniform vec2 %s_segment;\n"
"\n"
"vec4 get_%s()\n"
"{\n"
" vec2 pos = (%s_matrix * vec3 (gl_FragCoord.xy, 1.0)).xy;\n"
" float t = dot (pos, %s_segment) / dot (%s_segment, %s_segment);\n"
" return texture1D (%s_sampler, t);\n"
" return texture1D (%s_sampler, %s_texcoords.x);\n"
"}\n",
namestr, namestr, namestr, namestr, namestr,
namestr, namestr, namestr, namestr);
namestr, namestr, namestr, namestr, namestr);
break;
case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
_cairo_output_stream_printf (stream,
Expand Down

0 comments on commit 31e116f

Please sign in to comment.