mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-05 20:28:02 +02:00
gl: Provide a shader implementation of repeat wrap modes
In OpenGL ES 2.0, repeat wrap modes (GL_REPEAT and GL_MIRRORED REPEAT) are only available for NPOT textures if the GL_OES_texture_npot is supported. This commit adds a shader implementation of these wrap modes for use by devices that do not support GL_OES_texture_npot.
This commit is contained in:
parent
82f69d1ef7
commit
6867383017
4 changed files with 90 additions and 21 deletions
|
|
@ -168,10 +168,16 @@ _cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
|
|||
wrap_mode = GL_CLAMP_TO_EDGE;
|
||||
break;
|
||||
case CAIRO_EXTEND_REPEAT:
|
||||
wrap_mode = GL_REPEAT;
|
||||
if (ctx->has_npot_repeat)
|
||||
wrap_mode = GL_REPEAT;
|
||||
else
|
||||
wrap_mode = GL_CLAMP_TO_EDGE;
|
||||
break;
|
||||
case CAIRO_EXTEND_REFLECT:
|
||||
wrap_mode = GL_MIRRORED_REPEAT;
|
||||
if (ctx->has_npot_repeat)
|
||||
wrap_mode = GL_MIRRORED_REPEAT;
|
||||
else
|
||||
wrap_mode = GL_CLAMP_TO_EDGE;
|
||||
break;
|
||||
default:
|
||||
wrap_mode = 0;
|
||||
|
|
|
|||
|
|
@ -187,18 +187,20 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
|
|||
|
||||
/* Check for required extensions */
|
||||
if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
|
||||
if (_cairo_gl_has_extension ("GL_ARB_texture_non_power_of_two"))
|
||||
if (_cairo_gl_has_extension ("GL_ARB_texture_non_power_of_two")) {
|
||||
ctx->tex_target = GL_TEXTURE_2D;
|
||||
else if (_cairo_gl_has_extension ("GL_ARB_texture_rectangle"))
|
||||
ctx->has_npot_repeat = TRUE;
|
||||
} else if (_cairo_gl_has_extension ("GL_ARB_texture_rectangle")) {
|
||||
ctx->tex_target = GL_TEXTURE_RECTANGLE;
|
||||
else
|
||||
ctx->has_npot_repeat = FALSE;
|
||||
} else
|
||||
return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ctx->tex_target = GL_TEXTURE_2D;
|
||||
if (_cairo_gl_has_extension ("GL_OES_texture_npot"))
|
||||
ctx->tex_target = GL_TEXTURE_2D;
|
||||
ctx->has_npot_repeat = TRUE;
|
||||
else
|
||||
return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
|
||||
ctx->has_npot_repeat = FALSE;
|
||||
}
|
||||
|
||||
if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP &&
|
||||
|
|
|
|||
|
|
@ -319,6 +319,7 @@ struct _cairo_gl_context {
|
|||
cairo_gl_flavor_t gl_flavor;
|
||||
cairo_bool_t has_map_buffer;
|
||||
cairo_bool_t has_packed_depth_stencil;
|
||||
cairo_bool_t has_npot_repeat;
|
||||
|
||||
void (*acquire) (void *ctx);
|
||||
void (*release) (void *ctx);
|
||||
|
|
|
|||
|
|
@ -319,8 +319,10 @@ typedef struct _cairo_shader_cache_entry {
|
|||
cairo_gl_shader_in_t in;
|
||||
GLint src_gl_filter;
|
||||
cairo_bool_t src_border_fade;
|
||||
cairo_extend_t src_extend;
|
||||
GLint mask_gl_filter;
|
||||
cairo_bool_t mask_border_fade;
|
||||
cairo_extend_t mask_extend;
|
||||
|
||||
cairo_gl_context_t *ctx; /* XXX: needed to destroy the program */
|
||||
cairo_gl_shader_t shader;
|
||||
|
|
@ -331,12 +333,16 @@ _cairo_gl_shader_cache_equal_desktop (const void *key_a, const void *key_b)
|
|||
{
|
||||
const cairo_shader_cache_entry_t *a = key_a;
|
||||
const cairo_shader_cache_entry_t *b = key_b;
|
||||
cairo_bool_t both_have_npot_repeat =
|
||||
a->ctx->has_npot_repeat && b->ctx->has_npot_repeat;
|
||||
|
||||
return a->src == b->src &&
|
||||
a->mask == b->mask &&
|
||||
a->dest == b->dest &&
|
||||
a->use_coverage == b->use_coverage &&
|
||||
a->in == b->in;
|
||||
a->in == b->in &&
|
||||
(both_have_npot_repeat || a->src_extend == b->src_extend) &&
|
||||
(both_have_npot_repeat || a->mask_extend == b->mask_extend);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -349,6 +355,8 @@ _cairo_gl_shader_cache_equal_gles2 (const void *key_a, const void *key_b)
|
|||
{
|
||||
const cairo_shader_cache_entry_t *a = key_a;
|
||||
const cairo_shader_cache_entry_t *b = key_b;
|
||||
cairo_bool_t both_have_npot_repeat =
|
||||
a->ctx->has_npot_repeat && b->ctx->has_npot_repeat;
|
||||
|
||||
return a->src == b->src &&
|
||||
a->mask == b->mask &&
|
||||
|
|
@ -357,8 +365,10 @@ _cairo_gl_shader_cache_equal_gles2 (const void *key_a, const void *key_b)
|
|||
a->in == b->in &&
|
||||
a->src_gl_filter == b->src_gl_filter &&
|
||||
a->src_border_fade == b->src_border_fade &&
|
||||
(both_have_npot_repeat || a->src_extend == b->src_extend) &&
|
||||
a->mask_gl_filter == b->mask_gl_filter &&
|
||||
a->mask_border_fade == b->mask_border_fade;
|
||||
a->mask_border_fade == b->mask_border_fade &&
|
||||
(both_have_npot_repeat || a->mask_extend == b->mask_extend);
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
|
|
@ -642,9 +652,9 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
|
|||
else
|
||||
{
|
||||
_cairo_output_stream_printf (stream,
|
||||
" return texture2D%s (%s_sampler, %s_texcoords);\n"
|
||||
" return texture2D%s (%s_sampler, %s_wrap (%s_texcoords));\n"
|
||||
"}\n",
|
||||
rectstr, namestr, namestr);
|
||||
rectstr, namestr, namestr, namestr);
|
||||
}
|
||||
break;
|
||||
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
|
||||
|
|
@ -669,9 +679,9 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
|
|||
else
|
||||
{
|
||||
_cairo_output_stream_printf (stream,
|
||||
" return texture2D%s (%s_sampler, vec2 (%s_texcoords.x, 0.5));\n"
|
||||
" return texture2D%s (%s_sampler, %s_wrap (vec2 (%s_texcoords.x, 0.5)));\n"
|
||||
"}\n",
|
||||
rectstr, namestr, namestr);
|
||||
rectstr, namestr, namestr, namestr);
|
||||
}
|
||||
break;
|
||||
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
|
||||
|
|
@ -706,9 +716,10 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
|
|||
else
|
||||
{
|
||||
_cairo_output_stream_printf (stream,
|
||||
" return mix (vec4 (0.0), texture2D%s (%s_sampler, vec2(t, 0.5)), is_valid);\n"
|
||||
" vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2 (t, 0.5)));\n"
|
||||
" return mix (vec4 (0.0), texel, is_valid);\n"
|
||||
"}\n",
|
||||
rectstr, namestr);
|
||||
rectstr, namestr, namestr);
|
||||
}
|
||||
break;
|
||||
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
|
||||
|
|
@ -750,9 +761,10 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
|
|||
else
|
||||
{
|
||||
_cairo_output_stream_printf (stream,
|
||||
" return mix (vec4 (0.0), texture2D%s (%s_sampler, vec2 (upper_t, 0.5)), has_color);\n"
|
||||
" vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n"
|
||||
" return mix (vec4 (0.0), texel, has_color);\n"
|
||||
"}\n",
|
||||
rectstr, namestr);
|
||||
rectstr, namestr, namestr);
|
||||
}
|
||||
break;
|
||||
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
|
||||
|
|
@ -778,11 +790,12 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
|
|||
" float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n"
|
||||
" \n"
|
||||
" float upper_t = mix (t.y, t.x, is_valid.x);\n"
|
||||
" return mix (vec4 (0.0), texture2D%s (%s_sampler, vec2 (upper_t, 0.5)), has_color);\n"
|
||||
" vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n"
|
||||
" return mix (vec4 (0.0), texel, has_color);\n"
|
||||
"}\n",
|
||||
namestr, rectstr, namestr, namestr, namestr, namestr,
|
||||
namestr, namestr, namestr, namestr, namestr,
|
||||
namestr, namestr, namestr, rectstr, namestr);
|
||||
namestr, namestr, namestr, rectstr, namestr, namestr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -838,6 +851,47 @@ _cairo_gl_shader_emit_border_fade (cairo_output_stream_t *stream,
|
|||
_cairo_output_stream_printf (stream, "}\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Emits the wrap function used by an operand.
|
||||
*
|
||||
* In OpenGL ES 2.0, repeat wrap modes (GL_REPEAT and GL_MIRRORED REPEAT) are
|
||||
* only available for NPOT textures if the GL_OES_texture_npot is supported.
|
||||
* If GL_OES_texture_npot is not supported, we need to implement the wrapping
|
||||
* functionality in the shader.
|
||||
*/
|
||||
static void
|
||||
_cairo_gl_shader_emit_wrap (cairo_gl_context_t *ctx,
|
||||
cairo_output_stream_t *stream,
|
||||
cairo_gl_operand_t *operand,
|
||||
cairo_gl_tex_t name)
|
||||
{
|
||||
const char *namestr = operand_names[name];
|
||||
cairo_extend_t extend = _cairo_gl_operand_get_extend (operand);
|
||||
|
||||
_cairo_output_stream_printf (stream,
|
||||
"vec2 %s_wrap(vec2 coords)\n"
|
||||
"{\n",
|
||||
namestr);
|
||||
|
||||
if (! ctx->has_npot_repeat &&
|
||||
(extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT))
|
||||
{
|
||||
if (extend == CAIRO_EXTEND_REPEAT) {
|
||||
_cairo_output_stream_printf (stream,
|
||||
" return fract(coords);\n");
|
||||
} else { /* CAIRO_EXTEND_REFLECT */
|
||||
_cairo_output_stream_printf (stream,
|
||||
" return mix(fract(coords), 1.0 - fract(coords), floor(mod(coords, 2.0)));\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_cairo_output_stream_printf (stream, " return coords;\n");
|
||||
}
|
||||
|
||||
_cairo_output_stream_printf (stream, "}\n");
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
|
||||
cairo_gl_shader_in_t in,
|
||||
|
|
@ -858,6 +912,9 @@ cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
|
|||
"precision mediump float;\n"
|
||||
"#endif\n");
|
||||
|
||||
_cairo_gl_shader_emit_wrap (ctx, stream, src, CAIRO_GL_TEX_SOURCE);
|
||||
_cairo_gl_shader_emit_wrap (ctx, stream, mask, CAIRO_GL_TEX_MASK);
|
||||
|
||||
if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES) {
|
||||
if (_cairo_gl_shader_needs_border_fade (src))
|
||||
_cairo_gl_shader_emit_border_fade (stream, src, CAIRO_GL_TEX_SOURCE);
|
||||
|
|
@ -1065,6 +1122,7 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
|
|||
char *fs_source;
|
||||
cairo_status_t status;
|
||||
|
||||
lookup.ctx = ctx;
|
||||
lookup.src = source->type;
|
||||
lookup.mask = mask->type;
|
||||
lookup.dest = CAIRO_GL_OPERAND_NONE;
|
||||
|
|
@ -1072,8 +1130,10 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
|
|||
lookup.in = in;
|
||||
lookup.src_gl_filter = _cairo_gl_operand_get_gl_filter (source);
|
||||
lookup.src_border_fade = _cairo_gl_shader_needs_border_fade (source);
|
||||
lookup.src_extend = _cairo_gl_operand_get_extend (source);
|
||||
lookup.mask_gl_filter = _cairo_gl_operand_get_gl_filter (mask);
|
||||
lookup.mask_border_fade = _cairo_gl_shader_needs_border_fade (mask);
|
||||
lookup.mask_extend = _cairo_gl_operand_get_extend (mask);
|
||||
lookup.base.hash = _cairo_gl_shader_cache_hash (&lookup);
|
||||
lookup.base.size = 1;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue