690 lines
22 KiB
C
690 lines
22 KiB
C
/*
|
|
* Copyright © 2014 Keith Packard
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
* the above copyright notice appear in all copies and that both that copyright
|
|
* notice and this permission notice appear in supporting documentation, and
|
|
* that the name of the copyright holders not be used in advertising or
|
|
* publicity pertaining to distribution of the software without specific,
|
|
* written prior permission. The copyright holders make no representations
|
|
* about the suitability of this software for any purpose. It is provided "as
|
|
* is" without express or implied warranty.
|
|
*
|
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
* OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include "glamor_priv.h"
|
|
#include "glamor_transform.h"
|
|
#include "glamor_program.h"
|
|
|
|
static Bool
|
|
use_solid(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
|
|
{
|
|
return glamor_set_solid(pixmap, gc, TRUE, prog->fg_uniform);
|
|
}
|
|
|
|
const glamor_facet glamor_fill_solid = {
|
|
.name = "solid",
|
|
.fs_exec = " gl_FragColor = fg;\n",
|
|
.locations = glamor_program_location_fg,
|
|
.use = use_solid,
|
|
};
|
|
|
|
static Bool
|
|
use_tile(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
|
|
{
|
|
return glamor_set_tiled(pixmap, gc, prog->fill_offset_uniform, prog->fill_size_inv_uniform);
|
|
}
|
|
|
|
static const glamor_facet glamor_fill_tile = {
|
|
.name = "tile",
|
|
.vs_exec = " fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
|
|
.fs_exec = " gl_FragColor = texture2D(sampler, fill_pos);\n",
|
|
.locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
|
|
.use = use_tile,
|
|
};
|
|
|
|
static Bool
|
|
use_stipple(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
|
|
{
|
|
return glamor_set_stippled(pixmap, gc, prog->fg_uniform,
|
|
prog->fill_offset_uniform,
|
|
prog->fill_size_inv_uniform);
|
|
}
|
|
|
|
static const glamor_facet glamor_fill_stipple = {
|
|
.name = "stipple",
|
|
.vs_exec = " fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
|
|
.fs_exec = (" float a = texture2D(sampler, fill_pos).w;\n"
|
|
" if (a == 0.0)\n"
|
|
" discard;\n"
|
|
" gl_FragColor = fg;\n"),
|
|
.locations = glamor_program_location_fg | glamor_program_location_fillsamp | glamor_program_location_fillpos,
|
|
.use = use_stipple,
|
|
};
|
|
|
|
static Bool
|
|
use_opaque_stipple(PixmapPtr pixmap, GCPtr gc, glamor_program *prog, void *arg)
|
|
{
|
|
if (!use_stipple(pixmap, gc, prog, arg))
|
|
return FALSE;
|
|
glamor_set_color(pixmap, gc->bgPixel, prog->bg_uniform);
|
|
return TRUE;
|
|
}
|
|
|
|
static const glamor_facet glamor_fill_opaque_stipple = {
|
|
.name = "opaque_stipple",
|
|
.vs_exec = " fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
|
|
.fs_exec = (" float a = texture2D(sampler, fill_pos).w;\n"
|
|
" if (a == 0.0)\n"
|
|
" gl_FragColor = bg;\n"
|
|
" else\n"
|
|
" gl_FragColor = fg;\n"),
|
|
.locations = glamor_program_location_fg | glamor_program_location_bg | glamor_program_location_fillsamp | glamor_program_location_fillpos,
|
|
.use = use_opaque_stipple
|
|
};
|
|
|
|
static const glamor_facet *glamor_facet_fill[4] = {
|
|
&glamor_fill_solid,
|
|
&glamor_fill_tile,
|
|
&glamor_fill_stipple,
|
|
&glamor_fill_opaque_stipple,
|
|
};
|
|
|
|
typedef struct {
|
|
glamor_program_location location;
|
|
const char *vs_vars;
|
|
const char *fs_vars;
|
|
} glamor_location_var;
|
|
|
|
static glamor_location_var location_vars[] = {
|
|
{
|
|
.location = glamor_program_location_fg,
|
|
.fs_vars = "uniform vec4 fg;\n"
|
|
},
|
|
{
|
|
.location = glamor_program_location_bg,
|
|
.fs_vars = "uniform vec4 bg;\n"
|
|
},
|
|
{
|
|
.location = glamor_program_location_fillsamp,
|
|
.fs_vars = "uniform sampler2D sampler;\n"
|
|
},
|
|
{
|
|
.location = glamor_program_location_fillpos,
|
|
.vs_vars = ("uniform vec2 fill_offset;\n"
|
|
"uniform vec2 fill_size_inv;\n"
|
|
"varying vec2 fill_pos;\n"),
|
|
.fs_vars = ("varying vec2 fill_pos;\n")
|
|
},
|
|
{
|
|
.location = glamor_program_location_font,
|
|
.fs_vars = "uniform usampler2D font;\n",
|
|
},
|
|
{
|
|
.location = glamor_program_location_bitplane,
|
|
.fs_vars = ("uniform uvec4 bitplane;\n"
|
|
"uniform vec4 bitmul;\n"),
|
|
},
|
|
{
|
|
.location = glamor_program_location_dash,
|
|
.vs_vars = "uniform float dash_length;\n",
|
|
.fs_vars = "uniform sampler2D dash;\n",
|
|
},
|
|
{
|
|
.location = glamor_program_location_atlas,
|
|
.fs_vars = "uniform sampler2D atlas;\n",
|
|
},
|
|
};
|
|
|
|
static char *
|
|
add_var(char *cur, const char *add)
|
|
{
|
|
char *new;
|
|
|
|
if (!add)
|
|
return cur;
|
|
|
|
new = realloc(cur, strlen(cur) + strlen(add) + 1);
|
|
if (!new) {
|
|
free(cur);
|
|
return NULL;
|
|
}
|
|
strcat(new, add);
|
|
return new;
|
|
}
|
|
|
|
static char *
|
|
vs_location_vars(glamor_program_location locations)
|
|
{
|
|
int l;
|
|
char *vars = strdup("");
|
|
|
|
for (l = 0; vars && l < ARRAY_SIZE(location_vars); l++)
|
|
if (locations & location_vars[l].location)
|
|
vars = add_var(vars, location_vars[l].vs_vars);
|
|
return vars;
|
|
}
|
|
|
|
static char *
|
|
fs_location_vars(glamor_program_location locations)
|
|
{
|
|
int l;
|
|
char *vars = strdup("");
|
|
|
|
for (l = 0; vars && l < ARRAY_SIZE(location_vars); l++)
|
|
if (locations & location_vars[l].location)
|
|
vars = add_var(vars, location_vars[l].fs_vars);
|
|
return vars;
|
|
}
|
|
|
|
static const char vs_template[] =
|
|
"%s" /* version */
|
|
"%s" /* defines */
|
|
"%s" /* prim vs_vars */
|
|
"%s" /* fill vs_vars */
|
|
"%s" /* location vs_vars */
|
|
GLAMOR_DECLARE_MATRIX
|
|
"void main() {\n"
|
|
"%s" /* prim vs_exec, outputs 'pos' and gl_Position */
|
|
"%s" /* fill vs_exec */
|
|
"}\n";
|
|
|
|
static const char fs_template[] =
|
|
"%s" /* version */
|
|
GLAMOR_DEFAULT_PRECISION
|
|
"%s" /* defines */
|
|
"%s" /* prim fs_vars */
|
|
"%s" /* fill fs_vars */
|
|
"%s" /* location fs_vars */
|
|
"void main() {\n"
|
|
"%s" /* prim fs_exec */
|
|
"%s" /* fill fs_exec */
|
|
"%s" /* combine */
|
|
"}\n";
|
|
|
|
static const char *
|
|
str(const char *s)
|
|
{
|
|
if (!s)
|
|
return "";
|
|
return s;
|
|
}
|
|
|
|
static const glamor_facet facet_null_fill = {
|
|
.name = ""
|
|
};
|
|
|
|
#define DBG 0
|
|
|
|
static GLint
|
|
glamor_get_uniform(glamor_program *prog,
|
|
glamor_program_location location,
|
|
const char *name)
|
|
{
|
|
GLint uniform;
|
|
if (location && (prog->locations & location) == 0)
|
|
return -2;
|
|
uniform = glGetUniformLocation(prog->prog, name);
|
|
#if DBG
|
|
ErrorF("%s uniform %d\n", name, uniform);
|
|
#endif
|
|
return uniform;
|
|
}
|
|
|
|
Bool
|
|
glamor_build_program(ScreenPtr screen,
|
|
glamor_program *prog,
|
|
const glamor_facet *prim,
|
|
const glamor_facet *fill,
|
|
const char *combine,
|
|
const char *defines)
|
|
{
|
|
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
|
|
|
|
glamor_program_location locations = prim->locations;
|
|
glamor_program_flag flags = prim->flags;
|
|
|
|
int version = prim->version;
|
|
char *version_string = NULL;
|
|
|
|
char *fs_vars = NULL;
|
|
char *vs_vars = NULL;
|
|
|
|
char *vs_prog_string;
|
|
char *fs_prog_string;
|
|
|
|
GLint fs_prog, vs_prog;
|
|
|
|
if (!fill)
|
|
fill = &facet_null_fill;
|
|
|
|
locations |= fill->locations;
|
|
flags |= fill->flags;
|
|
version = MAX(version, fill->version);
|
|
|
|
if (version > glamor_priv->glsl_version)
|
|
goto fail;
|
|
|
|
vs_vars = vs_location_vars(locations);
|
|
fs_vars = fs_location_vars(locations);
|
|
|
|
if (!vs_vars)
|
|
goto fail;
|
|
if (!fs_vars)
|
|
goto fail;
|
|
|
|
if (version) {
|
|
if (asprintf(&version_string, "#version %d\n", version) < 0)
|
|
version_string = NULL;
|
|
if (!version_string)
|
|
goto fail;
|
|
}
|
|
|
|
if (asprintf(&vs_prog_string,
|
|
vs_template,
|
|
str(version_string),
|
|
str(defines),
|
|
str(prim->vs_vars),
|
|
str(fill->vs_vars),
|
|
vs_vars,
|
|
str(prim->vs_exec),
|
|
str(fill->vs_exec)) < 0)
|
|
vs_prog_string = NULL;
|
|
|
|
if (asprintf(&fs_prog_string,
|
|
fs_template,
|
|
str(version_string),
|
|
str(defines),
|
|
str(prim->fs_vars),
|
|
str(fill->fs_vars),
|
|
fs_vars,
|
|
str(prim->fs_exec),
|
|
str(fill->fs_exec),
|
|
str(combine)) < 0)
|
|
fs_prog_string = NULL;
|
|
|
|
if (!vs_prog_string || !fs_prog_string)
|
|
goto fail;
|
|
|
|
prog->prog = glCreateProgram();
|
|
#if DBG
|
|
ErrorF("\n\tProgram %d for %s %s\n\tVertex shader:\n\n\t================\n%s\n\n\tFragment Shader:\n\n%s\t================\n",
|
|
prog->prog, prim->name, fill->name, vs_prog_string, fs_prog_string);
|
|
#endif
|
|
|
|
prog->flags = flags;
|
|
prog->locations = locations;
|
|
prog->prim_use = prim->use;
|
|
prog->prim_use_render = prim->use_render;
|
|
prog->fill_use = fill->use;
|
|
prog->fill_use_render = fill->use_render;
|
|
|
|
vs_prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_prog_string);
|
|
fs_prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_prog_string);
|
|
free(vs_prog_string);
|
|
free(fs_prog_string);
|
|
glAttachShader(prog->prog, vs_prog);
|
|
glDeleteShader(vs_prog);
|
|
glAttachShader(prog->prog, fs_prog);
|
|
glDeleteShader(fs_prog);
|
|
glBindAttribLocation(prog->prog, GLAMOR_VERTEX_POS, "primitive");
|
|
|
|
if (prim->source_name) {
|
|
#if DBG
|
|
ErrorF("Bind GLAMOR_VERTEX_SOURCE to %s\n", prim->source_name);
|
|
#endif
|
|
glBindAttribLocation(prog->prog, GLAMOR_VERTEX_SOURCE, prim->source_name);
|
|
}
|
|
if (prog->alpha == glamor_program_alpha_dual_blend) {
|
|
glBindFragDataLocationIndexed(prog->prog, 0, 0, "color0");
|
|
glBindFragDataLocationIndexed(prog->prog, 0, 1, "color1");
|
|
}
|
|
|
|
glamor_link_glsl_prog(screen, prog->prog, "%s_%s", prim->name, fill->name);
|
|
|
|
prog->matrix_uniform = glamor_get_uniform(prog, glamor_program_location_none, "v_matrix");
|
|
prog->fg_uniform = glamor_get_uniform(prog, glamor_program_location_fg, "fg");
|
|
prog->bg_uniform = glamor_get_uniform(prog, glamor_program_location_bg, "bg");
|
|
prog->fill_offset_uniform = glamor_get_uniform(prog, glamor_program_location_fillpos, "fill_offset");
|
|
prog->fill_size_inv_uniform = glamor_get_uniform(prog, glamor_program_location_fillpos, "fill_size_inv");
|
|
prog->font_uniform = glamor_get_uniform(prog, glamor_program_location_font, "font");
|
|
prog->bitplane_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitplane");
|
|
prog->bitmul_uniform = glamor_get_uniform(prog, glamor_program_location_bitplane, "bitmul");
|
|
prog->dash_uniform = glamor_get_uniform(prog, glamor_program_location_dash, "dash");
|
|
prog->dash_length_uniform = glamor_get_uniform(prog, glamor_program_location_dash, "dash_length");
|
|
prog->atlas_uniform = glamor_get_uniform(prog, glamor_program_location_atlas, "atlas");
|
|
|
|
free(version_string);
|
|
free(fs_vars);
|
|
free(vs_vars);
|
|
return TRUE;
|
|
fail:
|
|
prog->failed = 1;
|
|
if (prog->prog) {
|
|
glDeleteProgram(prog->prog);
|
|
prog->prog = 0;
|
|
}
|
|
free(version_string);
|
|
free(fs_vars);
|
|
free(vs_vars);
|
|
return FALSE;
|
|
}
|
|
|
|
Bool
|
|
glamor_use_program(PixmapPtr pixmap,
|
|
GCPtr gc,
|
|
glamor_program *prog,
|
|
void *arg)
|
|
{
|
|
glUseProgram(prog->prog);
|
|
|
|
if (prog->prim_use && !prog->prim_use(pixmap, gc, prog, arg))
|
|
return FALSE;
|
|
|
|
if (prog->fill_use && !prog->fill_use(pixmap, gc, prog, arg))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
glamor_program *
|
|
glamor_use_program_fill(PixmapPtr pixmap,
|
|
GCPtr gc,
|
|
glamor_program_fill *program_fill,
|
|
const glamor_facet *prim)
|
|
{
|
|
ScreenPtr screen = pixmap->drawable.pScreen;
|
|
glamor_program *prog = &program_fill->progs[gc->fillStyle];
|
|
|
|
int fill_style = gc->fillStyle;
|
|
const glamor_facet *fill;
|
|
|
|
if (prog->failed)
|
|
return FALSE;
|
|
|
|
if (!prog->prog) {
|
|
fill = glamor_facet_fill[fill_style];
|
|
if (!fill)
|
|
return NULL;
|
|
|
|
if (!glamor_build_program(screen, prog, prim, fill, NULL, NULL))
|
|
return NULL;
|
|
}
|
|
|
|
if (!glamor_use_program(pixmap, gc, prog, NULL))
|
|
return NULL;
|
|
|
|
return prog;
|
|
}
|
|
|
|
static struct blendinfo composite_op_info[] = {
|
|
[PictOpClear] = {0, 0, GL_ZERO, GL_ZERO},
|
|
[PictOpSrc] = {0, 0, GL_ONE, GL_ZERO},
|
|
[PictOpDst] = {0, 0, GL_ZERO, GL_ONE},
|
|
[PictOpOver] = {0, 1, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
|
|
[PictOpOverReverse] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ONE},
|
|
[PictOpIn] = {1, 0, GL_DST_ALPHA, GL_ZERO},
|
|
[PictOpInReverse] = {0, 1, GL_ZERO, GL_SRC_ALPHA},
|
|
[PictOpOut] = {1, 0, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
|
|
[PictOpOutReverse] = {0, 1, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
|
|
[PictOpAtop] = {1, 1, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
|
|
[PictOpAtopReverse] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA},
|
|
[PictOpXor] = {1, 1, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
|
|
[PictOpAdd] = {0, 0, GL_ONE, GL_ONE},
|
|
};
|
|
|
|
static void
|
|
glamor_set_blend(CARD8 op, glamor_program_alpha alpha, PicturePtr dst)
|
|
{
|
|
glamor_screen_private *glamor_priv = glamor_get_screen_private(dst->pDrawable->pScreen);
|
|
GLenum src_blend, dst_blend;
|
|
struct blendinfo *op_info;
|
|
|
|
switch (alpha) {
|
|
case glamor_program_alpha_ca_first:
|
|
op = PictOpOutReverse;
|
|
break;
|
|
case glamor_program_alpha_ca_second:
|
|
op = PictOpAdd;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (glamor_priv->gl_flavor != GLAMOR_GL_ES2)
|
|
glDisable(GL_COLOR_LOGIC_OP);
|
|
|
|
if (op == PictOpSrc)
|
|
return;
|
|
|
|
op_info = &composite_op_info[op];
|
|
|
|
src_blend = op_info->source_blend;
|
|
dst_blend = op_info->dest_blend;
|
|
|
|
/* If there's no dst alpha channel, adjust the blend op so that we'll treat
|
|
* it as always 1.
|
|
*/
|
|
if (PICT_FORMAT_A(dst->format) == 0 && op_info->dest_alpha) {
|
|
if (src_blend == GL_DST_ALPHA)
|
|
src_blend = GL_ONE;
|
|
else if (src_blend == GL_ONE_MINUS_DST_ALPHA)
|
|
src_blend = GL_ZERO;
|
|
}
|
|
|
|
/* Set up the source alpha value for blending in component alpha mode. */
|
|
if (alpha == glamor_program_alpha_dual_blend) {
|
|
switch (dst_blend) {
|
|
case GL_SRC_ALPHA:
|
|
dst_blend = GL_SRC1_COLOR;
|
|
break;
|
|
case GL_ONE_MINUS_SRC_ALPHA:
|
|
dst_blend = GL_ONE_MINUS_SRC1_COLOR;
|
|
break;
|
|
}
|
|
} else if (alpha != glamor_program_alpha_normal) {
|
|
switch (dst_blend) {
|
|
case GL_SRC_ALPHA:
|
|
dst_blend = GL_SRC_COLOR;
|
|
break;
|
|
case GL_ONE_MINUS_SRC_ALPHA:
|
|
dst_blend = GL_ONE_MINUS_SRC_COLOR;
|
|
break;
|
|
}
|
|
}
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(src_blend, dst_blend);
|
|
}
|
|
|
|
static Bool
|
|
use_source_solid(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
|
|
{
|
|
PictSolidFill *solid = &src->pSourcePict->solidFill;
|
|
float color[4];
|
|
|
|
glamor_get_rgba_from_color(&solid->fullcolor, color);
|
|
glamor_set_blend(op, prog->alpha, dst);
|
|
glUniform4fv(prog->fg_uniform, 1, color);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static const glamor_facet glamor_source_solid = {
|
|
.name = "render_solid",
|
|
.fs_exec = " vec4 source = fg;\n",
|
|
.locations = glamor_program_location_fg,
|
|
.use_render = use_source_solid,
|
|
};
|
|
|
|
static Bool
|
|
use_source_picture(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
|
|
{
|
|
glamor_set_blend(op, prog->alpha, dst);
|
|
|
|
return glamor_set_texture((PixmapPtr) src->pDrawable,
|
|
glamor_picture_red_is_alpha(dst),
|
|
0, 0,
|
|
prog->fill_offset_uniform,
|
|
prog->fill_size_inv_uniform);
|
|
}
|
|
|
|
static const glamor_facet glamor_source_picture = {
|
|
.name = "render_picture",
|
|
.vs_exec = " fill_pos = (fill_offset + primitive.xy + pos) * fill_size_inv;\n",
|
|
.fs_exec = " vec4 source = texture2D(sampler, fill_pos);\n",
|
|
.locations = glamor_program_location_fillsamp | glamor_program_location_fillpos,
|
|
.use_render = use_source_picture,
|
|
};
|
|
|
|
static Bool
|
|
use_source_1x1_picture(CARD8 op, PicturePtr src, PicturePtr dst, glamor_program *prog)
|
|
{
|
|
glamor_set_blend(op, prog->alpha, dst);
|
|
|
|
return glamor_set_texture_pixmap((PixmapPtr) src->pDrawable,
|
|
glamor_picture_red_is_alpha(dst));
|
|
}
|
|
|
|
static const glamor_facet glamor_source_1x1_picture = {
|
|
.name = "render_picture",
|
|
.fs_exec = " vec4 source = texture2D(sampler, vec2(0.5));\n",
|
|
.locations = glamor_program_location_fillsamp,
|
|
.use_render = use_source_1x1_picture,
|
|
};
|
|
|
|
static const glamor_facet *glamor_facet_source[glamor_program_source_count] = {
|
|
[glamor_program_source_solid] = &glamor_source_solid,
|
|
[glamor_program_source_picture] = &glamor_source_picture,
|
|
[glamor_program_source_1x1_picture] = &glamor_source_1x1_picture,
|
|
};
|
|
|
|
static const char *glamor_combine[] = {
|
|
[glamor_program_alpha_normal] = " gl_FragColor = source * mask.a;\n",
|
|
[glamor_program_alpha_ca_first] = " gl_FragColor = source.a * mask;\n",
|
|
[glamor_program_alpha_ca_second] = " gl_FragColor = source * mask;\n",
|
|
[glamor_program_alpha_dual_blend] = " color0 = source * mask;\n"
|
|
" color1 = source.a * mask;\n"
|
|
};
|
|
|
|
static Bool
|
|
glamor_setup_one_program_render(ScreenPtr screen,
|
|
glamor_program *prog,
|
|
glamor_program_source source_type,
|
|
glamor_program_alpha alpha,
|
|
const glamor_facet *prim,
|
|
const char *defines)
|
|
{
|
|
if (prog->failed)
|
|
return FALSE;
|
|
|
|
if (!prog->prog) {
|
|
const glamor_facet *fill = glamor_facet_source[source_type];
|
|
|
|
if (!fill)
|
|
return FALSE;
|
|
|
|
prog->alpha = alpha;
|
|
if (!glamor_build_program(screen, prog, prim, fill, glamor_combine[alpha], defines))
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
glamor_program *
|
|
glamor_setup_program_render(CARD8 op,
|
|
PicturePtr src,
|
|
PicturePtr mask,
|
|
PicturePtr dst,
|
|
glamor_program_render *program_render,
|
|
const glamor_facet *prim,
|
|
const char *defines)
|
|
{
|
|
ScreenPtr screen = dst->pDrawable->pScreen;
|
|
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
|
|
glamor_program_alpha alpha;
|
|
glamor_program_source source_type;
|
|
glamor_program *prog;
|
|
|
|
if (op > ARRAY_SIZE(composite_op_info))
|
|
return NULL;
|
|
|
|
if (glamor_is_component_alpha(mask)) {
|
|
if (glamor_priv->has_dual_blend) {
|
|
alpha = glamor_program_alpha_dual_blend;
|
|
} else {
|
|
/* This only works for PictOpOver */
|
|
if (op != PictOpOver)
|
|
return NULL;
|
|
|
|
alpha = glamor_program_alpha_ca_first;
|
|
}
|
|
} else
|
|
alpha = glamor_program_alpha_normal;
|
|
|
|
if (src->pDrawable) {
|
|
|
|
/* Can't do transforms, alphamaps or sourcing from non-pixmaps yet */
|
|
if (src->transform || src->alphaMap || src->pDrawable->type != DRAWABLE_PIXMAP)
|
|
return NULL;
|
|
|
|
if (src->pDrawable->width == 1 && src->pDrawable->height == 1 && src->repeat)
|
|
source_type = glamor_program_source_1x1_picture;
|
|
else
|
|
source_type = glamor_program_source_picture;
|
|
} else {
|
|
SourcePictPtr sp = src->pSourcePict;
|
|
if (!sp)
|
|
return NULL;
|
|
switch (sp->type) {
|
|
case SourcePictTypeSolidFill:
|
|
source_type = glamor_program_source_solid;
|
|
break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
prog = &program_render->progs[source_type][alpha];
|
|
if (!glamor_setup_one_program_render(screen, prog, source_type, alpha, prim, defines))
|
|
return NULL;
|
|
|
|
if (alpha == glamor_program_alpha_ca_first) {
|
|
|
|
/* Make sure we can also build the second program before
|
|
* deciding to use this path.
|
|
*/
|
|
if (!glamor_setup_one_program_render(screen,
|
|
&program_render->progs[source_type][glamor_program_alpha_ca_second],
|
|
source_type, glamor_program_alpha_ca_second, prim,
|
|
defines))
|
|
return NULL;
|
|
}
|
|
return prog;
|
|
}
|
|
|
|
Bool
|
|
glamor_use_program_render(glamor_program *prog,
|
|
CARD8 op,
|
|
PicturePtr src,
|
|
PicturePtr dst)
|
|
{
|
|
glUseProgram(prog->prog);
|
|
|
|
if (prog->prim_use_render && !prog->prim_use_render(op, src, dst, prog))
|
|
return FALSE;
|
|
|
|
if (prog->fill_use_render && !prog->fill_use_render(op, src, dst, prog))
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|