mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-05 18:08:03 +02:00
[gl] Use GL_RGBA textures even for CAIRO_CONTENT_COLOR.
When the texture is GL_RGB, GL_CLAMP_TO_BORDER (EXTEND_NONE) fills the border color alpha channel with 1, when the whole reason we were using the border color was to get a color and alpha of 0. We're forced to use GL_RGBA textures and do extra work to fill in the alpha channel of them to 1 to get cairo's desired behavior. This fixes a failure in rotate-image-surface-paint and 4 other testcases. No performance difference in firefox-talos-gfx.
This commit is contained in:
parent
e316cb9db5
commit
12d521df8a
1 changed files with 75 additions and 56 deletions
|
|
@ -42,6 +42,13 @@
|
|||
slim_hidden_proto (cairo_gl_context_reference);
|
||||
slim_hidden_proto (cairo_gl_context_destroy);
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_gl_surface_fill_rectangles (void *abstract_surface,
|
||||
cairo_operator_t op,
|
||||
const cairo_color_t *color,
|
||||
cairo_rectangle_int_t *rects,
|
||||
int num_rects);
|
||||
|
||||
#define BIAS .375
|
||||
|
||||
static inline float
|
||||
|
|
@ -379,8 +386,9 @@ _cairo_gl_set_operator (cairo_gl_surface_t *dst, cairo_operator_t op,
|
|||
src_factor = blend_factors[op].src;
|
||||
dst_factor = blend_factors[op].dst;
|
||||
|
||||
/* We may have a visual with alpha bits despite the user requesting
|
||||
* CAIRO_CONTENT_COLOR. So clear out those bits in that case.
|
||||
/* Even when the user requests CAIRO_CONTENT_COLOR, we use GL_RGBA
|
||||
* due to texture filtering of GL_CLAMP_TO_BORDER. So fix those
|
||||
* bits in that case.
|
||||
*/
|
||||
if (dst->base.content == CAIRO_CONTENT_COLOR) {
|
||||
if (src_factor == GL_ONE_MINUS_DST_ALPHA)
|
||||
|
|
@ -486,10 +494,19 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
|
|||
format = GL_RGBA;
|
||||
break;
|
||||
case CAIRO_CONTENT_ALPHA:
|
||||
/* We want to be trying GL_ALPHA framebuffer objects here. */
|
||||
format = GL_RGBA;
|
||||
break;
|
||||
case CAIRO_CONTENT_COLOR:
|
||||
format = GL_RGB;
|
||||
/* GL_RGB is almost what we want here -- sampling 1 alpha when
|
||||
* texturing, using 1 as destination alpha factor in blending,
|
||||
* etc. However, when filtering with GL_CLAMP_TO_BORDER, the
|
||||
* alpha channel of the border color will also be clamped to
|
||||
* 1, when we actually want the border color we explicitly
|
||||
* specified. So, we have to store RGBA, and fill the alpha
|
||||
* channel with 1 when blending.
|
||||
*/
|
||||
format = GL_RGBA;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -524,6 +541,24 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
|
|||
return &surface->base;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_gl_surface_clear (cairo_gl_surface_t *surface)
|
||||
{
|
||||
cairo_gl_context_t *ctx;
|
||||
|
||||
ctx = _cairo_gl_context_acquire (surface->ctx);
|
||||
_cairo_gl_set_destination (surface);
|
||||
if (surface->base.content == CAIRO_CONTENT_COLOR)
|
||||
glClearColor (0.0, 0.0, 0.0, 1.0);
|
||||
else
|
||||
glClearColor (0.0, 0.0, 0.0, 0.0);
|
||||
glClear (GL_COLOR_BUFFER_BIT);
|
||||
_cairo_gl_context_release (ctx);
|
||||
|
||||
surface->base.is_clear = TRUE;
|
||||
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
cairo_gl_surface_create (cairo_gl_context_t *ctx,
|
||||
cairo_content_t content,
|
||||
|
|
@ -546,13 +581,7 @@ cairo_gl_surface_create (cairo_gl_context_t *ctx,
|
|||
return &surface->base;
|
||||
|
||||
/* Cairo surfaces start out initialized to transparent (black) */
|
||||
ctx = _cairo_gl_context_acquire (surface->ctx);
|
||||
_cairo_gl_set_destination (surface);
|
||||
glClearColor (0.0, 0.0, 0.0, 0.0);
|
||||
glClear (GL_COLOR_BUFFER_BIT);
|
||||
_cairo_gl_context_release (ctx);
|
||||
|
||||
surface->base.is_clear = TRUE;
|
||||
_cairo_gl_surface_clear (surface);
|
||||
|
||||
return &surface->base;
|
||||
}
|
||||
|
|
@ -689,6 +718,32 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
|
|||
|
||||
cairo_surface_destroy (&clone->base);
|
||||
|
||||
/* If we just treated some rgb-only data as rgba, then we have to
|
||||
* go back and fix up the alpha channel where we filled in this
|
||||
* texture data.
|
||||
*/
|
||||
if (!has_alpha) {
|
||||
cairo_rectangle_int_t rect;
|
||||
cairo_color_t color;
|
||||
|
||||
rect.x = dst_x;
|
||||
rect.y = dst_y;
|
||||
rect.width = width;
|
||||
rect.height = height;
|
||||
|
||||
color.red = 0.0;
|
||||
color.green = 0.0;
|
||||
color.blue = 0.0;
|
||||
color.alpha = 1.0;
|
||||
|
||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
|
||||
_cairo_gl_surface_fill_rectangles (dst,
|
||||
CAIRO_OPERATOR_SOURCE,
|
||||
&color,
|
||||
&rect, 1);
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -1122,7 +1177,7 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
|
|||
cairo_gl_composite_setup_t *setup)
|
||||
{
|
||||
cairo_surface_attributes_t *src_attributes;
|
||||
GLfloat constant_color[4] = {0.0, 0.0, 0.0, 1.0};
|
||||
GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
|
||||
|
||||
src_attributes = &setup->src.operand.texture.attributes;
|
||||
|
||||
|
|
@ -1134,7 +1189,7 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
|
|||
case OPERAND_TEXTURE:
|
||||
_cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex,
|
||||
src_attributes);
|
||||
/* Set up the constant color we use to set alpha to 1 if needed. */
|
||||
/* Set up the constant color we use to set color to 0 if needed. */
|
||||
glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
|
||||
/* Set up the combiner to just set color to the sampled texture. */
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||||
|
|
@ -1150,16 +1205,7 @@ _cairo_gl_set_src_operand (cairo_gl_context_t *ctx,
|
|||
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
|
||||
else
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
|
||||
/* Wire the src alpha to 1 if the surface doesn't have it.
|
||||
* We may have a teximage with alpha bits even though we didn't ask
|
||||
* for it and we don't pay attention to setting alpha to 1 in a dest
|
||||
* that has inadvertent alpha.
|
||||
*/
|
||||
if (setup->src.operand.texture.surface->base.content !=
|
||||
CAIRO_CONTENT_COLOR)
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
|
||||
else
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
||||
break;
|
||||
|
|
@ -1174,8 +1220,8 @@ static void
|
|||
_cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
|
||||
cairo_gl_composite_setup_t *setup)
|
||||
{
|
||||
GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
|
||||
cairo_surface_attributes_t *src_attributes;
|
||||
GLfloat constant_color[4];
|
||||
|
||||
src_attributes = &setup->src.operand.texture.attributes;
|
||||
|
||||
|
|
@ -1194,25 +1240,13 @@ _cairo_gl_set_src_alpha_operand (cairo_gl_context_t *ctx,
|
|||
constant_color[3] = 1.0;
|
||||
_cairo_gl_set_texture_surface (0, setup->src.operand.texture.tex,
|
||||
src_attributes);
|
||||
/* Set up the constant color we use to set alpha to 1 if needed. */
|
||||
glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
|
||||
/* Set up the combiner to just set color to the sampled texture. */
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
|
||||
|
||||
/* Wire the src alpha to 1 if the surface doesn't have it.
|
||||
* We may have a teximage with alpha bits even though we didn't ask
|
||||
* for it and we don't pay attention to setting alpha to 1 in a dest
|
||||
* that has inadvertent alpha.
|
||||
*/
|
||||
if (setup->src.operand.texture.surface->base.content != CAIRO_CONTENT_COLOR) {
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
|
||||
} else {
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
|
||||
}
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE0);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE0);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
||||
break;
|
||||
|
|
@ -1227,7 +1261,7 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
|
|||
cairo_gl_composite_setup_t *setup)
|
||||
{
|
||||
cairo_surface_attributes_t *mask_attributes;
|
||||
GLfloat constant_color[4] = {0.0, 0.0, 0.0, 1.0};
|
||||
GLfloat constant_color[4] = {0.0, 0.0, 0.0, 0.0};
|
||||
|
||||
mask_attributes = &setup->mask.operand.texture.attributes;
|
||||
|
||||
|
|
@ -1259,7 +1293,7 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
|
|||
case OPERAND_TEXTURE:
|
||||
_cairo_gl_set_texture_surface (1, setup->mask.operand.texture.tex,
|
||||
mask_attributes);
|
||||
/* Set up the constant color we use to set alpha to 1 if needed. */
|
||||
/* Set up the constant color we use to set color to 0 if needed. */
|
||||
glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant_color);
|
||||
|
||||
/* Force the mask color to 0 if the surface should be alpha-only.
|
||||
|
|
@ -1271,16 +1305,7 @@ _cairo_gl_set_component_alpha_mask_operand (cairo_gl_context_t *ctx,
|
|||
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE1);
|
||||
else
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_CONSTANT);
|
||||
/* Wire the mask alpha to 1 if the surface doesn't have it.
|
||||
* We may have a teximage with alpha bits even though we didn't ask
|
||||
* for it and we don't pay attention to setting alpha to 1 in a dest
|
||||
* that has inadvertent alpha.
|
||||
*/
|
||||
if (setup->mask.operand.texture.surface->base.content !=
|
||||
CAIRO_CONTENT_COLOR)
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE1);
|
||||
else
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_CONSTANT);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE1);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
||||
break;
|
||||
|
|
@ -2344,13 +2369,7 @@ _cairo_gl_surface_paint (void *abstract_surface,
|
|||
{
|
||||
/* simplify the common case of clearing the surface */
|
||||
if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) {
|
||||
cairo_gl_surface_t *surface = abstract_surface;
|
||||
cairo_gl_context_t *ctx;
|
||||
|
||||
ctx = _cairo_gl_context_acquire (surface->ctx);
|
||||
_cairo_gl_set_destination (surface);
|
||||
glClear (GL_COLOR_BUFFER_BIT);
|
||||
_cairo_gl_context_release (ctx);
|
||||
_cairo_gl_surface_clear (abstract_surface);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue