示例#1
0
/*
 * Emits the border fade functions used by an operand.
 *
 * If bilinear filtering is used, the emitted function performs a linear
 * fade to transparency effect in the intervals [-1/2n, 1/2n] and
 * [1 - 1/2n, 1 + 1/2n] (n: texture size).
 *
 * If nearest filtering is used, the emitted function just returns
 * 0.0 for all values outside [0, 1).
 */
static void
_cairo_gl_shader_emit_border_fade (cairo_output_stream_t *stream,
				   cairo_gl_operand_t *operand,
				   cairo_gl_tex_t name)
{
    const char *namestr = operand_names[name];
    GLint gl_filter = _cairo_gl_operand_get_gl_filter (operand);

    /* 2D version */
    _cairo_output_stream_printf (stream,
	"vec2 %s_border_fade (vec2 coords, vec2 dims)\n"
	"{\n",
	namestr);

    if (gl_filter == GL_LINEAR)
	_cairo_output_stream_printf (stream,
	    "    return clamp(-abs(dims * (coords - 0.5)) + (dims + vec2(1.0)) * 0.5, 0.0, 1.0);\n");
    else
	_cairo_output_stream_printf (stream,
	    "    bvec2 in_tex1 = greaterThanEqual (coords, vec2 (0.0));\n"
	    "    bvec2 in_tex2 = lessThan (coords, vec2 (1.0));\n"
	    "    return vec2 (float (all (in_tex1) && all (in_tex2)));\n");

    _cairo_output_stream_printf (stream, "}\n");

    /* 1D version */
    _cairo_output_stream_printf (stream,
	"float %s_border_fade (float x, float dim)\n"
	"{\n",
	namestr);
    if (gl_filter == GL_LINEAR)
	_cairo_output_stream_printf (stream,
	    "    return clamp(-abs(dim * (x - 0.5)) + (dim + 1.0) * 0.5, 0.0, 1.0);\n");
    else
	_cairo_output_stream_printf (stream,
	    "    bool in_tex = x >= 0.0 && x < 1.0;\n"
	    "    return float (in_tex);\n");

    _cairo_output_stream_printf (stream, "}\n");
}
示例#2
0
cairo_status_t
_cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
                              cairo_gl_operand_t *source,
                              cairo_gl_operand_t *mask,
			      cairo_bool_t use_coverage,
                              cairo_gl_shader_in_t in,
                              cairo_gl_shader_t **shader)
{
    cairo_shader_cache_entry_t lookup, *entry;
    char *fs_source;
    cairo_status_t status;

    lookup.ctx = ctx;
    lookup.src = source->type;
    lookup.mask = mask->type;
    lookup.dest = CAIRO_GL_OPERAND_NONE;
    lookup.use_coverage = use_coverage;
    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;

    entry = _cairo_cache_lookup (&ctx->shaders, &lookup.base);
    if (entry) {
        assert (entry->shader.program);
        *shader = &entry->shader;
	return CAIRO_STATUS_SUCCESS;
    }

    status = cairo_gl_shader_get_fragment_source (ctx,
						  in,
						  source,
						  mask,
						  use_coverage,
						  CAIRO_GL_OPERAND_NONE,
						  &fs_source);
    if (unlikely (status))
	return status;

    entry = malloc (sizeof (cairo_shader_cache_entry_t));
    if (unlikely (entry == NULL)) {
        free (fs_source);
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }

    memcpy (entry, &lookup, sizeof (cairo_shader_cache_entry_t));

    entry->ctx = ctx;
    _cairo_gl_shader_init (&entry->shader);
    status = _cairo_gl_shader_compile (ctx,
				       &entry->shader,
				       cairo_gl_operand_get_var_type (source->type),
				       cairo_gl_operand_get_var_type (mask->type),
				       use_coverage,
				       fs_source);
    free (fs_source);

    if (unlikely (status)) {
	free (entry);
	return status;
    }

    _cairo_gl_shader_set_samplers (ctx, &entry->shader);

    status = _cairo_cache_insert (&ctx->shaders, &entry->base);
    if (unlikely (status)) {
	_cairo_gl_shader_fini (ctx, &entry->shader);
	free (entry);
	return status;
    }

    *shader = &entry->shader;

    return CAIRO_STATUS_SUCCESS;
}
示例#3
0
void
_cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
                                  cairo_gl_operand_t *operand,
                                  cairo_gl_tex_t      tex_unit)
{
    const cairo_matrix_t *texgen = NULL;

    switch (operand->type) {
    default:
    case CAIRO_GL_OPERAND_COUNT:
        ASSERT_NOT_REACHED;
    case CAIRO_GL_OPERAND_NONE:
	return;

    case CAIRO_GL_OPERAND_CONSTANT:
	_cairo_gl_shader_bind_vec4 (ctx,
                                    ctx->current_shader->constant_location[tex_unit],
                                    operand->constant.color[0],
                                    operand->constant.color[1],
                                    operand->constant.color[2],
                                    operand->constant.color[3]);
	return;

    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
	_cairo_gl_shader_bind_float  (ctx,
				      ctx->current_shader->a_location[tex_unit],
				      operand->gradient.a);
	/* fall through */
    case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
	_cairo_gl_shader_bind_vec3   (ctx,
				      ctx->current_shader->circle_d_location[tex_unit],
				      operand->gradient.circle_d.center.x,
				      operand->gradient.circle_d.center.y,
				      operand->gradient.circle_d.radius);
	_cairo_gl_shader_bind_float  (ctx,
				      ctx->current_shader->radius_0_location[tex_unit],
				      operand->gradient.radius_0);
        /* fall through */
    case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
    case CAIRO_GL_OPERAND_TEXTURE:
	/*
	 * For GLES2 we use shaders to implement GL_CLAMP_TO_BORDER (used
	 * with CAIRO_EXTEND_NONE). When bilinear filtering is enabled,
	 * these shaders need the texture dimensions for their calculations.
	 */
	if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES &&
	    _cairo_gl_operand_get_extend (operand) == CAIRO_EXTEND_NONE &&
	    _cairo_gl_operand_get_gl_filter (operand) == GL_LINEAR)
	{
	    float width, height;
	    if (operand->type == CAIRO_GL_OPERAND_TEXTURE) {
		width = operand->texture.surface->width;
		height = operand->texture.surface->height;
	    }
	    else {
		width = operand->gradient.gradient->cache_entry.size,
		height = 1;
	    }
	    _cairo_gl_shader_bind_vec2 (ctx,
					ctx->current_shader->texdims_location[tex_unit],
					width, height);
	}
	break;
    }

    if (operand->type == CAIRO_GL_OPERAND_TEXTURE) {
	    if (operand->texture.texgen)
		    texgen = &operand->texture.attributes.matrix;
    } else {
	    if (operand->gradient.texgen)
		    texgen = &operand->gradient.m;
    }
    if (texgen) {
	    _cairo_gl_shader_bind_matrix(ctx,
					 ctx->current_shader->texgen_location[tex_unit],
					 texgen);
    }
}