static cairo_status_t
_cairo_gl_shader_compile (cairo_gl_context_t *ctx,
			  cairo_gl_shader_t *shader,
			  cairo_gl_var_type_t src,
			  cairo_gl_var_type_t mask,
			  cairo_bool_t use_coverage,
			  const char *fragment_text)
{
    unsigned int vertex_shader;
    cairo_status_t status;

    assert (shader->program == 0);

    vertex_shader = cairo_gl_var_type_hash (src, mask, use_coverage,
					    CAIRO_GL_VAR_NONE);
    if (ctx->vertex_shaders[vertex_shader] == 0) {
	char *source;

	status = cairo_gl_shader_get_vertex_source (src,
						    mask,
						    use_coverage,
						    CAIRO_GL_VAR_NONE,
						    &source);
        if (unlikely (status))
            goto FAILURE;

	ctx->shader_impl->compile_shader (ctx, &ctx->vertex_shaders[vertex_shader],
					  GL_VERTEX_SHADER,
					  source);
        free (source);
    }

    ctx->shader_impl->compile_shader (ctx, &shader->fragment_shader,
				      GL_FRAGMENT_SHADER,
				      fragment_text);

    ctx->shader_impl->link_shader (ctx, &shader->program,
				   ctx->vertex_shaders[vertex_shader],
				   shader->fragment_shader);

    return CAIRO_STATUS_SUCCESS;

 FAILURE:
    _cairo_gl_shader_fini (ctx, shader);
    shader->fragment_shader = 0;
    shader->program = 0;

    return status;
}
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.vertex = cairo_gl_var_type_hash (cairo_gl_operand_get_var_type (source),
					    cairo_gl_operand_get_var_type (mask),
					    use_coverage,
					    CAIRO_GL_VAR_NONE);

    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_and_link (ctx,
						&entry->shader,
						cairo_gl_operand_get_var_type (source),
						cairo_gl_operand_get_var_type (mask),
						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;
}
static cairo_status_t
_cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx,
				   cairo_gl_shader_t *shader,
				   cairo_gl_var_type_t src,
				   cairo_gl_var_type_t mask,
				   cairo_bool_t use_coverage,
				   const char *fragment_text)
{
    cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
    unsigned int vertex_shader;
    cairo_status_t status;
    int i;

    assert (shader->program == 0);

    vertex_shader = cairo_gl_var_type_hash (src, mask, use_coverage,
					    CAIRO_GL_VAR_NONE);
    if (ctx->vertex_shaders[vertex_shader] == 0) {
	char *source;

	status = cairo_gl_shader_get_vertex_source (src,
						    mask,
						    use_coverage,
						    CAIRO_GL_VAR_NONE,
						    &source);
	if (unlikely (status))
	    goto FAILURE;

	compile_shader (ctx, &ctx->vertex_shaders[vertex_shader],
			GL_VERTEX_SHADER, source);
	free (source);
    }

    compile_shader (ctx, &shader->fragment_shader,
		    GL_FRAGMENT_SHADER, fragment_text);

    link_shader_program (ctx, &shader->program,
			 ctx->vertex_shaders[vertex_shader],
			 shader->fragment_shader);

    shader->mvp_location =
	dispatch->GetUniformLocation (shader->program,
				      "ModelViewProjectionMatrix");

    for (i = 0; i < 2; i++) {
	shader->constant_location[i] =
	    _cairo_gl_get_op_uniform_location (ctx, shader, i, "constant");
	shader->a_location[i] =
	    _cairo_gl_get_op_uniform_location (ctx, shader, i, "a");
	shader->circle_d_location[i] =
	    _cairo_gl_get_op_uniform_location (ctx, shader, i, "circle_d");
	shader->radius_0_location[i] =
	    _cairo_gl_get_op_uniform_location (ctx, shader, i, "radius_0");
	shader->texdims_location[i] =
	    _cairo_gl_get_op_uniform_location (ctx, shader, i, "texdims");
	shader->texgen_location[i] =
	    _cairo_gl_get_op_uniform_location (ctx, shader, i, "texgen");
    }

    return CAIRO_STATUS_SUCCESS;

 FAILURE:
    _cairo_gl_shader_fini (ctx, shader);
    shader->fragment_shader = 0;
    shader->program = 0;

    return status;
}
Exemple #4
0
static cairo_status_t
_cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx,
				   cairo_gl_shader_t *shader,
				   cairo_gl_operand_t *src,
				   cairo_gl_operand_t *mask,
				   cairo_bool_t use_coverage,
				   const char *fragment_text)
{
    unsigned int vertex_shader;
    cairo_status_t status;
    cairo_gl_var_type_t src_type;
    cairo_gl_var_type_t mask_type;
    cairo_extend_t src_atlas_extend = CAIRO_EXTEND_NONE;
    cairo_extend_t mask_atlas_extend = CAIRO_EXTEND_NONE;
    cairo_bool_t src_use_atlas = FALSE;
    cairo_bool_t mask_use_atlas = FALSE;

    assert (shader->program == 0);

    if (src != NULL) {
      src_type = cairo_gl_operand_get_var_type (src->type,
                                                src->use_color_attribute);
      src_atlas_extend = _cairo_gl_operand_get_atlas_extend (src);
      src_use_atlas = _cairo_gl_operand_get_use_atlas (src);
    }
    else
      src_type = CAIRO_GL_VAR_NONE;

    if (mask != NULL) {
      mask_type = cairo_gl_operand_get_var_type (mask->type,
                                                 mask->use_color_attribute);
      mask_atlas_extend = _cairo_gl_operand_get_atlas_extend (mask);
      mask_use_atlas = _cairo_gl_operand_get_use_atlas (mask);
    }
    else
      mask_type = CAIRO_GL_VAR_NONE;

    vertex_shader = cairo_gl_var_type_hash (src_type, mask_type,
					    src_atlas_extend,
					    mask_atlas_extend,
					    src_use_atlas,
					    mask_use_atlas,
					    use_coverage,
					    CAIRO_GL_VAR_NONE);
    if (ctx->vertex_shaders[vertex_shader] == 0) {
	char *source;

	status = cairo_gl_shader_get_vertex_source (src_type,
						    mask_type,
						    src_use_atlas,
						    mask_use_atlas,
						    use_coverage,
						    CAIRO_GL_VAR_NONE,
						    &source);
        if (unlikely (status))
            goto FAILURE;

	compile_shader (ctx, &ctx->vertex_shaders[vertex_shader],
			GL_VERTEX_SHADER, source);
        free (source);
    }

    compile_shader (ctx, &shader->fragment_shader,
		    GL_FRAGMENT_SHADER, fragment_text);

    link_shader_program (ctx, &shader->program,
			 ctx->vertex_shaders[vertex_shader],
			 shader->fragment_shader);

    return CAIRO_STATUS_SUCCESS;

 FAILURE:
    _cairo_gl_shader_fini (ctx, shader);
    shader->fragment_shader = 0;
    shader->program = 0;

    return status;
}