glamor: Add support for solid source pictures.

This commit is contained in:
Eric Anholt 2009-09-04 18:43:52 -07:00 committed by Zhigang Gong
parent 1159ebb30b
commit 5915b4c0cf
2 changed files with 159 additions and 63 deletions

View File

@ -43,6 +43,8 @@ typedef struct glamor_composite_shader {
GLint dest_to_dest_uniform_location; GLint dest_to_dest_uniform_location;
GLint dest_to_source_uniform_location; GLint dest_to_source_uniform_location;
GLint dest_to_mask_uniform_location; GLint dest_to_mask_uniform_location;
GLint source_uniform_location;
GLint mask_uniform_location;
} glamor_composite_shader; } glamor_composite_shader;
typedef struct glamor_screen_private { typedef struct glamor_screen_private {
@ -70,7 +72,7 @@ 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[2]; glamor_composite_shader composite_shader[8];
} glamor_screen_private; } glamor_screen_private;
typedef struct glamor_pixmap_private { typedef struct glamor_pixmap_private {

View File

@ -39,7 +39,9 @@
#include "glu3/glu3.h" #include "glu3/glu3.h"
struct shader_key { struct shader_key {
Bool solid_source;
Bool has_mask; Bool has_mask;
Bool solid_mask;
}; };
struct blendinfo { struct blendinfo {
@ -65,7 +67,9 @@ static struct blendinfo composite_op_info[] = {
[PictOpAdd] = {0, 0, GL_ONE, GL_ONE}, [PictOpAdd] = {0, 0, GL_ONE, GL_ONE},
}; };
#define HAS_MASK_INDEX 1 #define SOLID_SOURCE_INDEX 1
#define HAS_MASK_INDEX 2
#define SOLID_MASK_INDEX 3
static glamor_composite_shader * static glamor_composite_shader *
glamor_lookup_composite_shader(ScreenPtr screen, struct shader_key *key) glamor_lookup_composite_shader(ScreenPtr screen, struct shader_key *key)
@ -73,8 +77,13 @@ glamor_lookup_composite_shader(ScreenPtr screen, struct shader_key *key)
glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); glamor_screen_private *glamor_priv = glamor_get_screen_private(screen);
int index = 0; int index = 0;
if (key->has_mask) if (key->solid_source)
index += SOLID_SOURCE_INDEX;
if (key->has_mask) {
index += HAS_MASK_INDEX; index += HAS_MASK_INDEX;
if (key->solid_mask)
index += SOLID_MASK_INDEX;
}
assert(index < ARRAY_SIZE(glamor_priv->composite_shader)); assert(index < ARRAY_SIZE(glamor_priv->composite_shader));
@ -84,31 +93,58 @@ glamor_lookup_composite_shader(ScreenPtr screen, struct shader_key *key)
static GLuint static GLuint
glamor_create_composite_fs(struct shader_key *key) glamor_create_composite_fs(struct shader_key *key)
{ {
const char *header = const char *source_pixmap_header =
"uniform sampler2D source_sampler;\n" "uniform sampler2D source_sampler;\n"
"varying vec4 source_coords;\n"; "varying vec4 source_coords;\n";
const char *mask_header = const char *source_solid_header =
"uniform vec4 source;\n";
const char *mask_pixmap_header =
"uniform sampler2D mask_sampler;\n" "uniform sampler2D mask_sampler;\n"
"varying vec4 mask_coords;\n"; "varying vec4 mask_coords;\n";
const char *mask_solid_header =
"uniform vec4 mask;\n";
const char *main_opening = const char *main_opening =
"void main()\n" "void main()\n"
"{\n" "{\n";
" vec4 result;\n" const char *source_pixmap_fetch =
" result = texture2DProj(source_sampler, source_coords.xyw);\n"; " vec4 source = texture2DProj(source_sampler, "
" source_coords.xyw);\n";
const char *mask_pixmap_fetch =
" vec4 mask = texture2DProj(mask_sampler, mask_coords.xyw);\n";
const char *source_in_mask = const char *source_in_mask =
" vec4 mask = texture2DProj(mask_sampler, mask_coords.xyw);\n" " gl_FragColor = source * mask.w;\n";
" result = result * mask.w;\n"; const char *source_only =
" gl_FragColor = source;\n";
const char *main_closing = const char *main_closing =
" gl_FragColor = result;\n"
"}\n"; "}\n";
char *source; char *source;
const char *source_setup = "";
const char *source_fetch = "";
const char *mask_setup = "";
const char *mask_fetch = "";
GLuint prog; GLuint prog;
source = XNFprintf("%s%s%s%s%s", if (key->solid_source) {
header, source_setup = source_solid_header;
key->has_mask ? mask_header : "", } else {
source_setup = source_pixmap_header;
source_fetch = source_pixmap_fetch;
}
if (key->has_mask) {
if (key->solid_mask) {
mask_setup = mask_solid_header;
} else {
mask_setup = mask_pixmap_header;
mask_fetch = mask_pixmap_fetch;
}
}
source = XNFprintf("%s%s%s%s%s%s%s",
source_setup,
mask_setup,
main_opening, main_opening,
key->has_mask ? source_in_mask : "", source_fetch,
mask_fetch,
key->has_mask ? source_in_mask : source_only,
main_closing); main_closing);
prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER_ARB, source); prog = glamor_compile_glsl_prog(GL_FRAGMENT_SHADER_ARB, source);
@ -139,12 +175,13 @@ glamor_create_composite_vs(struct shader_key *key)
"}\n"; "}\n";
char *source; char *source;
GLuint prog; GLuint prog;
Bool compute_mask_coords = key->has_mask && !key->solid_mask;
source = XNFprintf("%s%s%s%s%s", source = XNFprintf("%s%s%s%s%s",
header, header,
key->has_mask ? mask_header : "", compute_mask_coords ? mask_header : "",
main_opening, main_opening,
key->has_mask ? mask_coords : "", compute_mask_coords ? mask_coords : "",
main_closing); main_closing);
prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER_ARB, source); prog = glamor_compile_glsl_prog(GL_VERTEX_SHADER_ARB, source);
@ -177,20 +214,31 @@ glamor_create_composite_shader(ScreenPtr screen, struct shader_key *key)
shader->prog = prog; shader->prog = prog;
glUseProgramObjectARB(prog); glUseProgramObjectARB(prog);
source_sampler_uniform_location = glGetUniformLocationARB(prog,
"source_sampler");
shader->dest_to_dest_uniform_location = shader->dest_to_dest_uniform_location =
glGetUniformLocationARB(prog, "dest_to_dest"); glGetUniformLocationARB(prog, "dest_to_dest");
shader->dest_to_source_uniform_location =
glGetUniformLocationARB(prog, "dest_to_source"); if (key->solid_source) {
glUniform1i(source_sampler_uniform_location, 0); shader->source_uniform_location = glGetUniformLocationARB(prog,
"source");
} else {
source_sampler_uniform_location = glGetUniformLocationARB(prog,
"source_sampler");
shader->dest_to_source_uniform_location =
glGetUniformLocationARB(prog, "dest_to_source");
glUniform1i(source_sampler_uniform_location, 0);
}
if (key->has_mask) { if (key->has_mask) {
mask_sampler_uniform_location = glGetUniformLocationARB(prog, if (key->solid_mask) {
"mask_sampler"); shader->mask_uniform_location = glGetUniformLocationARB(prog,
glUniform1i(mask_sampler_uniform_location, 1); "mask");
shader->dest_to_mask_uniform_location = } else {
glGetUniformLocationARB(prog, "dest_to_mask"); mask_sampler_uniform_location = glGetUniformLocationARB(prog,
"mask_sampler");
glUniform1i(mask_sampler_uniform_location, 1);
shader->dest_to_mask_uniform_location =
glGetUniformLocationARB(prog, "dest_to_mask");
}
} }
} }
@ -199,10 +247,21 @@ glamor_init_composite_shaders(ScreenPtr screen)
{ {
struct shader_key key; struct shader_key key;
memset(&key, 0, sizeof(key));
key.has_mask = FALSE; key.has_mask = FALSE;
glamor_create_composite_shader(screen, &key); glamor_create_composite_shader(screen, &key);
key.has_mask = TRUE; key.has_mask = TRUE;
glamor_create_composite_shader(screen, &key); glamor_create_composite_shader(screen, &key);
key.solid_mask = TRUE;
glamor_create_composite_shader(screen, &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 void static void
@ -277,8 +336,12 @@ glamor_set_composite_op(ScreenPtr screen,
static void static void
glamor_set_composite_texture(ScreenPtr screen, int unit, PicturePtr picture, glamor_set_composite_texture(ScreenPtr screen, int unit, PicturePtr picture,
glamor_pixmap_private *pixmap_priv) glamor_pixmap_private *pixmap_priv,
GLint transform_uniform_location,
int x_translate, int y_translate)
{ {
GLUmat4 transform;
glActiveTexture(GL_TEXTURE0 + unit); glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, pixmap_priv->tex); glBindTexture(GL_TEXTURE_2D, pixmap_priv->tex);
switch (picture->repeatType) { switch (picture->repeatType) {
@ -313,6 +376,27 @@ glamor_set_composite_texture(ScreenPtr screen, int unit, PicturePtr picture,
} }
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glamor_set_composite_transform_matrix(&transform,
picture,
x_translate,
y_translate);
glUniformMatrix4fvARB(transform_uniform_location, 1, 0,
(float *)&transform);
}
static void
glamor_set_composite_solid(PicturePtr picture, GLint uniform_location)
{
CARD32 c = picture->pSourcePict->solidFill.color; /* a8r8g8b8 */
float color[4]; /* rgba */
color[0] = ((c >> 16) & 0xff) / 255.0;
color[1] = ((c >> 8) & 0xff) / 255.0;
color[2] = ((c >> 0) & 0xff) / 255.0;
color[3] = ((c >> 24) & 0xff) / 255.0;
glUniform4fvARB(uniform_location, 1, color);
} }
void void
@ -332,10 +416,11 @@ glamor_composite(CARD8 op,
ScreenPtr screen = dest->pDrawable->pScreen; ScreenPtr screen = dest->pDrawable->pScreen;
PixmapPtr dest_pixmap = glamor_get_drawable_pixmap(dest->pDrawable); PixmapPtr dest_pixmap = glamor_get_drawable_pixmap(dest->pDrawable);
PixmapPtr source_pixmap, mask_pixmap = NULL; PixmapPtr source_pixmap, mask_pixmap = NULL;
glamor_pixmap_private *source_pixmap_priv, *mask_pixmap_priv = NULL; glamor_pixmap_private *source_pixmap_priv = NULL;
glamor_pixmap_private *mask_pixmap_priv = NULL;
struct shader_key key; struct shader_key key;
glamor_composite_shader *shader; glamor_composite_shader *shader;
GLUmat4 dest_to_dest, dest_to_source, dest_to_mask; GLUmat4 dest_to_dest;
RegionRec region; RegionRec region;
int i; int i;
@ -358,14 +443,23 @@ glamor_composite(CARD8 op,
return; return;
} }
memset(&key, 0, sizeof(key));
key.has_mask = (mask != NULL); key.has_mask = (mask != NULL);
if (!source->pDrawable) { if (!source->pDrawable) {
ErrorF("source-only source\n"); if (source->pSourcePict->type == SourcePictTypeSolidFill) {
goto fail; key.solid_source = TRUE;
} else {
ErrorF("gradient source\n");
goto fail;
}
} }
if (mask && !mask->pDrawable) { if (mask && !mask->pDrawable) {
ErrorF("source-only mask\n"); if (mask->pSourcePict->type == SourcePictTypeSolidFill) {
goto fail; key.solid_mask = TRUE;
} else {
ErrorF("gradient mask\n");
goto fail;
}
} }
if (source->alphaMap) { if (source->alphaMap) {
ErrorF("source alphaMap\n"); ErrorF("source alphaMap\n");
@ -376,17 +470,19 @@ glamor_composite(CARD8 op,
goto fail; goto fail;
} }
source_pixmap = glamor_get_drawable_pixmap(source->pDrawable); if (!key.solid_source) {
source_pixmap_priv = glamor_get_pixmap_private(source_pixmap); source_pixmap = glamor_get_drawable_pixmap(source->pDrawable);
if (source_pixmap == dest_pixmap) { source_pixmap_priv = glamor_get_pixmap_private(source_pixmap);
ErrorF("source == dest\n"); if (source_pixmap == dest_pixmap) {
goto fail; ErrorF("source == dest\n");
goto fail;
}
if (!source_pixmap_priv || source_pixmap_priv->tex == 0) {
ErrorF("no FBO in source\n");
goto fail;
}
} }
if (!source_pixmap_priv || source_pixmap_priv->tex == 0) { if (mask && !key.solid_mask) {
ErrorF("no FBO in source\n");
goto fail;
}
if (mask) {
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) {
@ -431,25 +527,23 @@ glamor_composite(CARD8 op,
-1, 1); -1, 1);
glUniformMatrix4fvARB(shader->dest_to_dest_uniform_location, 1, 0, glUniformMatrix4fvARB(shader->dest_to_dest_uniform_location, 1, 0,
(float *)&dest_to_dest); (float *)&dest_to_dest);
glamor_set_composite_transform_matrix(&dest_to_source,
source,
x_source - x_dest,
y_source - x_dest);
glUniformMatrix4fvARB(shader->dest_to_source_uniform_location, 1, 0,
(float *)&dest_to_source);
if (mask) { if (key.solid_source) {
glamor_set_composite_transform_matrix(&dest_to_mask, glamor_set_composite_solid(source, shader->source_uniform_location);
mask, } else {
x_mask - x_dest, glamor_set_composite_texture(screen, 0, source, source_pixmap_priv,
y_mask - x_dest); shader->dest_to_source_uniform_location,
glUniformMatrix4fvARB(shader->dest_to_mask_uniform_location, 1, 0, x_source - x_dest, y_source - y_dest);
(float *)&dest_to_mask); }
if (key.has_mask) {
if (key.solid_mask) {
glamor_set_composite_solid(mask, shader->mask_uniform_location);
} else {
glamor_set_composite_texture(screen, 1, mask, mask_pixmap_priv,
shader->dest_to_mask_uniform_location,
x_mask - x_dest, y_mask - y_dest);
}
} }
glamor_set_composite_texture(screen, 0, source, source_pixmap_priv);
if (mask)
glamor_set_composite_texture(screen, 1, mask, mask_pixmap_priv);
if (!miComputeCompositeRegion(&region, if (!miComputeCompositeRegion(&region,
source, mask, dest, source, mask, dest,
@ -469,9 +563,9 @@ glamor_composite(CARD8 op,
} }
glEnd(); glEnd();
glamor_set_composite_op(screen, PictOpSrc, dest, mask); glDisable(GL_BLEND);
glUseProgramObjectARB(0); glUseProgramObjectARB(0);
REGION_UNINIT(pDst->pDrawable->pScreen, &region); REGION_UNINIT(pDst->pDrawable->pScreen, &region);
return; return;