xserver-multidpi/hw/xgl/xglpict.c
Aaron Plattner f2e310132f Add CreatePixmap allocation hints.
These hints allow an acceleration architecture to optimize allocation of certain
types of pixmaps, such as pixmaps that will serve as backing pixmaps for
redirected windows.
2007-11-04 16:11:28 -08:00

788 lines
20 KiB
C

/*
* Copyright © 2004 David Reveman
*
* 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
* David Reveman not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior permission.
* David Reveman makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*
* DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL DAVID REVEMAN 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 "xgl.h"
#include "fb.h"
#ifdef RENDER
#include "fbpict.h"
#define XGL_PICTURE_FALLBACK_PROLOGUE(pPicture, func) \
xglSyncDamageBoxBits (pPicture->pDrawable); \
XGL_PICTURE_SCREEN_UNWRAP (func)
#define XGL_PICTURE_FALLBACK_EPILOGUE(pPicture, func, xglfunc) \
XGL_PICTURE_SCREEN_WRAP (func, xglfunc); \
xglAddCurrentSurfaceDamage (pPicture->pDrawable)
void
xglComposite (CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
INT16 xSrc,
INT16 ySrc,
INT16 xMask,
INT16 yMask,
INT16 xDst,
INT16 yDst,
CARD16 width,
CARD16 height)
{
PictureScreenPtr pPictureScreen;
ScreenPtr pScreen = pDst->pDrawable->pScreen;
XGL_SCREEN_PRIV (pScreen);
if (xglCompositeGeneral (op,
pSrc, pMask, pDst, NULL,
xSrc, ySrc,
xMask, yMask,
xDst + pDst->pDrawable->x,
yDst + pDst->pDrawable->y,
width, height))
{
xglAddCurrentBitDamage (pDst->pDrawable);
return;
}
pPictureScreen = GetPictureScreen (pScreen);
if (pSrc->pDrawable)
{
if (!xglSyncBits (pSrc->pDrawable, NullBox))
FatalError (XGL_SW_FAILURE_STRING);
}
if (pMask && pMask->pDrawable)
{
if (!xglSyncBits (pMask->pDrawable, NullBox))
FatalError (XGL_SW_FAILURE_STRING);
}
if (op == PictOpSrc)
{
XGL_DRAWABLE_PIXMAP (pDst->pDrawable);
if (!xglMapPixmapBits (pPixmap))
FatalError (XGL_SW_FAILURE_STRING);
} else
xglSyncDamageBoxBits (pDst->pDrawable);
XGL_PICTURE_SCREEN_UNWRAP (Composite);
(*pPictureScreen->Composite) (op, pSrc, pMask, pDst,
xSrc, ySrc, xMask, yMask, xDst, yDst,
width, height);
XGL_PICTURE_SCREEN_WRAP (Composite, xglComposite);
if (op == PictOpSrc)
{
RegionRec region;
xDst += pDst->pDrawable->x;
yDst += pDst->pDrawable->y;
if (pSrc->pDrawable)
{
xSrc += pSrc->pDrawable->x;
ySrc += pSrc->pDrawable->y;
}
if (pMask && pMask->pDrawable)
{
xMask += pMask->pDrawable->x;
yMask += pMask->pDrawable->y;
}
if (!miComputeCompositeRegion (&region, pSrc, pMask, pDst,
xSrc, ySrc, xMask, yMask, xDst, yDst,
width, height))
return;
xglAddSurfaceDamage (pDst->pDrawable, &region);
REGION_UNINIT (pDst->pDrawable->pScreen, &region);
} else
xglAddCurrentSurfaceDamage (pDst->pDrawable);
}
void
xglAddTriangles (PicturePtr pDst,
INT16 xOff,
INT16 yOff,
int ntri,
xTriangle *tris)
{
PictureScreenPtr pPictureScreen;
ScreenPtr pScreen = pDst->pDrawable->pScreen;
XGL_SCREEN_PRIV (pScreen);
XGL_DRAWABLE_PIXMAP_PRIV (pDst->pDrawable);
pPictureScreen = GetPictureScreen (pScreen);
pPixmapPriv->damageBox.x1 = 0;
pPixmapPriv->damageBox.y1 = 0;
pPixmapPriv->damageBox.x2 = pDst->pDrawable->width;
pPixmapPriv->damageBox.y2 = pDst->pDrawable->height;
XGL_PICTURE_FALLBACK_PROLOGUE (pDst, AddTriangles);
(*pPictureScreen->AddTriangles) (pDst, xOff, yOff, ntri, tris);
XGL_PICTURE_FALLBACK_EPILOGUE (pDst, AddTriangles, xglAddTriangles);
}
void
xglChangePicture (PicturePtr pPicture,
Mask mask)
{
PictureScreenPtr pPictureScreen;
ScreenPtr pScreen = pPicture->pDrawable->pScreen;
XGL_SCREEN_PRIV (pScreen);
XGL_DRAWABLE_PIXMAP_PRIV (pPicture->pDrawable);
pPictureScreen = GetPictureScreen (pScreen);
if (pPicture->stateChanges & CPRepeat)
pPixmapPriv->pictureMask |= xglPCFillMask;
if (pPicture->stateChanges & CPComponentAlpha)
pPixmapPriv->pictureMask |= xglPCComponentAlphaMask;
if (pPicture->stateChanges & CPDither)
pPixmapPriv->pictureMask |= xglPCDitherMask;
XGL_PICTURE_SCREEN_UNWRAP (ChangePicture);
(*pPictureScreen->ChangePicture) (pPicture, mask);
XGL_PICTURE_SCREEN_WRAP (ChangePicture, xglChangePicture);
}
int
xglChangePictureTransform (PicturePtr pPicture,
PictTransform *transform)
{
PictureScreenPtr pPictureScreen;
ScreenPtr pScreen = pPicture->pDrawable->pScreen;
int ret;
XGL_SCREEN_PRIV (pScreen);
XGL_DRAWABLE_PIXMAP_PRIV (pPicture->pDrawable);
pPictureScreen = GetPictureScreen (pScreen);
if (transform != pPicture->transform ||
(transform && memcmp (transform, &pPicture->transform,
sizeof (PictTransform))))
pPixmapPriv->pictureMask |= xglPCTransformMask;
XGL_PICTURE_SCREEN_UNWRAP (ChangePictureTransform);
ret = (*pPictureScreen->ChangePictureTransform) (pPicture, transform);
XGL_PICTURE_SCREEN_WRAP (ChangePictureTransform,
xglChangePictureTransform);
return ret;
}
int
xglChangePictureFilter (PicturePtr pPicture,
int filter,
xFixed *params,
int nparams)
{
PictureScreenPtr pPictureScreen;
ScreenPtr pScreen = pPicture->pDrawable->pScreen;
int ret;
XGL_SCREEN_PRIV (pScreen);
XGL_DRAWABLE_PIXMAP_PRIV (pPicture->pDrawable);
pPictureScreen = GetPictureScreen (pScreen);
pPixmapPriv->pictureMask |= xglPCFilterMask;
XGL_PICTURE_SCREEN_UNWRAP (ChangePictureFilter);
ret = (*pPictureScreen->ChangePictureFilter) (pPicture, filter,
params, nparams);
XGL_PICTURE_SCREEN_WRAP (ChangePictureFilter, xglChangePictureFilter);
return ret;
}
static void
xglDestroyDevicePicture (PicturePtr pPicture)
{
if (pPicture->pSourcePict->source.devPrivate.ptr)
glitz_surface_destroy (pPicture->pSourcePict->source.devPrivate.ptr);
}
PicturePtr
xglCreateDevicePicture (pointer data)
{
PicturePtr pPicture;
int error;
pPicture = CreateDevicePicture (0, &error);
if (!pPicture)
return 0;
pPicture->pSourcePict->source.devPrivate.ptr = data;
pPicture->pSourcePict->source.Destroy = xglDestroyDevicePicture;
return pPicture;
}
static int fillMode[] = {
GLITZ_FILL_TRANSPARENT, /* RepeatNone */
GLITZ_FILL_REPEAT, /* RepeatNormal */
GLITZ_FILL_NEAREST, /* RepeatPad */
GLITZ_FILL_REFLECT /* RepeatReflect */
};
static void
xglUpdatePicture (PicturePtr pPicture)
{
glitz_surface_t *surface;
XGL_DRAWABLE_PIXMAP_PRIV (pPicture->pDrawable);
surface = pPixmapPriv->surface;
if (pPixmapPriv->pictureMask & xglPCFillMask)
{
glitz_surface_set_fill (surface, fillMode[pPicture->repeat]);
}
if (pPixmapPriv->pictureMask & xglPCFilterMask)
{
switch (pPicture->filter) {
case PictFilterNearest:
case PictFilterFast:
glitz_surface_set_filter (surface, GLITZ_FILTER_NEAREST, NULL, 0);
break;
case PictFilterGood:
case PictFilterBest:
case PictFilterBilinear:
glitz_surface_set_filter (surface, GLITZ_FILTER_BILINEAR, NULL, 0);
break;
case PictFilterConvolution:
glitz_surface_set_filter (surface, GLITZ_FILTER_CONVOLUTION,
(glitz_fixed16_16_t *)
pPicture->filter_params,
pPicture->filter_nparams);
break;
}
}
if (pPixmapPriv->pictureMask & xglPCTransformMask)
{
glitz_surface_set_transform (surface, (glitz_transform_t *)
pPicture->transform);
}
if (pPixmapPriv->pictureMask & xglPCComponentAlphaMask)
{
glitz_surface_set_component_alpha (surface, pPicture->componentAlpha);
}
if (pPixmapPriv->pictureMask & xglPCDitherMask)
{
glitz_surface_set_dither (surface, pPicture->dither);
}
pPixmapPriv->pictureMask &= ~XGL_PICTURE_CHANGES (~0);
}
#define N_STACK_PARAM 256
static int gradientNParam[] = {
0, /* SourcePictTypeSolidFill */
4, /* SourcePictTypeLinear */
6, /* SourcePictTypeRadial */
4, /* SourcePictTypeConical */
};
Bool
xglSyncPicture (ScreenPtr pScreen,
PicturePtr pPicture,
INT16 x,
INT16 y,
CARD16 width,
CARD16 height,
INT16 *xOff,
INT16 *yOff)
{
xglPixmapPtr pPixmapPriv;
XGL_SCREEN_PRIV (pScreen);
*xOff = *yOff = 0;
if (pPicture->pSourcePict)
{
if (pPicture->pSourcePict->source.devPrivate.ptr)
return TRUE;
if (pPicture->pDrawable)
{
(*pScreen->DestroyPixmap) ((PixmapPtr) pPicture->pDrawable);
pPicture->pDrawable = (DrawablePtr) 0;
}
switch (pPicture->pSourcePict->source.type) {
case SourcePictTypeSolidFill:
x = y = 0;
width = height = 1;
break;
case SourcePictTypeLinear:
case SourcePictTypeRadial: {
glitz_fixed16_16_t stackParam[N_STACK_PARAM];
glitz_fixed16_16_t *param;
int nParam, nStop, size, i;
CARD32 *pixel;
PictGradientStopPtr pStop;
glitz_buffer_t *buffer;
glitz_format_t *format;
glitz_surface_t *surface;
static glitz_pixel_format_t pixelFormat = {
GLITZ_FOURCC_RGB,
{
32,
0xff000000,
0x00ff0000,
0x0000ff00,
0x000000ff
},
0, 0, 0,
GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP
};
if (!(pScreenPriv->features & GLITZ_FEATURE_FRAGMENT_PROGRAM_MASK))
break;
format = glitz_find_standard_format (pScreenPriv->drawable,
GLITZ_STANDARD_ARGB32);
if (!format)
break;
nParam = gradientNParam[pPicture->pSourcePict->gradient.type];
pStop = pPicture->pSourcePict->gradient.stops;
nStop = pPicture->pSourcePict->gradient.nstops;
size = nParam + nStop * 4;
if (size > N_STACK_PARAM)
{
param = malloc (sizeof (xFixed) * size);
if (!param)
break;
}
else
{
param = stackParam;
}
pixel = (CARD32 *) (param + nParam + nStop * 3);
buffer = glitz_buffer_create_for_data (pixel);
if (!buffer)
{
if (size > N_STACK_PARAM)
free (param);
break;
}
surface = glitz_surface_create (pScreenPriv->drawable,
format, nStop, 1, 0, NULL);
if (!surface)
{
glitz_buffer_destroy (buffer);
if (size > N_STACK_PARAM)
free (param);
break;
}
for (i = 0; i < nStop; i++)
{
pixel[i] = pStop[i].color;
param[nParam + 3 * i + 0] = pStop[i].x;
param[nParam + 3 * i + 1] = i << 16;
param[nParam + 3 * i + 2] = 0;
}
glitz_set_pixels (surface, 0, 0, nStop, 1, &pixelFormat, buffer);
glitz_buffer_destroy (buffer);
switch (pPicture->pSourcePict->source.type) {
case SourcePictTypeLinear:
param[0] = pPicture->pSourcePict->linear.p1.x;
param[1] = pPicture->pSourcePict->linear.p1.y;
param[2] = pPicture->pSourcePict->linear.p2.x;
param[3] = pPicture->pSourcePict->linear.p2.y;
glitz_surface_set_filter (surface,
GLITZ_FILTER_LINEAR_GRADIENT,
param, nParam + nStop * 3);
break;
case SourcePictTypeRadial:
param[0] = pPicture->pSourcePict->radial.inner.x;
param[1] = pPicture->pSourcePict->radial.inner.y;
param[2] = pPicture->pSourcePict->radial.inner_radius;
param[3] = pPicture->pSourcePict->radial.outer.x;
param[4] = pPicture->pSourcePict->radial.outer.y;
param[5] = pPicture->pSourcePict->radial.outer_radius;
glitz_surface_set_filter (surface,
GLITZ_FILTER_RADIAL_GRADIENT,
param, nParam + nStop * 3);
break;
}
glitz_surface_set_fill (surface, fillMode[pPicture->repeat]);
glitz_surface_set_transform (surface, (glitz_transform_t *)
pPicture->transform);
pPicture->pSourcePict->gradient.devPrivate.ptr = surface;
pPicture->pSourcePict->gradient.Destroy = xglDestroyDevicePicture;
if (size > N_STACK_PARAM)
free (param);
return TRUE;
} break;
case SourcePictTypeConical:
default:
break;
}
if (!pPicture->pDrawable)
{
PictFormatPtr pFormat;
PixmapPtr pPixmap;
PicturePtr pTmp;
RegionRec region;
BoxRec box;
int error;
pFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8);
if (!pFormat)
return FALSE;
pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
pFormat->depth, 0);
if (!pPixmap)
return FALSE;
pTmp = CreatePicture (0, &pPixmap->drawable, pFormat, 0, NULL,
serverClient, &error);
if (!pTmp)
{
(*pScreen->DestroyPixmap) (pPixmap);
return FALSE;
}
ValidatePicture (pTmp);
if (!xglSyncBits (pTmp->pDrawable, NullBox))
FatalError (XGL_SW_FAILURE_STRING);
fbCompositeGeneral (PictOpSrc,
pPicture, 0, pTmp,
x, y, 0, 0, 0, 0,
width, height);
FreePicture ((pointer) pTmp, (XID) 0);
box.x1 = 0;
box.y1 = 0;
box.x2 = width;
box.y2 = height;
REGION_INIT (pScreen, &region, &box, 1);
xglAddSurfaceDamage (&pPixmap->drawable, &region);
REGION_UNINIT (pDrawable->pScreen, &region);
pPicture->pDrawable = &pPixmap->drawable;
*xOff = x;
*yOff = y;
XGL_GET_PIXMAP_PRIV (pPixmap)->pictureMask &=
~(xglPCFillMask | xglPCFilterMask | xglPCTransformMask);
}
}
#ifdef XV
switch (pPicture->format) {
case PICT_yuy2:
xglSetPixmapVisual ((PixmapPtr) pPicture->pDrawable,
&pScreenPriv->pXvVisual[XGL_XV_FORMAT_YUY2]);
break;
case PICT_yv12:
xglSetPixmapVisual ((PixmapPtr) pPicture->pDrawable,
&pScreenPriv->pXvVisual[XGL_XV_FORMAT_YV12]);
default:
break;
}
#endif
if (!xglSyncSurface (pPicture->pDrawable))
return FALSE;
pPixmapPriv = XGL_GET_PIXMAP_PRIV ((PixmapPtr) pPicture->pDrawable);
if (XGL_PICTURE_CHANGES (pPixmapPriv->pictureMask))
xglUpdatePicture (pPicture);
return TRUE;
}
static int
xglVisualDepth (ScreenPtr pScreen, VisualPtr pVisual)
{
DepthPtr pDepth;
int d, v;
for (d = 0; d < pScreen->numDepths; d++)
{
pDepth = &pScreen->allowedDepths[d];
for (v = 0; v < pDepth->numVids; v++)
if (pDepth->vids[v] == pVisual->vid)
return pDepth->depth;
}
return 0;
}
typedef struct _xglformatInit {
CARD32 format;
CARD8 depth;
} xglFormatInitRec, *xglFormatInitPtr;
static int
xglAddFormat (xglFormatInitPtr formats,
int nformat,
CARD32 format,
CARD8 depth)
{
int n;
for (n = 0; n < nformat; n++)
if (formats[n].format == format && formats[n].depth == depth)
return nformat;
formats[nformat].format = format;
formats[nformat].depth = depth;
return ++nformat;
}
#define Mask(n) ((n) == 32 ? 0xffffffff : ((1 << (n)) - 1))
Bool
xglPictureInit (ScreenPtr pScreen)
{
int f, nformats = 0;
PictFormatPtr pFormats;
xglFormatInitRec formats[64];
CARD32 format;
CARD8 depth;
VisualPtr pVisual;
int v;
int bpp;
int r, g, b;
int d;
DepthPtr pDepth;
/* formats required by protocol */
formats[nformats].format = PICT_a1;
formats[nformats].depth = 1;
nformats++;
formats[nformats].format = PICT_a4;
formats[nformats].depth = 4;
nformats++;
formats[nformats].format = PICT_a8;
formats[nformats].depth = 8;
nformats++;
formats[nformats].format = PICT_a8r8g8b8;
formats[nformats].depth = 32;
nformats++;
/* now look through the depths and visuals adding other formats */
for (v = 0; v < pScreen->numVisuals; v++)
{
pVisual = &pScreen->visuals[v];
depth = xglVisualDepth (pScreen, pVisual);
if (!depth)
continue;
bpp = BitsPerPixel (depth);
switch (pVisual->class) {
case DirectColor:
case TrueColor:
r = Ones (pVisual->redMask);
g = Ones (pVisual->greenMask);
b = Ones (pVisual->blueMask);
if (pVisual->offsetBlue == 0 &&
pVisual->offsetGreen == b &&
pVisual->offsetRed == b + g)
{
format = PICT_FORMAT (bpp, PICT_TYPE_ARGB, 0, r, g, b);
nformats = xglAddFormat (formats, nformats, format, depth);
}
break;
case StaticColor:
case PseudoColor:
case StaticGray:
case GrayScale:
break;
}
}
/* walk supported depths and add missing Direct formats */
for (d = 0; d < pScreen->numDepths; d++)
{
pDepth = &pScreen->allowedDepths[d];
bpp = BitsPerPixel (pDepth->depth);
format = 0;
switch (bpp) {
case 16:
if (pDepth->depth == 15)
nformats = xglAddFormat (formats, nformats,
PICT_x1r5g5b5, pDepth->depth);
if (pDepth->depth == 16)
nformats = xglAddFormat (formats, nformats,
PICT_r5g6b5, pDepth->depth);
break;
case 24:
if (pDepth->depth == 24)
nformats = xglAddFormat (formats, nformats,
PICT_r8g8b8, pDepth->depth);
break;
case 32:
if (pDepth->depth == 24)
nformats = xglAddFormat (formats, nformats,
PICT_x8r8g8b8, pDepth->depth);
break;
}
}
/* add YUV formats */
nformats = xglAddFormat (formats, nformats, PICT_yuy2, 16);
nformats = xglAddFormat (formats, nformats, PICT_yv12, 12);
pFormats = (PictFormatPtr) xalloc (nformats * sizeof (PictFormatRec));
if (!pFormats)
return 0;
memset (pFormats, '\0', nformats * sizeof (PictFormatRec));
for (f = 0; f < nformats; f++)
{
pFormats[f].id = FakeClientID (0);
pFormats[f].depth = formats[f].depth;
format = formats[f].format;
pFormats[f].format = format;
switch (PICT_FORMAT_TYPE (format)) {
case PICT_TYPE_ARGB:
pFormats[f].type = PictTypeDirect;
pFormats[f].direct.alphaMask = Mask (PICT_FORMAT_A (format));
if (pFormats[f].direct.alphaMask)
pFormats[f].direct.alpha = (PICT_FORMAT_R (format) +
PICT_FORMAT_G (format) +
PICT_FORMAT_B (format));
pFormats[f].direct.redMask = Mask (PICT_FORMAT_R (format));
pFormats[f].direct.red = (PICT_FORMAT_G (format) +
PICT_FORMAT_B (format));
pFormats[f].direct.greenMask = Mask (PICT_FORMAT_G (format));
pFormats[f].direct.green = PICT_FORMAT_B (format);
pFormats[f].direct.blueMask = Mask (PICT_FORMAT_B (format));
pFormats[f].direct.blue = 0;
break;
case PICT_TYPE_A:
pFormats[f].type = PictTypeDirect;
pFormats[f].direct.alpha = 0;
pFormats[f].direct.alphaMask = Mask (PICT_FORMAT_A (format));
break;
case PICT_TYPE_COLOR:
case PICT_TYPE_GRAY:
pFormats[f].type = PictTypeDirect;
break;
case PICT_TYPE_YUY2:
case PICT_TYPE_YV12:
pFormats[f].type = PictTypeOther;
break;
}
}
if (!fbPictureInit (pScreen, pFormats, nformats))
return FALSE;
return TRUE;
}
void
xglPictureClipExtents (PicturePtr pPicture,
BoxPtr extents)
{
if (pPicture->clientClipType != CT_NONE)
{
BoxPtr clip = REGION_EXTENTS (pPicture->pDrawable->pScreen,
(RegionPtr) pPicture->clientClip);
if (extents->x1 < pPicture->clipOrigin.x + clip->x1)
extents->x1 = pPicture->clipOrigin.x + clip->x1;
if (extents->y1 < pPicture->clipOrigin.y + clip->y1)
extents->y1 = pPicture->clipOrigin.y + clip->y1;
if (extents->x2 > pPicture->clipOrigin.x + clip->x2)
extents->x2 = pPicture->clipOrigin.x + clip->x2;
if (extents->y2 > pPicture->clipOrigin.y + clip->y2)
extents->y2 = pPicture->clipOrigin.y + clip->y2;
}
else
{
if (extents->x1 < 0)
extents->x1 = 0;
if (extents->y1 < 0)
extents->y1 = 0;
if (extents->x2 > pPicture->pDrawable->width)
extents->x2 = pPicture->pDrawable->width;
if (extents->y2 > pPicture->pDrawable->height)
extents->y2 = pPicture->pDrawable->height;
}
}
#endif