glamor: Rework the Render shader setup to be easily modified, like cairo-gl.

This commit is contained in:
Eric Anholt 2010-02-09 22:35:04 -08:00 committed by Zhigang Gong
parent f4a3194837
commit 126fc09cb5
2 changed files with 108 additions and 89 deletions

View File

@ -98,6 +98,19 @@ typedef struct {
#define GLAMOR_NUM_GLYPH_CACHES 4 #define GLAMOR_NUM_GLYPH_CACHES 4
enum shader_source {
SHADER_SOURCE_SOLID,
SHADER_SOURCE_TEXTURE_ALPHA,
SHADER_SOURCE_COUNT,
};
enum shader_mask {
SHADER_MASK_NONE,
SHADER_MASK_SOLID,
SHADER_MASK_TEXTURE_ALPHA,
SHADER_MASK_COUNT,
};
typedef struct glamor_screen_private { typedef struct glamor_screen_private {
CreateGCProcPtr saved_create_gc; CreateGCProcPtr saved_create_gc;
CreatePixmapProcPtr saved_create_pixmap; CreatePixmapProcPtr saved_create_pixmap;
@ -130,7 +143,8 @@ typedef struct glamor_screen_private {
GLint put_image_xybitmap_bg_uniform_location; GLint put_image_xybitmap_bg_uniform_location;
/* glamor_composite */ /* glamor_composite */
glamor_composite_shader composite_shader[8]; glamor_composite_shader composite_shader[SHADER_SOURCE_COUNT]
[SHADER_MASK_COUNT];
glamor_glyph_cache_t glyph_caches[GLAMOR_NUM_GLYPH_CACHES]; glamor_glyph_cache_t glyph_caches[GLAMOR_NUM_GLYPH_CACHES];
} glamor_screen_private; } glamor_screen_private;

View File

@ -39,9 +39,8 @@
#include "glu3/glu3.h" #include "glu3/glu3.h"
struct shader_key { struct shader_key {
Bool solid_source; enum shader_source source;
Bool has_mask; enum shader_mask mask;
Bool solid_mask;
}; };
struct blendinfo { struct blendinfo {
@ -67,29 +66,6 @@ static struct blendinfo composite_op_info[] = {
[PictOpAdd] = {0, 0, GL_ONE, GL_ONE}, [PictOpAdd] = {0, 0, GL_ONE, GL_ONE},
}; };
#define SOLID_SOURCE_INDEX 1
#define HAS_MASK_INDEX 2
#define SOLID_MASK_INDEX 3
static glamor_composite_shader *
glamor_lookup_composite_shader(ScreenPtr screen, struct shader_key *key)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
int index = 0;
if (key->solid_source)
index += SOLID_SOURCE_INDEX;
if (key->has_mask) {
index += HAS_MASK_INDEX;
if (key->solid_mask)
index += SOLID_MASK_INDEX;
}
assert(index < ARRAY_SIZE(glamor_priv->composite_shader));
return &glamor_priv->composite_shader[index];
}
static GLuint static GLuint
glamor_create_composite_fs(struct shader_key *key) glamor_create_composite_fs(struct shader_key *key)
{ {
@ -104,12 +80,12 @@ glamor_create_composite_fs(struct shader_key *key)
const char *main_opening = const char *main_opening =
"void main()\n" "void main()\n"
"{\n"; "{\n";
const char *source_pixmap_fetch = const char *source_alpha_pixmap_fetch =
" vec4 source = texture2D(source_sampler, gl_TexCoord[0].xy);\n"; " vec4 source = texture2D(source_sampler, gl_TexCoord[0].xy);\n";
const char *mask_pixmap_fetch = const char *mask_alpha_pixmap_fetch =
" vec4 mask = texture2D(mask_sampler, gl_TexCoord[1].xy);\n"; " vec4 mask = texture2D(mask_sampler, gl_TexCoord[1].xy);\n";
const char *source_in_mask = const char *source_in_mask =
" gl_FragColor = source * mask.w;\n"; " gl_FragColor = source * mask.a;\n";
const char *source_only = const char *source_only =
" gl_FragColor = source;\n"; " gl_FragColor = source;\n";
const char *main_closing = const char *main_closing =
@ -119,29 +95,49 @@ glamor_create_composite_fs(struct shader_key *key)
const char *source_fetch = ""; const char *source_fetch = "";
const char *mask_setup = ""; const char *mask_setup = "";
const char *mask_fetch = ""; const char *mask_fetch = "";
const char *in;
GLuint prog; GLuint prog;
if (key->solid_source) { switch (key->source) {
case SHADER_SOURCE_SOLID:
source_setup = source_solid_header; source_setup = source_solid_header;
} else { break;
case SHADER_SOURCE_TEXTURE_ALPHA:
source_setup = source_pixmap_header; source_setup = source_pixmap_header;
source_fetch = source_pixmap_fetch; source_fetch = source_alpha_pixmap_fetch;
break;
FatalError("Bad composite shader source");
default:
FatalError("Bad composite source mask");
} }
if (key->has_mask) {
if (key->solid_mask) { switch (key->mask) {
mask_setup = mask_solid_header; case SHADER_MASK_NONE:
} else { break;
mask_setup = mask_pixmap_header; case SHADER_MASK_SOLID:
mask_fetch = mask_pixmap_fetch; mask_setup = mask_solid_header;
} break;
case SHADER_MASK_TEXTURE_ALPHA:
mask_setup = mask_pixmap_header;
mask_fetch = mask_alpha_pixmap_fetch;
break;
default:
FatalError("Bad composite shader mask");
} }
if (key->mask == SHADER_MASK_NONE) {
in = source_only;
} else {
in = source_in_mask;
}
source = XNFprintf("%s%s%s%s%s%s%s", source = XNFprintf("%s%s%s%s%s%s%s",
source_setup, source_setup,
mask_setup, mask_setup,
main_opening, main_opening,
source_fetch, source_fetch,
mask_fetch, mask_fetch,
key->has_mask ? source_in_mask : source_only, in,
main_closing); main_closing);
prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER_ARB, source); prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER_ARB, source);
@ -156,19 +152,28 @@ glamor_create_composite_vs(struct shader_key *key)
const char *main_opening = const char *main_opening =
"void main()\n" "void main()\n"
"{\n" "{\n"
" gl_Position = gl_Vertex;\n" " gl_Position = gl_Vertex;\n";
const char *source_coords =
" gl_TexCoord[0] = gl_MultiTexCoord0;\n"; " gl_TexCoord[0] = gl_MultiTexCoord0;\n";
const char *mask_coords = const char *mask_coords =
" gl_TexCoord[1] = gl_MultiTexCoord1;\n"; " gl_TexCoord[1] = gl_MultiTexCoord1;\n";
const char *main_closing = const char *main_closing =
"}\n"; "}\n";
const char *source_coords_setup = "";
const char *mask_coords_setup = "";
char *source; char *source;
GLuint prog; GLuint prog;
Bool compute_mask_coords = key->has_mask && !key->solid_mask;
source = XNFprintf("%s%s%s", if (key->source != SHADER_SOURCE_SOLID)
source_coords_setup = source_coords;
if (key->mask != SHADER_MASK_NONE && key->mask != SHADER_MASK_SOLID)
mask_coords_setup = mask_coords;
source = XNFprintf("%s%s%s%s",
main_opening, main_opening,
compute_mask_coords ? mask_coords : "", source_coords_setup,
mask_coords_setup,
main_closing); main_closing);
prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER_ARB, source); prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER_ARB, source);
@ -178,13 +183,11 @@ glamor_create_composite_vs(struct shader_key *key)
} }
static void static void
glamor_create_composite_shader(ScreenPtr screen, struct shader_key *key) glamor_create_composite_shader(ScreenPtr screen, struct shader_key *key,
glamor_composite_shader *shader)
{ {
GLuint vs, fs, prog; GLuint vs, fs, prog;
GLint source_sampler_uniform_location, mask_sampler_uniform_location; GLint source_sampler_uniform_location, mask_sampler_uniform_location;
glamor_composite_shader *shader;
shader = glamor_lookup_composite_shader(screen, key);
vs = glamor_create_composite_vs(key); vs = glamor_create_composite_vs(key);
if (vs == 0) if (vs == 0)
@ -202,7 +205,7 @@ glamor_create_composite_shader(ScreenPtr screen, struct shader_key *key)
glUseProgramObjectARB(prog); glUseProgramObjectARB(prog);
if (key->solid_source) { if (key->source == SHADER_SOURCE_SOLID) {
shader->source_uniform_location = glGetUniformLocationARB(prog, shader->source_uniform_location = glGetUniformLocationARB(prog,
"source"); "source");
} else { } else {
@ -211,8 +214,8 @@ glamor_create_composite_shader(ScreenPtr screen, struct shader_key *key)
glUniform1i(source_sampler_uniform_location, 0); glUniform1i(source_sampler_uniform_location, 0);
} }
if (key->has_mask) { if (key->mask != SHADER_MASK_NONE) {
if (key->solid_mask) { if (key->mask == SHADER_MASK_SOLID) {
shader->mask_uniform_location = glGetUniformLocationARB(prog, shader->mask_uniform_location = glGetUniformLocationARB(prog,
"mask"); "mask");
} else { } else {
@ -223,27 +226,22 @@ glamor_create_composite_shader(ScreenPtr screen, struct shader_key *key)
} }
} }
static glamor_composite_shader *
glamor_lookup_composite_shader(ScreenPtr screen, struct shader_key *key)
{
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
glamor_composite_shader *shader;
shader = &glamor_priv->composite_shader[key->source][key->mask];
if (shader->prog == 0)
glamor_create_composite_shader(screen, key, shader);
return shader;
}
void void
glamor_init_composite_shaders(ScreenPtr screen) glamor_init_composite_shaders(ScreenPtr screen)
{ {
struct shader_key key;
memset(&key, 0, sizeof(key));
key.has_mask = FALSE;
glamor_create_composite_shader(screen, &key);
key.has_mask = TRUE;
glamor_create_composite_shader(screen, &key);
key.solid_mask = TRUE;
glamor_create_composite_shader(screen, &key);
memset(&key, 0, sizeof(key));
key.solid_source = TRUE;
key.has_mask = FALSE;
glamor_create_composite_shader(screen, &key);
key.has_mask = TRUE;
glamor_create_composite_shader(screen, &key);
key.solid_mask = TRUE;
glamor_create_composite_shader(screen, &key);
} }
static Bool static Bool
@ -505,33 +503,40 @@ glamor_composite_with_shader(CARD8 op,
BoxPtr box; BoxPtr box;
memset(&key, 0, sizeof(key)); memset(&key, 0, sizeof(key));
key.has_mask = (mask != NULL);
if (!source->pDrawable) { if (!source->pDrawable) {
if (source->pSourcePict->type == SourcePictTypeSolidFill) { if (source->pSourcePict->type == SourcePictTypeSolidFill) {
key.solid_source = TRUE; key.source = SHADER_SOURCE_SOLID;
} else { } else {
ErrorF("gradient source\n"); glamor_fallback("gradient source\n");
goto fail; goto fail;
} }
} else {
key.source = SHADER_SOURCE_TEXTURE_ALPHA;
} }
if (mask && !mask->pDrawable) { if (mask) {
if (mask->pSourcePict->type == SourcePictTypeSolidFill) { if (!mask->pDrawable) {
key.solid_mask = TRUE; if (mask->pSourcePict->type == SourcePictTypeSolidFill) {
key.mask = SHADER_MASK_SOLID;
} else {
glamor_fallback("gradient mask\n");
goto fail;
}
} else { } else {
ErrorF("gradient mask\n"); key.mask = SHADER_MASK_TEXTURE_ALPHA;
goto fail;
} }
} else {
key.mask = SHADER_MASK_NONE;
} }
if (source->alphaMap) { if (source->alphaMap) {
ErrorF("source alphaMap\n"); glamor_fallback("source alphaMap\n");
goto fail; goto fail;
} }
if (mask && mask->alphaMap) { if (mask && mask->alphaMap) {
ErrorF("mask alphaMap\n"); glamor_fallback("mask alphaMap\n");
goto fail; goto fail;
} }
if (!key.solid_source) { if (key.source == SHADER_SOURCE_TEXTURE_ALPHA) {
source_pixmap = glamor_get_drawable_pixmap(source->pDrawable); source_pixmap = glamor_get_drawable_pixmap(source->pDrawable);
source_pixmap_priv = glamor_get_pixmap_private(source_pixmap); source_pixmap_priv = glamor_get_pixmap_private(source_pixmap);
if (source_pixmap == dest_pixmap) { if (source_pixmap == dest_pixmap) {
@ -545,7 +550,7 @@ glamor_composite_with_shader(CARD8 op,
if (!good_source_format(source)) if (!good_source_format(source))
goto fail; goto fail;
} }
if (mask && !key.solid_mask) { if (key.mask == SHADER_MASK_TEXTURE_ALPHA) {
mask_pixmap = glamor_get_drawable_pixmap(mask->pDrawable); mask_pixmap = glamor_get_drawable_pixmap(mask->pDrawable);
mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap); mask_pixmap_priv = glamor_get_pixmap_private(mask_pixmap);
if (mask_pixmap == dest_pixmap) { if (mask_pixmap == dest_pixmap) {
@ -589,13 +594,13 @@ glamor_composite_with_shader(CARD8 op,
y_mask += mask->pDrawable->y; y_mask += mask->pDrawable->y;
} }
if (key.solid_source) { if (key.source == SHADER_SOURCE_SOLID) {
glamor_set_composite_solid(source, shader->source_uniform_location); glamor_set_composite_solid(source, shader->source_uniform_location);
} else { } else {
glamor_set_composite_texture(screen, 0, source, source_pixmap_priv); glamor_set_composite_texture(screen, 0, source, source_pixmap_priv);
} }
if (key.has_mask) { if (key.mask != SHADER_MASK_NONE) {
if (key.solid_mask) { if (key.mask == SHADER_MASK_SOLID) {
glamor_set_composite_solid(mask, shader->mask_uniform_location); glamor_set_composite_solid(mask, shader->mask_uniform_location);
} else { } else {
glamor_set_composite_texture(screen, 1, mask, mask_pixmap_priv); glamor_set_composite_texture(screen, 1, mask, mask_pixmap_priv);
@ -614,13 +619,13 @@ glamor_composite_with_shader(CARD8 op,
glVertexPointer(2, GL_FLOAT, sizeof(float) * 2, vertices); glVertexPointer(2, GL_FLOAT, sizeof(float) * 2, vertices);
glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_VERTEX_ARRAY);
if (!key.solid_source) { if (key.source != SHADER_SOURCE_SOLID) {
glClientActiveTexture(GL_TEXTURE0); glClientActiveTexture(GL_TEXTURE0);
glTexCoordPointer(2, GL_FLOAT, sizeof(float) * 2, source_texcoords); glTexCoordPointer(2, GL_FLOAT, sizeof(float) * 2, source_texcoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
} }
if (key.has_mask && !key.solid_mask) { if (key.mask != SHADER_MASK_NONE && key.mask != SHADER_MASK_SOLID) {
glClientActiveTexture(GL_TEXTURE1); glClientActiveTexture(GL_TEXTURE1);
glTexCoordPointer(2, GL_FLOAT, sizeof(float) * 2, mask_texcoords); glTexCoordPointer(2, GL_FLOAT, sizeof(float) * 2, mask_texcoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
@ -637,7 +642,7 @@ glamor_composite_with_shader(CARD8 op,
vertices[3][0] = v_from_x_coord_x(dest_pixmap, box[i].x1); vertices[3][0] = v_from_x_coord_x(dest_pixmap, box[i].x1);
vertices[3][1] = v_from_x_coord_y(dest_pixmap, box[i].y2); vertices[3][1] = v_from_x_coord_y(dest_pixmap, box[i].y2);
if (!key.solid_source) { if (key.source != SHADER_SOURCE_SOLID) {
int tx1 = box[i].x1 + x_source - x_dest; int tx1 = box[i].x1 + x_source - x_dest;
int ty1 = box[i].y1 + y_source - y_dest; int ty1 = box[i].y1 + y_source - y_dest;
int tx2 = box[i].x2 + x_source - x_dest; int tx2 = box[i].x2 + x_source - x_dest;
@ -652,7 +657,7 @@ glamor_composite_with_shader(CARD8 op,
source_texcoords[3][1] = t_from_x_coord_y(source_pixmap, ty2); source_texcoords[3][1] = t_from_x_coord_y(source_pixmap, ty2);
} }
if (key.has_mask && !key.solid_mask) { if (key.mask != SHADER_MASK_NONE && key.mask != SHADER_MASK_SOLID) {
int tx1 = box[i].x1 + x_mask - x_dest; int tx1 = box[i].x1 + x_mask - x_dest;
int ty1 = box[i].y1 + y_mask - y_dest; int ty1 = box[i].y1 + y_mask - y_dest;
int tx2 = box[i].x2 + x_mask - x_dest; int tx2 = box[i].x2 + x_mask - x_dest;