You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1330 lines
30 KiB
1330 lines
30 KiB
/*
|
|
* Copyright © 2007 Novell, Inc.
|
|
*
|
|
* 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
|
|
* Novell, Inc. not be used in advertising or publicity pertaining to
|
|
* distribution of the software without specific, written prior permission.
|
|
* Novell, Inc. makes no representations about the suitability of this
|
|
* software for any purpose. It is provided "as is" without express or
|
|
* implied warranty.
|
|
*
|
|
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
|
|
* NO EVENT SHALL NOVELL, INC. 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.
|
|
*
|
|
* Author: David Reveman <davidr@novell.com>
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <unistd.h>
|
|
|
|
#include <compiz-core.h>
|
|
#include <decoration.h>
|
|
|
|
#include <X11/Xatom.h>
|
|
#include <X11/extensions/shape.h>
|
|
|
|
/*
|
|
* compiz composited video
|
|
*
|
|
* supported image formats:
|
|
*
|
|
* RGB - packed RGB colorspace
|
|
*
|
|
* +---------------+
|
|
* | | width = image-width
|
|
* | | height = image-height
|
|
* | RGB |
|
|
* | | any pixmap depth with a matching
|
|
* | | fb-config can be used.
|
|
* +---------------+
|
|
|
|
* YV12 - planar YV12 colorspace
|
|
*
|
|
* +---------------+
|
|
* | | width = image-width
|
|
* | | height = image-height + image-height / 2
|
|
* | Y | depth = 8
|
|
* | |
|
|
* | | alpha only fb-config with pixmap support
|
|
* +-------+-------+ must be available.
|
|
* | | |
|
|
* | V | U |
|
|
* | | |
|
|
* +---------------+
|
|
*
|
|
*/
|
|
|
|
static CompMetadata videoMetadata;
|
|
|
|
typedef struct _VideoTexture {
|
|
struct _VideoTexture *next;
|
|
int refCount;
|
|
Pixmap pixmap;
|
|
int width;
|
|
int height;
|
|
Damage damage;
|
|
CompTexture texture;
|
|
} VideoTexture;
|
|
|
|
typedef struct _VideoFunction {
|
|
struct _VideoFunction *next;
|
|
|
|
int handle;
|
|
int target;
|
|
int param;
|
|
} VideoFunction;
|
|
|
|
#define IMAGE_FORMAT_RGB 0
|
|
#define IMAGE_FORMAT_YV12 1
|
|
#define IMAGE_FORMAT_NUM 2
|
|
|
|
static int displayPrivateIndex;
|
|
|
|
#define VIDEO_DISPLAY_OPTION_YV12 0
|
|
#define VIDEO_DISPLAY_OPTION_NUM 1
|
|
|
|
typedef struct _VideoDisplay {
|
|
int screenPrivateIndex;
|
|
HandleEventProc handleEvent;
|
|
VideoTexture *textures;
|
|
Atom videoAtom;
|
|
Atom videoSupportedAtom;
|
|
Atom videoImageFormatAtom[IMAGE_FORMAT_NUM];
|
|
|
|
CompOption opt[VIDEO_DISPLAY_OPTION_NUM];
|
|
} VideoDisplay;
|
|
|
|
typedef struct _VideoScreen {
|
|
int windowPrivateIndex;
|
|
|
|
DrawWindowProc drawWindow;
|
|
DrawWindowTextureProc drawWindowTexture;
|
|
DamageWindowRectProc damageWindowRect;
|
|
|
|
WindowMoveNotifyProc windowMoveNotify;
|
|
WindowResizeNotifyProc windowResizeNotify;
|
|
|
|
VideoFunction *yv12Functions;
|
|
|
|
Bool imageFormat[IMAGE_FORMAT_NUM];
|
|
} VideoScreen;
|
|
|
|
typedef struct _VideoSource {
|
|
VideoTexture *texture;
|
|
int format;
|
|
decor_point_t p1;
|
|
decor_point_t p2;
|
|
Bool aspect;
|
|
float aspectRatio;
|
|
float panScan;
|
|
int width;
|
|
int height;
|
|
} VideoSource;
|
|
|
|
typedef struct _VideoContext {
|
|
VideoSource *source;
|
|
int width;
|
|
int height;
|
|
REGION box;
|
|
CompMatrix matrix;
|
|
Bool scaled;
|
|
float panX;
|
|
float panY;
|
|
Bool full;
|
|
} VideoContext;
|
|
|
|
typedef struct _VideoWindow {
|
|
VideoSource *source;
|
|
VideoContext *context;
|
|
} VideoWindow;
|
|
|
|
#define GET_VIDEO_DISPLAY(d) \
|
|
((VideoDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
|
|
|
|
#define VIDEO_DISPLAY(d) \
|
|
VideoDisplay *vd = GET_VIDEO_DISPLAY (d)
|
|
|
|
#define GET_VIDEO_SCREEN(s, vd) \
|
|
((VideoScreen *) (s)->base.privates[(vd)->screenPrivateIndex].ptr)
|
|
|
|
#define VIDEO_SCREEN(s) \
|
|
VideoScreen *vs = GET_VIDEO_SCREEN (s, GET_VIDEO_DISPLAY (s->display))
|
|
|
|
#define GET_VIDEO_WINDOW(w, vs) \
|
|
((VideoWindow *) (w)->base.privates[(vs)->windowPrivateIndex].ptr)
|
|
|
|
#define VIDEO_WINDOW(w) \
|
|
VideoWindow *vw = GET_VIDEO_WINDOW (w, \
|
|
GET_VIDEO_SCREEN (w->screen, \
|
|
GET_VIDEO_DISPLAY (w->screen->display)))
|
|
|
|
#define NUM_OPTIONS(d) (sizeof ((d)->opt) / sizeof (CompOption))
|
|
|
|
static void
|
|
videoSetSupportedHint (CompScreen *s)
|
|
{
|
|
Atom data[16];
|
|
int i, n = 0;
|
|
|
|
VIDEO_DISPLAY (s->display);
|
|
VIDEO_SCREEN (s);
|
|
|
|
for (i = 0; i < IMAGE_FORMAT_NUM; i++)
|
|
{
|
|
if (!vs->imageFormat[i])
|
|
continue;
|
|
|
|
if (i == 0 || vd->opt[i - 1].value.b)
|
|
data[n++] = vd->videoImageFormatAtom[i];
|
|
}
|
|
|
|
XChangeProperty (s->display->display, s->root,
|
|
vd->videoSupportedAtom, XA_ATOM, 32,
|
|
PropModeReplace, (unsigned char *) data, n);
|
|
}
|
|
|
|
static CompOption *
|
|
videoGetDisplayOptions (CompPlugin *plugin,
|
|
CompDisplay *display,
|
|
int *count)
|
|
{
|
|
VIDEO_DISPLAY (display);
|
|
|
|
*count = NUM_OPTIONS (vd);
|
|
return vd->opt;
|
|
}
|
|
|
|
static Bool
|
|
videoSetDisplayOption (CompPlugin *plugin,
|
|
CompDisplay *display,
|
|
const char *name,
|
|
CompOptionValue *value)
|
|
{
|
|
CompOption *o;
|
|
int index;
|
|
|
|
VIDEO_DISPLAY (display);
|
|
|
|
o = compFindOption (vd->opt, NUM_OPTIONS (vd), name, &index);
|
|
if (!o)
|
|
return FALSE;
|
|
|
|
switch (index) {
|
|
case VIDEO_DISPLAY_OPTION_YV12:
|
|
if (compSetBoolOption (o, value))
|
|
{
|
|
CompScreen *s;
|
|
|
|
for (s = display->screens; s; s = s->next)
|
|
videoSetSupportedHint (s);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static int
|
|
getYV12FragmentFunction (CompScreen *s,
|
|
CompTexture *texture,
|
|
int param)
|
|
{
|
|
VideoFunction *function;
|
|
CompFunctionData *data;
|
|
int target;
|
|
|
|
VIDEO_SCREEN (s);
|
|
|
|
if (texture->target == GL_TEXTURE_2D)
|
|
target = COMP_FETCH_TARGET_2D;
|
|
else
|
|
target = COMP_FETCH_TARGET_RECT;
|
|
|
|
for (function = vs->yv12Functions; function; function = function->next)
|
|
if (function->param == param && function->target == target)
|
|
return function->handle;
|
|
|
|
data = createFunctionData ();
|
|
if (data)
|
|
{
|
|
static char *temp[] = { "uv", "tmp", "position" };
|
|
int i, handle = 0;
|
|
char str[1024];
|
|
Bool ok = TRUE;
|
|
|
|
for (i = 0; i < sizeof (temp) / sizeof (temp[0]); i++)
|
|
ok &= addTempHeaderOpToFunctionData (data, temp[i]);
|
|
|
|
snprintf (str, 1024,
|
|
"MOV position, fragment.texcoord[0];"
|
|
"MAX position, position, program.env[%d];"
|
|
"MIN position, position, program.env[%d].zwww;",
|
|
param, param);
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
|
|
if (target == COMP_FETCH_TARGET_RECT)
|
|
{
|
|
snprintf (str, 1024,
|
|
"TEX output, position, texture[0], RECT;"
|
|
"MOV output, output.a;");
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
|
|
if (s->glxPixmapFBConfigs[8].yInverted)
|
|
{
|
|
snprintf (str, 1024,
|
|
"MAD position, position, 0.5, program.env[%d].xy;",
|
|
param + 1);
|
|
}
|
|
else
|
|
{
|
|
snprintf (str, 1024,
|
|
"ADD position, position, program.env[%d].xy;"
|
|
"MUL position, position, 0.5;",
|
|
param + 1);
|
|
}
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
|
|
snprintf (str, 1024,
|
|
"TEX tmp, position, texture[0], RECT;"
|
|
"MOV uv, tmp.a;"
|
|
"MAD output, output, 1.164, -0.073;"
|
|
"ADD position.x, position.x, program.env[%d].z;"
|
|
"TEX tmp, position, texture[0], RECT;"
|
|
"MOV uv.y, tmp.a;",
|
|
param + 1);
|
|
}
|
|
else
|
|
{
|
|
snprintf (str, 1024,
|
|
"TEX output, position, texture[0], 2D;"
|
|
"MOV output, output.a;");
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
|
|
if (s->glxPixmapFBConfigs[8].yInverted)
|
|
{
|
|
snprintf (str, 1024,
|
|
"MAD position, position, 0.5, { 0.0, %f };",
|
|
2.0f / 3.0f);
|
|
}
|
|
else
|
|
{
|
|
snprintf (str, 1024,
|
|
"SUB position, position, { 0.0, %f };"
|
|
"MUL position, position, 0.5;",
|
|
1.0f / 3.0f);
|
|
}
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
|
|
snprintf (str, 1024,
|
|
"TEX tmp, position, texture[0], 2D;"
|
|
"MOV uv, tmp.a;"
|
|
"MAD output, output, 1.164, -0.073;"
|
|
"ADD position.x, position.x, 0.5;"
|
|
"TEX tmp, position, texture[0], 2D;"
|
|
"MOV uv.y, tmp.a;");
|
|
}
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
|
|
snprintf (str, 1024,
|
|
"SUB uv, uv, { 0.5, 0.5 };"
|
|
"MAD output.xyz, { 1.596, -0.813, 0.0 }, uv.xxxw, output;"
|
|
"MAD output.xyz, { 0.0, -0.391, 2.018 }, uv.yyyw, output;"
|
|
"MOV output.a, 1.0;");
|
|
|
|
ok &= addDataOpToFunctionData (data, str);
|
|
|
|
if (!ok)
|
|
{
|
|
destroyFunctionData (data);
|
|
return 0;
|
|
}
|
|
|
|
function = malloc (sizeof (VideoFunction));
|
|
if (function)
|
|
{
|
|
handle = createFragmentFunction (s, "video", data);
|
|
|
|
function->handle = handle;
|
|
function->target = target;
|
|
function->param = param;
|
|
|
|
function->next = vs->yv12Functions;
|
|
vs->yv12Functions = function;
|
|
}
|
|
|
|
destroyFunctionData (data);
|
|
|
|
return handle;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
videoDestroyFragmentFunctions (CompScreen *s,
|
|
VideoFunction **videoFunctions)
|
|
{
|
|
VideoFunction *function, *next;
|
|
|
|
function = *videoFunctions;
|
|
while (function)
|
|
{
|
|
destroyFragmentFunction (s, function->handle);
|
|
|
|
next = function->next;
|
|
free (function);
|
|
function = next;
|
|
}
|
|
|
|
*videoFunctions = NULL;
|
|
}
|
|
|
|
static void
|
|
videoDrawWindowTexture (CompWindow *w,
|
|
CompTexture *texture,
|
|
const FragmentAttrib *attrib,
|
|
unsigned int mask)
|
|
{
|
|
CompScreen *s = w->screen;
|
|
|
|
VIDEO_SCREEN (s);
|
|
VIDEO_WINDOW (w);
|
|
|
|
if (vw->context)
|
|
{
|
|
VideoSource *src = vw->context->source;
|
|
|
|
if (src->format == IMAGE_FORMAT_YV12 &&
|
|
&src->texture->texture == texture)
|
|
{
|
|
FragmentAttrib fa = *attrib;
|
|
int param, function;
|
|
|
|
param = allocFragmentParameters (&fa, 2);
|
|
|
|
function = getYV12FragmentFunction (s, texture, param);
|
|
if (function)
|
|
{
|
|
float minX, minY, maxX, maxY, y1, y2;
|
|
|
|
addFragmentFunction (&fa, function);
|
|
|
|
minX = COMP_TEX_COORD_X (&texture->matrix, 1.0f);
|
|
maxX = COMP_TEX_COORD_X (&texture->matrix, src->width - 1.0f);
|
|
|
|
y1 = COMP_TEX_COORD_Y (&texture->matrix, 1.0f);
|
|
y2 = COMP_TEX_COORD_Y (&texture->matrix, src->height - 1.0f);
|
|
|
|
minY = MIN (y1, y2);
|
|
maxY = MAX (y1, y2);
|
|
|
|
(*s->programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB, param,
|
|
minX, minY, maxX, maxY);
|
|
|
|
/* need to provide plane offsets when texture coordinates
|
|
are not normalized */
|
|
if (texture->target != GL_TEXTURE_2D)
|
|
{
|
|
float offsetX, offsetY;
|
|
|
|
offsetX = COMP_TEX_COORD_X (&texture->matrix,
|
|
src->width / 2);
|
|
|
|
if (s->glxPixmapFBConfigs[8].yInverted)
|
|
offsetY = COMP_TEX_COORD_Y (&texture->matrix,
|
|
src->height);
|
|
else
|
|
offsetY = COMP_TEX_COORD_Y (&texture->matrix,
|
|
-src->height / 2);
|
|
|
|
(*s->programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
|
|
param + 1,
|
|
0.0f, offsetY, offsetX, 0.0f);
|
|
}
|
|
}
|
|
|
|
UNWRAP (vs, s, drawWindowTexture);
|
|
(*s->drawWindowTexture) (w, texture, &fa, mask);
|
|
WRAP (vs, s, drawWindowTexture, videoDrawWindowTexture);
|
|
}
|
|
else
|
|
{
|
|
if (!(mask & PAINT_WINDOW_BLEND_MASK))
|
|
{
|
|
/* we don't have to draw client window texture when
|
|
video cover the full window and blending isn't used */
|
|
if (vw->context->full && texture == w->texture)
|
|
return;
|
|
}
|
|
|
|
UNWRAP (vs, s, drawWindowTexture);
|
|
(*s->drawWindowTexture) (w, texture, attrib, mask);
|
|
WRAP (vs, s, drawWindowTexture, videoDrawWindowTexture);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UNWRAP (vs, s, drawWindowTexture);
|
|
(*s->drawWindowTexture) (w, texture, attrib, mask);
|
|
WRAP (vs, s, drawWindowTexture, videoDrawWindowTexture);
|
|
}
|
|
}
|
|
|
|
static Bool
|
|
videoDrawWindow (CompWindow *w,
|
|
const CompTransform *transform,
|
|
const FragmentAttrib *attrib,
|
|
Region region,
|
|
unsigned int mask)
|
|
{
|
|
Bool status;
|
|
|
|
VIDEO_SCREEN (w->screen);
|
|
|
|
UNWRAP (vs, w->screen, drawWindow);
|
|
status = (*w->screen->drawWindow) (w, transform, attrib, region, mask);
|
|
WRAP (vs, w->screen, drawWindow, videoDrawWindow);
|
|
|
|
if (status)
|
|
{
|
|
VIDEO_WINDOW (w);
|
|
|
|
if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
|
|
region = &infiniteRegion;
|
|
|
|
if (vw->context && region->numRects)
|
|
{
|
|
CompTexture *texture = &vw->context->source->texture->texture;
|
|
int saveFilter;
|
|
|
|
w->vCount = w->indexCount = 0;
|
|
|
|
if (vw->context->box.extents.x1 < vw->context->box.extents.x2 &&
|
|
vw->context->box.extents.y1 < vw->context->box.extents.y2)
|
|
{
|
|
(*w->screen->addWindowGeometry) (w,
|
|
&vw->context->matrix, 1,
|
|
&vw->context->box,
|
|
region);
|
|
}
|
|
|
|
if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
|
|
mask |= PAINT_WINDOW_BLEND_MASK;
|
|
|
|
saveFilter = w->screen->filter[NOTHING_TRANS_FILTER];
|
|
|
|
if (vw->context->scaled)
|
|
w->screen->filter[NOTHING_TRANS_FILTER] =
|
|
COMP_TEXTURE_FILTER_GOOD;
|
|
|
|
if (w->vCount)
|
|
(*w->screen->drawWindowTexture) (w, texture, attrib, mask);
|
|
|
|
w->screen->filter[NOTHING_TRANS_FILTER] = saveFilter;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static VideoTexture *
|
|
videoGetTexture (CompScreen *screen,
|
|
Pixmap pixmap)
|
|
{
|
|
VideoTexture *texture;
|
|
unsigned int width, height, depth, ui;
|
|
Window root;
|
|
int i;
|
|
|
|
VIDEO_DISPLAY (screen->display);
|
|
|
|
for (texture = vd->textures; texture; texture = texture->next)
|
|
{
|
|
if (texture->pixmap == pixmap)
|
|
{
|
|
texture->refCount++;
|
|
return texture;
|
|
}
|
|
}
|
|
|
|
texture = malloc (sizeof (VideoTexture));
|
|
if (!texture)
|
|
return NULL;
|
|
|
|
initTexture (screen, &texture->texture);
|
|
|
|
if (!XGetGeometry (screen->display->display, pixmap, &root,
|
|
&i, &i, &width, &height, &ui, &depth))
|
|
{
|
|
finiTexture (screen, &texture->texture);
|
|
free (texture);
|
|
return NULL;
|
|
}
|
|
|
|
if (!bindPixmapToTexture (screen, &texture->texture, pixmap,
|
|
width, height, depth))
|
|
{
|
|
finiTexture (screen, &texture->texture);
|
|
free (texture);
|
|
return NULL;
|
|
}
|
|
|
|
texture->damage = XDamageCreate (screen->display->display, pixmap,
|
|
XDamageReportRawRectangles);
|
|
|
|
texture->refCount = 1;
|
|
texture->pixmap = pixmap;
|
|
texture->width = width;
|
|
texture->height = height;
|
|
texture->next = vd->textures;
|
|
|
|
vd->textures = texture;
|
|
|
|
return texture;
|
|
}
|
|
|
|
static void
|
|
videoReleaseTexture (CompScreen *screen,
|
|
VideoTexture *texture)
|
|
{
|
|
VIDEO_DISPLAY (screen->display);
|
|
|
|
texture->refCount--;
|
|
if (texture->refCount)
|
|
return;
|
|
|
|
if (texture == vd->textures)
|
|
{
|
|
vd->textures = texture->next;
|
|
}
|
|
else
|
|
{
|
|
VideoTexture *t;
|
|
|
|
for (t = vd->textures; t; t = t->next)
|
|
{
|
|
if (t->next == texture)
|
|
{
|
|
t->next = texture->next;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
finiTexture (screen, &texture->texture);
|
|
free (texture);
|
|
}
|
|
|
|
static void
|
|
updateWindowVideoMatrix (CompWindow *w)
|
|
{
|
|
VIDEO_WINDOW (w);
|
|
|
|
if (!vw->context)
|
|
return;
|
|
|
|
vw->context->matrix = vw->context->source->texture->texture.matrix;
|
|
|
|
vw->context->matrix.yy /= (float)
|
|
vw->context->height / vw->context->source->height;
|
|
|
|
if (vw->context->width != vw->context->source->width ||
|
|
vw->context->height != vw->context->source->height)
|
|
{
|
|
vw->context->matrix.xx /= (float)
|
|
vw->context->width / vw->context->source->width;
|
|
|
|
vw->context->scaled = TRUE;
|
|
}
|
|
else
|
|
{
|
|
vw->context->scaled = FALSE;
|
|
}
|
|
|
|
vw->context->matrix.x0 -=
|
|
(vw->context->box.extents.x1 * vw->context->matrix.xx);
|
|
vw->context->matrix.y0 -=
|
|
(vw->context->box.extents.y1 * vw->context->matrix.yy);
|
|
|
|
vw->context->matrix.x0 += (vw->context->panX * vw->context->matrix.xx);
|
|
vw->context->matrix.y0 += (vw->context->panY * vw->context->matrix.yy);
|
|
}
|
|
|
|
static void
|
|
updateWindowVideoContext (CompWindow *w,
|
|
VideoSource *source)
|
|
{
|
|
int x1, y1, x2, y2;
|
|
|
|
VIDEO_WINDOW (w);
|
|
|
|
if (!vw->context)
|
|
{
|
|
vw->context = malloc (sizeof (VideoContext));
|
|
if (!vw->context)
|
|
return;
|
|
}
|
|
|
|
vw->context->source = source;
|
|
|
|
vw->context->box.rects = &vw->context->box.extents;
|
|
vw->context->box.numRects = 1;
|
|
|
|
decor_apply_gravity (source->p1.gravity,
|
|
source->p1.x, source->p1.y,
|
|
w->width, w->height,
|
|
&x1, &y1);
|
|
|
|
decor_apply_gravity (source->p2.gravity,
|
|
source->p2.x, source->p2.y,
|
|
w->width, w->height,
|
|
&x2, &y2);
|
|
|
|
x1 = MAX (x1, 0);
|
|
y1 = MAX (y1, 0);
|
|
x2 = MIN (x2, w->width);
|
|
y2 = MIN (y2, w->height);
|
|
|
|
vw->context->width = x2 - x1;
|
|
vw->context->height = y2 - y1;
|
|
|
|
vw->context->panX = 0.0f;
|
|
vw->context->panY = 0.0f;
|
|
|
|
if (source->aspect)
|
|
{
|
|
float aspect, width, height, v;
|
|
|
|
width = vw->context->width;
|
|
height = vw->context->height;
|
|
|
|
aspect = width / height;
|
|
|
|
if (aspect < source->aspectRatio)
|
|
{
|
|
v = (width + width * source->panScan) / source->aspectRatio;
|
|
height = MIN (vw->context->height, v);
|
|
width = height * source->aspectRatio;
|
|
}
|
|
else
|
|
{
|
|
v = (height + height * source->panScan) * source->aspectRatio;
|
|
width = MIN (vw->context->width, v);
|
|
height = width / source->aspectRatio;
|
|
}
|
|
|
|
x1 = (vw->context->width / 2.0f) - (width / 2.0f);
|
|
y1 = (vw->context->height / 2.0f) - (height / 2.0f);
|
|
x2 = ((vw->context->width / 2.0f) + (width / 2.0f) + 0.5f);
|
|
y2 = ((vw->context->height / 2.0f) + (height / 2.0f) + 0.5f);
|
|
|
|
vw->context->width = x2 - x1;
|
|
vw->context->height = y2 - y1;
|
|
|
|
if (x1 < 0)
|
|
vw->context->panX = -x1;
|
|
|
|
if (y1 < 0)
|
|
vw->context->panY = -y1;
|
|
|
|
x1 = MAX (x1, 0);
|
|
y1 = MAX (y1, 0);
|
|
x2 = MIN (x2, w->width);
|
|
y2 = MIN (y2, w->height);
|
|
}
|
|
|
|
if (x1 == 0 &&
|
|
y1 == 0 &&
|
|
x2 == w->width &&
|
|
y2 == w->height)
|
|
{
|
|
vw->context->full = TRUE;
|
|
}
|
|
else
|
|
{
|
|
vw->context->full = FALSE;
|
|
}
|
|
|
|
vw->context->box.extents.x1 = x1;
|
|
vw->context->box.extents.y1 = y1;
|
|
vw->context->box.extents.x2 = x2;
|
|
vw->context->box.extents.y2 = y2;
|
|
|
|
vw->context->box.extents.x1 += w->attrib.x;
|
|
vw->context->box.extents.y1 += w->attrib.y;
|
|
vw->context->box.extents.x2 += w->attrib.x;
|
|
vw->context->box.extents.y2 += w->attrib.y;
|
|
|
|
updateWindowVideoMatrix (w);
|
|
}
|
|
|
|
static void
|
|
videoWindowUpdate (CompWindow *w)
|
|
{
|
|
Atom actual;
|
|
int result, format, i;
|
|
unsigned long n, left;
|
|
unsigned char *propData;
|
|
VideoTexture *texture = NULL;
|
|
Pixmap pixmap = None;
|
|
Atom imageFormat = 0;
|
|
decor_point_t p[2];
|
|
int aspectX = 0;
|
|
int aspectY = 0;
|
|
int panScan = 0;
|
|
int width = 0;
|
|
int height = 0;
|
|
|
|
VIDEO_DISPLAY (w->screen->display);
|
|
VIDEO_SCREEN (w->screen);
|
|
VIDEO_WINDOW (w);
|
|
|
|
memset (p, 0, sizeof (p));
|
|
|
|
result = XGetWindowProperty (w->screen->display->display, w->id,
|
|
vd->videoAtom, 0L, 13L, FALSE,
|
|
XA_INTEGER, &actual, &format,
|
|
&n, &left, &propData);
|
|
|
|
if (result == Success && propData)
|
|
{
|
|
if (n == 13)
|
|
{
|
|
long *data = (long *) propData;
|
|
|
|
pixmap = *data++;
|
|
imageFormat = *data++;
|
|
|
|
width = *data++;
|
|
height = *data++;
|
|
|
|
aspectX = *data++;
|
|
aspectY = *data++;
|
|
panScan = *data++;
|
|
|
|
p[0].gravity = *data++;
|
|
p[0].x = *data++;
|
|
p[0].y = *data++;
|
|
p[1].gravity = *data++;
|
|
p[1].x = *data++;
|
|
p[1].y = *data++;
|
|
}
|
|
|
|
XFree (propData);
|
|
}
|
|
|
|
for (i = 0; i < IMAGE_FORMAT_NUM; i++)
|
|
if (vd->videoImageFormatAtom[i] == imageFormat)
|
|
break;
|
|
|
|
if (i < IMAGE_FORMAT_NUM)
|
|
{
|
|
if (!vs->imageFormat[i])
|
|
{
|
|
compLogMessage ("video", CompLogLevelWarn,
|
|
"Image format not supported");
|
|
i = IMAGE_FORMAT_NUM;
|
|
}
|
|
}
|
|
|
|
if (i < IMAGE_FORMAT_NUM)
|
|
{
|
|
texture = videoGetTexture (w->screen, pixmap);
|
|
if (!texture)
|
|
{
|
|
compLogMessage ("video", CompLogLevelWarn,
|
|
"Bad pixmap 0x%x", (int) pixmap);
|
|
}
|
|
}
|
|
|
|
if (vw->source)
|
|
{
|
|
videoReleaseTexture (w->screen, vw->source->texture);
|
|
}
|
|
else
|
|
{
|
|
vw->source = malloc (sizeof (VideoSource));
|
|
}
|
|
|
|
if (texture && vw->source)
|
|
{
|
|
vw->source->texture = texture;
|
|
vw->source->format = i;
|
|
vw->source->p1 = p[0];
|
|
vw->source->p2 = p[1];
|
|
vw->source->width = width;
|
|
vw->source->height = height;
|
|
vw->source->aspect = aspectX && aspectY;
|
|
vw->source->panScan = panScan / 65536.0f;
|
|
|
|
if (vw->source->aspect)
|
|
vw->source->aspectRatio = (float) aspectX / aspectY;
|
|
|
|
updateWindowVideoContext (w, vw->source);
|
|
}
|
|
else
|
|
{
|
|
if (texture)
|
|
videoReleaseTexture (w->screen, texture);
|
|
|
|
if (vw->source)
|
|
{
|
|
free (vw->source);
|
|
vw->source = NULL;
|
|
}
|
|
|
|
if (vw->context)
|
|
{
|
|
free (vw->context);
|
|
vw->context = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
videoHandleEvent (CompDisplay *d,
|
|
XEvent *event)
|
|
{
|
|
CompWindow *w;
|
|
|
|
VIDEO_DISPLAY (d);
|
|
|
|
switch (event->type) {
|
|
case PropertyNotify:
|
|
if (event->xproperty.atom == vd->videoAtom)
|
|
{
|
|
w = findWindowAtDisplay (d, event->xproperty.window);
|
|
if (w)
|
|
videoWindowUpdate (w);
|
|
}
|
|
break;
|
|
default:
|
|
if (event->type == d->damageEvent + XDamageNotify)
|
|
{
|
|
XDamageNotifyEvent *de = (XDamageNotifyEvent *) event;
|
|
VideoTexture *t;
|
|
|
|
for (t = vd->textures; t; t = t->next)
|
|
{
|
|
if (t->pixmap == de->drawable)
|
|
{
|
|
VideoWindow *vw;
|
|
VideoScreen *vs;
|
|
CompScreen *s;
|
|
BoxRec box;
|
|
int bw;
|
|
|
|
t->texture.oldMipmaps = TRUE;
|
|
|
|
for (s = d->screens; s; s = s->next)
|
|
{
|
|
vs = GET_VIDEO_SCREEN (s, vd);
|
|
|
|
for (w = s->windows; w; w = w->next)
|
|
{
|
|
if (w->shaded || w->mapNum)
|
|
{
|
|
vw = GET_VIDEO_WINDOW (w, vs);
|
|
|
|
if (vw->context &&
|
|
vw->context->source->texture == t)
|
|
{
|
|
box = vw->context->box.extents;
|
|
|
|
bw = w->attrib.border_width;
|
|
|
|
box.x1 -= w->attrib.x + bw;
|
|
box.y1 -= w->attrib.y + bw;
|
|
box.x2 -= w->attrib.x + bw;
|
|
box.y2 -= w->attrib.y + bw;
|
|
|
|
addWindowDamageRect (w, &box);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
UNWRAP (vd, d, handleEvent);
|
|
(*d->handleEvent) (d, event);
|
|
WRAP (vd, d, handleEvent, videoHandleEvent);
|
|
}
|
|
|
|
static Bool
|
|
videoDamageWindowRect (CompWindow *w,
|
|
Bool initial,
|
|
BoxPtr rect)
|
|
{
|
|
Bool status;
|
|
|
|
VIDEO_SCREEN (w->screen);
|
|
|
|
if (initial)
|
|
videoWindowUpdate (w);
|
|
|
|
UNWRAP (vs, w->screen, damageWindowRect);
|
|
status = (*w->screen->damageWindowRect) (w, initial, rect);
|
|
WRAP (vs, w->screen, damageWindowRect, videoDamageWindowRect);
|
|
|
|
return status;
|
|
}
|
|
|
|
static void
|
|
videoWindowMoveNotify (CompWindow *w,
|
|
int dx,
|
|
int dy,
|
|
Bool immediate)
|
|
{
|
|
VIDEO_SCREEN (w->screen);
|
|
VIDEO_WINDOW (w);
|
|
|
|
if (vw->context)
|
|
{
|
|
vw->context->box.extents.x1 += dx;
|
|
vw->context->box.extents.y1 += dy;
|
|
vw->context->box.extents.x2 += dx;
|
|
vw->context->box.extents.y2 += dy;
|
|
|
|
updateWindowVideoMatrix (w);
|
|
}
|
|
|
|
UNWRAP (vs, w->screen, windowMoveNotify);
|
|
(*w->screen->windowMoveNotify) (w, dx, dy, immediate);
|
|
WRAP (vs, w->screen, windowMoveNotify, videoWindowMoveNotify);
|
|
}
|
|
|
|
static void
|
|
videoWindowResizeNotify (CompWindow *w,
|
|
int dx,
|
|
int dy,
|
|
int dwidth,
|
|
int dheight)
|
|
{
|
|
VIDEO_SCREEN (w->screen);
|
|
VIDEO_WINDOW (w);
|
|
|
|
if (vw->source)
|
|
updateWindowVideoContext (w, vw->source);
|
|
|
|
UNWRAP (vs, w->screen, windowResizeNotify);
|
|
(*w->screen->windowResizeNotify) (w, dx, dy, dwidth, dheight);
|
|
WRAP (vs, w->screen, windowResizeNotify, videoWindowResizeNotify);
|
|
}
|
|
|
|
static const CompMetadataOptionInfo videoDisplayOptionInfo[] = {
|
|
{ "yv12", "bool", 0, 0, 0 }
|
|
};
|
|
|
|
static Bool
|
|
videoInitDisplay (CompPlugin *p,
|
|
CompDisplay *d)
|
|
{
|
|
VideoDisplay *vd;
|
|
|
|
if (!checkPluginABI ("core", CORE_ABIVERSION))
|
|
return FALSE;
|
|
|
|
vd = malloc (sizeof (VideoDisplay));
|
|
if (!vd)
|
|
return FALSE;
|
|
|
|
if (!compInitDisplayOptionsFromMetadata (d,
|
|
&videoMetadata,
|
|
videoDisplayOptionInfo,
|
|
vd->opt,
|
|
VIDEO_DISPLAY_OPTION_NUM))
|
|
{
|
|
free (vd);
|
|
return FALSE;
|
|
}
|
|
|
|
vd->screenPrivateIndex = allocateScreenPrivateIndex (d);
|
|
if (vd->screenPrivateIndex < 0)
|
|
{
|
|
compFiniDisplayOptions (d, vd->opt, VIDEO_DISPLAY_OPTION_NUM);
|
|
free (vd);
|
|
return FALSE;
|
|
}
|
|
|
|
vd->textures = 0;
|
|
|
|
vd->videoAtom =
|
|
XInternAtom (d->display, "_COMPIZ_VIDEO", 0);
|
|
vd->videoSupportedAtom =
|
|
XInternAtom (d->display, "_COMPIZ_VIDEO_SUPPORTED", 0);
|
|
|
|
vd->videoImageFormatAtom[IMAGE_FORMAT_RGB] =
|
|
XInternAtom (d->display, "_COMPIZ_VIDEO_IMAGE_FORMAT_RGB", 0);
|
|
vd->videoImageFormatAtom[IMAGE_FORMAT_YV12] =
|
|
XInternAtom (d->display, "_COMPIZ_VIDEO_IMAGE_FORMAT_YV12", 0);
|
|
|
|
WRAP (vd, d, handleEvent, videoHandleEvent);
|
|
|
|
d->base.privates[displayPrivateIndex].ptr = vd;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
videoFiniDisplay (CompPlugin *p,
|
|
CompDisplay *d)
|
|
{
|
|
VIDEO_DISPLAY (d);
|
|
|
|
freeScreenPrivateIndex (d, vd->screenPrivateIndex);
|
|
|
|
UNWRAP (vd, d, handleEvent);
|
|
|
|
compFiniDisplayOptions (d, vd->opt, VIDEO_DISPLAY_OPTION_NUM);
|
|
|
|
free (vd);
|
|
}
|
|
|
|
static Bool
|
|
videoInitScreen (CompPlugin *p,
|
|
CompScreen *s)
|
|
{
|
|
VideoScreen *vs;
|
|
|
|
VIDEO_DISPLAY (s->display);
|
|
|
|
vs = malloc (sizeof (VideoScreen));
|
|
if (!vs)
|
|
return FALSE;
|
|
|
|
vs->windowPrivateIndex = allocateWindowPrivateIndex (s);
|
|
if (vs->windowPrivateIndex < 0)
|
|
{
|
|
free (vs);
|
|
return FALSE;
|
|
}
|
|
|
|
vs->yv12Functions = NULL;
|
|
|
|
memset (vs->imageFormat, 0, sizeof (vs->imageFormat));
|
|
|
|
vs->imageFormat[IMAGE_FORMAT_RGB] = TRUE;
|
|
if (s->fragmentProgram)
|
|
{
|
|
if (s->glxPixmapFBConfigs[8].fbConfig)
|
|
{
|
|
vs->imageFormat[IMAGE_FORMAT_YV12] = TRUE;
|
|
}
|
|
else
|
|
{
|
|
compLogMessage ("video", CompLogLevelWarn,
|
|
"No 8 bit GLX pixmap format, "
|
|
"disabling YV12 image format");
|
|
}
|
|
}
|
|
|
|
WRAP (vs, s, drawWindow, videoDrawWindow);
|
|
WRAP (vs, s, drawWindowTexture, videoDrawWindowTexture);
|
|
WRAP (vs, s, damageWindowRect, videoDamageWindowRect);
|
|
WRAP (vs, s, windowMoveNotify, videoWindowMoveNotify);
|
|
WRAP (vs, s, windowResizeNotify, videoWindowResizeNotify);
|
|
|
|
s->base.privates[vd->screenPrivateIndex].ptr = vs;
|
|
|
|
videoSetSupportedHint (s);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
videoFiniScreen (CompPlugin *p,
|
|
CompScreen *s)
|
|
{
|
|
VIDEO_DISPLAY (s->display);
|
|
VIDEO_SCREEN (s);
|
|
|
|
freeWindowPrivateIndex (s, vs->windowPrivateIndex);
|
|
|
|
XDeleteProperty (s->display->display, s->root, vd->videoSupportedAtom);
|
|
|
|
videoDestroyFragmentFunctions (s, &vs->yv12Functions);
|
|
|
|
UNWRAP (vs, s, drawWindow);
|
|
UNWRAP (vs, s, drawWindowTexture);
|
|
UNWRAP (vs, s, damageWindowRect);
|
|
UNWRAP (vs, s, windowMoveNotify);
|
|
UNWRAP (vs, s, windowResizeNotify);
|
|
|
|
free (vs);
|
|
}
|
|
|
|
static Bool
|
|
videoInitWindow (CompPlugin *p,
|
|
CompWindow *w)
|
|
{
|
|
VideoWindow *vw;
|
|
|
|
VIDEO_SCREEN (w->screen);
|
|
|
|
vw = malloc (sizeof (VideoWindow));
|
|
if (!vw)
|
|
return FALSE;
|
|
|
|
vw->source = NULL;
|
|
vw->context = NULL;
|
|
|
|
w->base.privates[vs->windowPrivateIndex].ptr = vw;
|
|
|
|
if (w->shaded || w->attrib.map_state == IsViewable)
|
|
videoWindowUpdate (w);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
videoFiniWindow (CompPlugin *p,
|
|
CompWindow *w)
|
|
{
|
|
VIDEO_WINDOW (w);
|
|
|
|
if (vw->source)
|
|
{
|
|
videoReleaseTexture (w->screen, vw->source->texture);
|
|
free (vw->source);
|
|
}
|
|
|
|
if (vw->context)
|
|
free (vw->context);
|
|
|
|
free (vw);
|
|
}
|
|
|
|
static CompBool
|
|
videoInitObject (CompPlugin *p,
|
|
CompObject *o)
|
|
{
|
|
static InitPluginObjectProc dispTab[] = {
|
|
(InitPluginObjectProc) 0, /* InitCore */
|
|
(InitPluginObjectProc) videoInitDisplay,
|
|
(InitPluginObjectProc) videoInitScreen,
|
|
(InitPluginObjectProc) videoInitWindow
|
|
};
|
|
|
|
RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
|
|
}
|
|
|
|
static void
|
|
videoFiniObject (CompPlugin *p,
|
|
CompObject *o)
|
|
{
|
|
static FiniPluginObjectProc dispTab[] = {
|
|
(FiniPluginObjectProc) 0, /* FiniCore */
|
|
(FiniPluginObjectProc) videoFiniDisplay,
|
|
(FiniPluginObjectProc) videoFiniScreen,
|
|
(FiniPluginObjectProc) videoFiniWindow
|
|
};
|
|
|
|
DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
|
|
}
|
|
|
|
static CompOption *
|
|
videoGetObjectOptions (CompPlugin *plugin,
|
|
CompObject *object,
|
|
int *count)
|
|
{
|
|
static GetPluginObjectOptionsProc dispTab[] = {
|
|
(GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
|
|
(GetPluginObjectOptionsProc) videoGetDisplayOptions
|
|
};
|
|
|
|
*count = 0;
|
|
RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
|
|
(void *) count, (plugin, object, count));
|
|
}
|
|
|
|
static CompBool
|
|
videoSetObjectOption (CompPlugin *plugin,
|
|
CompObject *object,
|
|
const char *name,
|
|
CompOptionValue *value)
|
|
{
|
|
static SetPluginObjectOptionProc dispTab[] = {
|
|
(SetPluginObjectOptionProc) 0, /* SetCoreOption */
|
|
(SetPluginObjectOptionProc) videoSetDisplayOption
|
|
};
|
|
|
|
RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
|
|
(plugin, object, name, value));
|
|
}
|
|
|
|
static Bool
|
|
videoInit (CompPlugin *p)
|
|
{
|
|
if (!compInitPluginMetadataFromInfo (&videoMetadata,
|
|
p->vTable->name,
|
|
videoDisplayOptionInfo,
|
|
VIDEO_DISPLAY_OPTION_NUM,
|
|
0, 0))
|
|
return FALSE;
|
|
|
|
displayPrivateIndex = allocateDisplayPrivateIndex ();
|
|
if (displayPrivateIndex < 0)
|
|
{
|
|
compFiniMetadata (&videoMetadata);
|
|
return FALSE;
|
|
}
|
|
|
|
compAddMetadataFromFile (&videoMetadata, p->vTable->name);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
videoFini (CompPlugin *p)
|
|
{
|
|
freeDisplayPrivateIndex (displayPrivateIndex);
|
|
compFiniMetadata (&videoMetadata);
|
|
}
|
|
|
|
static CompMetadata *
|
|
videoGetMetadata (CompPlugin *plugin)
|
|
{
|
|
return &videoMetadata;
|
|
}
|
|
|
|
static CompPluginVTable videoVTable = {
|
|
"video",
|
|
videoGetMetadata,
|
|
videoInit,
|
|
videoFini,
|
|
videoInitObject,
|
|
videoFiniObject,
|
|
videoGetObjectOptions,
|
|
videoSetObjectOption
|
|
};
|
|
|
|
CompPluginVTable *
|
|
getCompPluginInfo20070830 (void)
|
|
{
|
|
return &videoVTable;
|
|
}
|