diff options
Diffstat (limited to 'xorg-server/hw/dmx/dmxpict.c')
-rw-r--r-- | xorg-server/hw/dmx/dmxpict.c | 1315 |
1 files changed, 1315 insertions, 0 deletions
diff --git a/xorg-server/hw/dmx/dmxpict.c b/xorg-server/hw/dmx/dmxpict.c new file mode 100644 index 000000000..37dfa10ac --- /dev/null +++ b/xorg-server/hw/dmx/dmxpict.c @@ -0,0 +1,1315 @@ +/* + * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Authors: + * Kevin E. Martin <kem@redhat.com> + * + */ + +/** \file + * Provide support for the RENDER extension (version 0.8). + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxpict.h" +#include "dmxwindow.h" +#include "dmxpixmap.h" + +#include "fb.h" +#include "pixmapstr.h" +#include "dixstruct.h" + +#include <X11/extensions/render.h> +#include <X11/extensions/renderproto.h> +#include "picture.h" +#include "picturestr.h" +#include "mipict.h" +#include "fbpict.h" + + +extern int RenderErrBase; +extern int (*ProcRenderVector[RenderNumberRequests])(ClientPtr); + +static int (*dmxSaveRenderVector[RenderNumberRequests])(ClientPtr); + + +static int dmxProcRenderCreateGlyphSet(ClientPtr client); +static int dmxProcRenderFreeGlyphSet(ClientPtr client); +static int dmxProcRenderAddGlyphs(ClientPtr client); +static int dmxProcRenderFreeGlyphs(ClientPtr client); +static int dmxProcRenderCompositeGlyphs(ClientPtr client); +static int dmxProcRenderSetPictureTransform(ClientPtr client); +static int dmxProcRenderSetPictureFilter(ClientPtr client); +#if 0 +/* FIXME: Not (yet) supported */ +static int dmxProcRenderCreateCursor(ClientPtr client); +static int dmxProcRenderCreateAnimCursor(ClientPtr client); +#endif + +/** Catch errors that might occur when allocating Glyph Sets. Errors + * are saved in dmxGlyphLastError for later handling. */ +static int dmxGlyphLastError; +static int dmxGlyphErrorHandler(Display *dpy, XErrorEvent *ev) +{ + dmxGlyphLastError = ev->error_code; + return 0; +} + + +/** Initialize the Proc Vector for the RENDER extension. The functions + * here cannot be handled by the mi layer RENDER hooks either because + * the required information is no longer available when it reaches the + * mi layer or no mi layer hooks exist. This function is called from + * InitOutput() since it should be initialized only once per server + * generation. */ +void dmxInitRender(void) +{ + int i; + + for (i = 0; i < RenderNumberRequests; i++) + dmxSaveRenderVector[i] = ProcRenderVector[i]; + + ProcRenderVector[X_RenderCreateGlyphSet] + = dmxProcRenderCreateGlyphSet; + ProcRenderVector[X_RenderFreeGlyphSet] + = dmxProcRenderFreeGlyphSet; + ProcRenderVector[X_RenderAddGlyphs] + = dmxProcRenderAddGlyphs; + ProcRenderVector[X_RenderFreeGlyphs] + = dmxProcRenderFreeGlyphs; + ProcRenderVector[X_RenderCompositeGlyphs8] + = dmxProcRenderCompositeGlyphs; + ProcRenderVector[X_RenderCompositeGlyphs16] + = dmxProcRenderCompositeGlyphs; + ProcRenderVector[X_RenderCompositeGlyphs32] + = dmxProcRenderCompositeGlyphs; + ProcRenderVector[X_RenderSetPictureTransform] + = dmxProcRenderSetPictureTransform; + ProcRenderVector[X_RenderSetPictureFilter] + = dmxProcRenderSetPictureFilter; +} + +/** Reset the Proc Vector for the RENDER extension back to the original + * functions. This function is called from dmxCloseScreen() during the + * server reset (only for screen #0). */ +void dmxResetRender(void) +{ + int i; + + for (i = 0; i < RenderNumberRequests; i++) + ProcRenderVector[i] = dmxSaveRenderVector[i]; +} + +/** Initialize the RENDER extension, allocate the picture privates and + * wrap mi function hooks. If the shadow frame buffer is used, then + * call the appropriate fb initialization function. */ +Bool dmxPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + PictureScreenPtr ps; + + /* The shadow framebuffer only relies on FB to be initialized */ + if (dmxShadowFB) return fbPictureInit(pScreen, formats, nformats); + + if (!miPictureInit(pScreen, formats, nformats)) + return FALSE; + + if (!dixRequestPrivate(dmxPictPrivateKey, sizeof(dmxPictPrivRec))) + return FALSE; + + ps = GetPictureScreen(pScreen); + + DMX_WRAP(CreatePicture, dmxCreatePicture, dmxScreen, ps); + DMX_WRAP(DestroyPicture, dmxDestroyPicture, dmxScreen, ps); + + DMX_WRAP(ChangePictureClip, dmxChangePictureClip, dmxScreen, ps); + DMX_WRAP(DestroyPictureClip, dmxDestroyPictureClip, dmxScreen, ps); + + DMX_WRAP(ChangePicture, dmxChangePicture, dmxScreen, ps); + DMX_WRAP(ValidatePicture, dmxValidatePicture, dmxScreen, ps); + + DMX_WRAP(Composite, dmxComposite, dmxScreen, ps); + DMX_WRAP(Glyphs, dmxGlyphs, dmxScreen, ps); + DMX_WRAP(CompositeRects, dmxCompositeRects, dmxScreen, ps); + + DMX_WRAP(Trapezoids, dmxTrapezoids, dmxScreen, ps); + DMX_WRAP(Triangles, dmxTriangles, dmxScreen, ps); + DMX_WRAP(TriStrip, dmxTriStrip, dmxScreen, ps); + DMX_WRAP(TriFan, dmxTriFan, dmxScreen, ps); + + return TRUE; +} + + +/** Find the appropriate format on the requested screen given the + * internal format requested. The list of formats is searched + * sequentially as the XRenderFindFormat() function does not always + * find the appropriate format when a specific format is requested. */ +static XRenderPictFormat *dmxFindFormat(DMXScreenInfo *dmxScreen, + PictFormatPtr pFmt) +{ + XRenderPictFormat *pFormat = NULL; + int i = 0; + + if (!pFmt || !dmxScreen->beDisplay) return pFormat; + + while (1) { + pFormat = XRenderFindFormat(dmxScreen->beDisplay, 0, 0, i++); + if (!pFormat) break; + + if (pFormat->type != pFmt->type) continue; + if (pFormat->depth != pFmt->depth) continue; + if (pFormat->direct.red != pFmt->direct.red) continue; + if (pFormat->direct.redMask != pFmt->direct.redMask) continue; + if (pFormat->direct.green != pFmt->direct.green) continue; + if (pFormat->direct.greenMask != pFmt->direct.greenMask) continue; + if (pFormat->direct.blue != pFmt->direct.blue) continue; + if (pFormat->direct.blueMask != pFmt->direct.blueMask) continue; + if (pFormat->direct.alpha != pFmt->direct.alpha) continue; + if (pFormat->direct.alphaMask != pFmt->direct.alphaMask) continue; + + /* We have a match! */ + break; + } + + return pFormat; +} + +/** Free \a glyphSet on back-end screen number \a idx. */ +Bool dmxBEFreeGlyphSet(ScreenPtr pScreen, GlyphSetPtr glyphSet) +{ + dmxGlyphPrivPtr glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet); + int idx = pScreen->myNum; + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + + if (glyphPriv->glyphSets[idx]) { + XRenderFreeGlyphSet(dmxScreen->beDisplay, glyphPriv->glyphSets[idx]); + glyphPriv->glyphSets[idx] = (GlyphSet)0; + return TRUE; + } + + return FALSE; +} + +/** Create \a glyphSet on the backend screen number \a idx. */ +int dmxBECreateGlyphSet(int idx, GlyphSetPtr glyphSet) +{ + XRenderPictFormat *pFormat; + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + dmxGlyphPrivPtr glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet); + PictFormatPtr pFmt = glyphSet->format; + int (*oldErrorHandler)(Display *, XErrorEvent *); + + pFormat = dmxFindFormat(dmxScreen, pFmt); + if (!pFormat) { + return BadMatch; + } + + dmxGlyphLastError = 0; + oldErrorHandler = XSetErrorHandler(dmxGlyphErrorHandler); + + /* Catch when this fails */ + glyphPriv->glyphSets[idx] + = XRenderCreateGlyphSet(dmxScreen->beDisplay, pFormat); + + XSetErrorHandler(oldErrorHandler); + + if (dmxGlyphLastError) { + return dmxGlyphLastError; + } + + return Success; +} + +/** Create a Glyph Set on each screen. Save the glyphset ID from each + * screen in the Glyph Set's private structure. Fail if the format + * requested is not available or if the Glyph Set cannot be created on + * the screen. */ +static int dmxProcRenderCreateGlyphSet(ClientPtr client) +{ + int ret; + REQUEST(xRenderCreateGlyphSetReq); + + ret = dmxSaveRenderVector[stuff->renderReqType](client); + + if (ret == Success) { + GlyphSetPtr glyphSet; + dmxGlyphPrivPtr glyphPriv; + int i; + + /* Look up glyphSet that was just created ???? */ + /* Store glyphsets from backends in glyphSet->devPrivate ????? */ + /* Make sure we handle all errors here!! */ + + glyphSet = SecurityLookupIDByType(client, stuff->gsid, GlyphSetType, + DixDestroyAccess); + glyphPriv = xalloc(sizeof(dmxGlyphPrivRec)); + if (!glyphPriv) return BadAlloc; + glyphPriv->glyphSets = NULL; + MAXSCREENSALLOC_RETURN(glyphPriv->glyphSets, BadAlloc); + DMX_SET_GLYPH_PRIV(glyphSet, glyphPriv); + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + int beret; + + if (!dmxScreen->beDisplay) { + glyphPriv->glyphSets[i] = 0; + continue; + } + + if ((beret = dmxBECreateGlyphSet(i, glyphSet)) != Success) { + int j; + + /* Free the glyph sets we've allocated thus far */ + for (j = 0; j < i; j++) + dmxBEFreeGlyphSet(screenInfo.screens[j], glyphSet); + + /* Free the resource created by render */ + FreeResource(stuff->gsid, RT_NONE); + + return beret; + } + } + } + + return ret; +} + +/** Free the previously allocated Glyph Sets for each screen. */ +static int dmxProcRenderFreeGlyphSet(ClientPtr client) +{ + GlyphSetPtr glyphSet; + REQUEST(xRenderFreeGlyphSetReq); + + REQUEST_SIZE_MATCH(xRenderFreeGlyphSetReq); + glyphSet = SecurityLookupIDByType(client, stuff->glyphset, GlyphSetType, + DixDestroyAccess); + + if (glyphSet && glyphSet->refcnt == 1) { + dmxGlyphPrivPtr glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet); + int i; + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (dmxScreen->beDisplay) { + if (dmxBEFreeGlyphSet(screenInfo.screens[i], glyphSet)) + dmxSync(dmxScreen, FALSE); + } + } + + MAXSCREENSFREE(glyphPriv->glyphSets); + xfree(glyphPriv); + DMX_SET_GLYPH_PRIV(glyphSet, NULL); + } + + return dmxSaveRenderVector[stuff->renderReqType](client); +} + +/** Add glyphs to the Glyph Set on each screen. */ +static int dmxProcRenderAddGlyphs(ClientPtr client) +{ + int ret; + REQUEST(xRenderAddGlyphsReq); + + ret = dmxSaveRenderVector[stuff->renderReqType](client); + + if (ret == Success) { + GlyphSetPtr glyphSet; + dmxGlyphPrivPtr glyphPriv; + int i; + int nglyphs; + CARD32 *gids; + Glyph *gidsCopy; + xGlyphInfo *gi; + CARD8 *bits; + int nbytes; + + glyphSet = SecurityLookupIDByType(client, stuff->glyphset, + GlyphSetType, DixReadAccess); + glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet); + + nglyphs = stuff->nglyphs; + gids = (CARD32 *)(stuff + 1); + gi = (xGlyphInfo *)(gids + nglyphs); + bits = (CARD8 *)(gi + nglyphs); + nbytes = ((stuff->length << 2) - + sizeof(xRenderAddGlyphsReq) - + (sizeof(CARD32) + sizeof(xGlyphInfo)) * nglyphs); + + gidsCopy = xalloc(sizeof(*gidsCopy) * nglyphs); + for (i = 0; i < nglyphs; i++) gidsCopy[i] = gids[i]; + + /* FIXME: Will this ever fail? */ + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (dmxScreen->beDisplay) { + XRenderAddGlyphs(dmxScreen->beDisplay, + glyphPriv->glyphSets[i], + gidsCopy, + (XGlyphInfo *)gi, + nglyphs, + (char *)bits, + nbytes); + dmxSync(dmxScreen, FALSE); + } + } + xfree(gidsCopy); + } + + return ret; +} + +/** Free glyphs from the Glyph Set for each screen. */ +static int dmxProcRenderFreeGlyphs(ClientPtr client) +{ + GlyphSetPtr glyphSet; + REQUEST(xRenderFreeGlyphsReq); + + REQUEST_AT_LEAST_SIZE(xRenderFreeGlyphsReq); + glyphSet = SecurityLookupIDByType(client, stuff->glyphset, GlyphSetType, + DixWriteAccess); + + if (glyphSet) { + dmxGlyphPrivPtr glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet); + int i; + int nglyphs; + Glyph *gids; + + nglyphs = ((client->req_len << 2) - sizeof(xRenderFreeGlyphsReq)) >> 2; + if (nglyphs) { + gids = xalloc(sizeof(*gids) * nglyphs); + for (i = 0; i < nglyphs; i++) + gids[i] = ((CARD32 *)(stuff + 1))[i]; + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (dmxScreen->beDisplay) { + XRenderFreeGlyphs(dmxScreen->beDisplay, + glyphPriv->glyphSets[i], gids, nglyphs); + dmxSync(dmxScreen, FALSE); + } + } + xfree(gids); + } + } + + return dmxSaveRenderVector[stuff->renderReqType](client); +} + +/** Composite glyphs on each screen into the requested picture. If + * either the src or dest picture has not been allocated due to lazy + * window creation, this request will gracefully return. */ +static int dmxProcRenderCompositeGlyphs(ClientPtr client) +{ + int ret; + REQUEST(xRenderCompositeGlyphsReq); + + ret = dmxSaveRenderVector[stuff->renderReqType](client); + + /* For the following to work with PanoramiX, it assumes that Render + * wraps the ProcRenderVector after dmxRenderInit has been called. + */ + if (ret == Success) { + PicturePtr pSrc; + dmxPictPrivPtr pSrcPriv; + PicturePtr pDst; + dmxPictPrivPtr pDstPriv; + PictFormatPtr pFmt; + XRenderPictFormat *pFormat; + int size; + + int scrnNum; + DMXScreenInfo *dmxScreen; + + CARD8 *buffer; + CARD8 *end; + int space; + + int nglyph; + char *glyphs; + char *curGlyph; + + xGlyphElt *elt; + int nelt; + XGlyphElt8 *elts; + XGlyphElt8 *curElt; + + GlyphSetPtr glyphSet; + dmxGlyphPrivPtr glyphPriv; + + pSrc = SecurityLookupIDByType(client, stuff->src, PictureType, + DixReadAccess); + pSrcPriv = DMX_GET_PICT_PRIV(pSrc); + if (!pSrcPriv->pict) + return ret; + + pDst = SecurityLookupIDByType(client, stuff->dst, PictureType, + DixWriteAccess); + pDstPriv = DMX_GET_PICT_PRIV(pDst); + if (!pDstPriv->pict) + return ret; + + scrnNum = pDst->pDrawable->pScreen->myNum; + dmxScreen = &dmxScreens[scrnNum]; + + /* Note: If the back-end display has been detached, then it + * should not be possible to reach here since the pSrcPriv->pict + * and pDstPriv->pict will have already been set to 0. + */ + if (!dmxScreen->beDisplay) + return ret; + + if (stuff->maskFormat) + pFmt = SecurityLookupIDByType(client, stuff->maskFormat, + PictFormatType, DixReadAccess); + else + pFmt = NULL; + + pFormat = dmxFindFormat(dmxScreen, pFmt); + + switch (stuff->renderReqType) { + case X_RenderCompositeGlyphs8: size = sizeof(CARD8); break; + case X_RenderCompositeGlyphs16: size = sizeof(CARD16); break; + case X_RenderCompositeGlyphs32: size = sizeof(CARD32); break; + default: return BadPictOp; /* Can't happen */ + } + + buffer = (CARD8 *)(stuff + 1); + end = (CARD8 *)stuff + (stuff->length << 2); + nelt = 0; + nglyph = 0; + while (buffer + sizeof(xGlyphElt) < end) { + elt = (xGlyphElt *)buffer; + buffer += sizeof(xGlyphElt); + + if (elt->len == 0xff) { + buffer += 4; + } else { + nelt++; + nglyph += elt->len; + space = size * elt->len; + if (space & 3) space += 4 - (space & 3); + buffer += space; + } + } + + /* The following only works for Render version > 0.2 */ + + /* All of the XGlyphElt* structure sizes are identical */ + elts = xalloc(nelt * sizeof(XGlyphElt8)); + if (!elts) + return BadAlloc; + + glyphs = xalloc(nglyph * size); + if (!glyphs) { + xfree(elts); + return BadAlloc; + } + + buffer = (CARD8 *)(stuff + 1); + end = (CARD8 *)stuff + (stuff->length << 2); + curGlyph = glyphs; + curElt = elts; + + glyphSet = SecurityLookupIDByType(client, stuff->glyphset, + GlyphSetType, DixReadAccess); + glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet); + + while (buffer + sizeof(xGlyphElt) < end) { + elt = (xGlyphElt *)buffer; + buffer += sizeof(xGlyphElt); + + if (elt->len == 0xff) { + glyphSet = SecurityLookupIDByType(client, + *((CARD32 *)buffer), + GlyphSetType, + DixReadAccess); + glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet); + buffer += 4; + } else { + curElt->glyphset = glyphPriv->glyphSets[scrnNum]; + curElt->xOff = elt->deltax; + curElt->yOff = elt->deltay; + curElt->nchars = elt->len; + curElt->chars = curGlyph; + + memcpy(curGlyph, buffer, size*elt->len); + curGlyph += size * elt->len; + + curElt++; + + space = size * elt->len; + if (space & 3) space += 4 - (space & 3); + buffer += space; + } + } + + switch (stuff->renderReqType) { + case X_RenderCompositeGlyphs8: + XRenderCompositeText8(dmxScreen->beDisplay, stuff->op, + pSrcPriv->pict, pDstPriv->pict, + pFormat, + stuff->xSrc, stuff->ySrc, + 0, 0, elts, nelt); + break; + case X_RenderCompositeGlyphs16: + XRenderCompositeText16(dmxScreen->beDisplay, stuff->op, + pSrcPriv->pict, pDstPriv->pict, + pFormat, + stuff->xSrc, stuff->ySrc, + 0, 0, (XGlyphElt16 *)elts, nelt); + break; + case X_RenderCompositeGlyphs32: + XRenderCompositeText32(dmxScreen->beDisplay, stuff->op, + pSrcPriv->pict, pDstPriv->pict, + pFormat, + stuff->xSrc, stuff->ySrc, + 0, 0, (XGlyphElt32 *)elts, nelt); + break; + } + + dmxSync(dmxScreen, FALSE); + + xfree(elts); + xfree(glyphs); + } + + return ret; +} + +/** Set the picture transform on each screen. */ +static int dmxProcRenderSetPictureTransform(ClientPtr client) +{ + DMXScreenInfo *dmxScreen; + PicturePtr pPicture; + dmxPictPrivPtr pPictPriv; + XTransform xform; + REQUEST(xRenderSetPictureTransformReq); + + REQUEST_SIZE_MATCH(xRenderSetPictureTransformReq); + VERIFY_PICTURE(pPicture, stuff->picture, client, DixWriteAccess, + RenderErrBase + BadPicture); + + /* For the following to work with PanoramiX, it assumes that Render + * wraps the ProcRenderVector after dmxRenderInit has been called. + */ + dmxScreen = &dmxScreens[pPicture->pDrawable->pScreen->myNum]; + pPictPriv = DMX_GET_PICT_PRIV(pPicture); + + if (pPictPriv->pict) { + xform.matrix[0][0] = stuff->transform.matrix11; + xform.matrix[0][1] = stuff->transform.matrix12; + xform.matrix[0][2] = stuff->transform.matrix13; + xform.matrix[1][0] = stuff->transform.matrix21; + xform.matrix[1][1] = stuff->transform.matrix22; + xform.matrix[1][2] = stuff->transform.matrix23; + xform.matrix[2][0] = stuff->transform.matrix31; + xform.matrix[2][1] = stuff->transform.matrix32; + xform.matrix[2][2] = stuff->transform.matrix33; + + XRenderSetPictureTransform(dmxScreen->beDisplay, + pPictPriv->pict, + &xform); + dmxSync(dmxScreen, FALSE); + } + + return dmxSaveRenderVector[stuff->renderReqType](client); +} + +/** Set the picture filter on each screen. */ +static int dmxProcRenderSetPictureFilter(ClientPtr client) +{ + DMXScreenInfo *dmxScreen; + PicturePtr pPicture; + dmxPictPrivPtr pPictPriv; + char *filter; + XFixed *params; + int nparams; + REQUEST(xRenderSetPictureFilterReq); + + REQUEST_AT_LEAST_SIZE(xRenderSetPictureFilterReq); + VERIFY_PICTURE(pPicture, stuff->picture, client, DixWriteAccess, + RenderErrBase + BadPicture); + + /* For the following to work with PanoramiX, it assumes that Render + * wraps the ProcRenderVector after dmxRenderInit has been called. + */ + dmxScreen = &dmxScreens[pPicture->pDrawable->pScreen->myNum]; + pPictPriv = DMX_GET_PICT_PRIV(pPicture); + + if (pPictPriv->pict) { + filter = (char *)(stuff + 1); + params = (XFixed *)(filter + ((stuff->nbytes + 3) & ~3)); + nparams = ((XFixed *)stuff + client->req_len) - params; + + XRenderSetPictureFilter(dmxScreen->beDisplay, + pPictPriv->pict, + filter, + params, + nparams); + dmxSync(dmxScreen, FALSE); + } + + return dmxSaveRenderVector[stuff->renderReqType](client); +} + + +/** Create a picture on the appropriate screen. This is the actual + * function that creates the picture. However, if the associated + * window has not yet been created due to lazy window creation, then + * delay the picture creation until the window is mapped. */ +static Picture dmxDoCreatePicture(PicturePtr pPicture) +{ + DrawablePtr pDraw = pPicture->pDrawable; + ScreenPtr pScreen = pDraw->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + XRenderPictFormat *pFormat; + Drawable draw; + + if (pPicture->pDrawable->type == DRAWABLE_WINDOW) { + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV((WindowPtr)(pDraw)); + + if (!(draw = pWinPriv->window)) { + /* Window has not been created yet due to the window + * optimization. Delay picture creation until window is + * mapped. + */ + pWinPriv->hasPict = TRUE; + return 0; + } + } else { + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV((PixmapPtr)(pDraw)); + + if (!(draw = pPixPriv->pixmap)) { + /* FIXME: Zero width/height pixmap?? */ + return 0; + } + } + + /* This should not be reached if the back-end display has been + * detached because the pWinPriv->window or the pPixPriv->pixmap + * will be NULL; however, we add it here for completeness + */ + if (!dmxScreen->beDisplay) + return 0; + + pFormat = dmxFindFormat(dmxScreen, pPicture->pFormat); + + return XRenderCreatePicture(dmxScreen->beDisplay, draw, pFormat, 0, 0); +} + +/** Create a list of pictures. This function is called by + * dmxCreateAndRealizeWindow() during the lazy window creation + * realization process. It creates the entire list of pictures that + * are associated with the given window. */ +void dmxCreatePictureList(WindowPtr pWindow) +{ + PicturePtr pPicture = GetPictureWindow(pWindow); + + while (pPicture) { + dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture); + + /* Create the picture for this window */ + pPictPriv->pict = dmxDoCreatePicture(pPicture); + + /* ValidatePicture takes care of the state changes */ + + pPicture = pPicture->pNext; + } +} + +/** Create \a pPicture on the backend. */ +int dmxBECreatePicture(PicturePtr pPicture) +{ + dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture); + + /* Create picutre on BE */ + pPictPriv->pict = dmxDoCreatePicture(pPicture); + + /* Flush changes to the backend server */ + dmxValidatePicture(pPicture, (1 << (CPLastBit+1)) - 1); + + return Success; +} + +/** Create a picture. This function handles the CreatePicture + * unwrapping/wrapping and calls dmxDoCreatePicture to actually create + * the picture on the appropriate screen. */ +int dmxCreatePicture(PicturePtr pPicture) +{ + ScreenPtr pScreen = pPicture->pDrawable->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + PictureScreenPtr ps = GetPictureScreen(pScreen); + dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture); + int ret = Success; + + DMX_UNWRAP(CreatePicture, dmxScreen, ps); +#if 1 + if (ps->CreatePicture) + ret = ps->CreatePicture(pPicture); +#endif + + /* Create picture on back-end server */ + pPictPriv->pict = dmxDoCreatePicture(pPicture); + pPictPriv->savedMask = 0; + + DMX_WRAP(CreatePicture, dmxCreatePicture, dmxScreen, ps); + + return ret; +} + +/** Destroy \a pPicture on the back-end server. */ +Bool dmxBEFreePicture(PicturePtr pPicture) +{ + ScreenPtr pScreen = pPicture->pDrawable->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture); + + if (pPictPriv->pict) { + XRenderFreePicture(dmxScreen->beDisplay, pPictPriv->pict); + pPictPriv->pict = (Picture)0; + return TRUE; + } + + return FALSE; +} + +/** Destroy a list of pictures that are associated with the window that + * is being destroyed. This function is called by #dmxDestroyWindow(). + * */ +Bool dmxDestroyPictureList(WindowPtr pWindow) +{ + PicturePtr pPicture = GetPictureWindow(pWindow); + Bool ret = FALSE; + + while (pPicture) { + ret |= dmxBEFreePicture(pPicture); + pPicture = pPicture->pNext; + } + + return ret; +} + +/** Destroy a picture. This function calls the wrapped function that + * frees the resources in the DMX server associated with this + * picture. */ +void dmxDestroyPicture(PicturePtr pPicture) +{ + ScreenPtr pScreen = pPicture->pDrawable->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + PictureScreenPtr ps = GetPictureScreen(pScreen); + + DMX_UNWRAP(DestroyPicture, dmxScreen, ps); + + /* Destroy picture on back-end server */ + if (dmxBEFreePicture(pPicture)) + dmxSync(dmxScreen, FALSE); + +#if 1 + if (ps->DestroyPicture) + ps->DestroyPicture(pPicture); +#endif + DMX_WRAP(DestroyPicture, dmxDestroyPicture, dmxScreen, ps); +} + +/** Change the picture's list of clip rectangles. */ +int dmxChangePictureClip(PicturePtr pPicture, int clipType, + pointer value, int n) +{ + ScreenPtr pScreen = pPicture->pDrawable->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + PictureScreenPtr ps = GetPictureScreen(pScreen); + dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture); + + DMX_UNWRAP(ChangePictureClip, dmxScreen, ps); +#if 1 + if (ps->ChangePictureClip) + ps->ChangePictureClip(pPicture, clipType, value, n); +#endif + + /* Change picture clip rects on back-end server */ + if (pPictPriv->pict) { + /* The clip has already been changed into a region by the mi + * routine called above. + */ + if (clipType == CT_NONE) { + /* Disable clipping, show all */ + XFixesSetPictureClipRegion(dmxScreen->beDisplay, + pPictPriv->pict, 0, 0, None); + } else if (pPicture->clientClip) { + RegionPtr pClip = pPicture->clientClip; + BoxPtr pBox = REGION_RECTS(pClip); + int nBox = REGION_NUM_RECTS(pClip); + XRectangle *pRects; + XRectangle *pRect; + int nRects; + + nRects = nBox; + pRects = pRect = xalloc(nRects * sizeof(*pRect)); + + while (nBox--) { + pRect->x = pBox->x1; + pRect->y = pBox->y1; + pRect->width = pBox->x2 - pBox->x1; + pRect->height = pBox->y2 - pBox->y1; + pBox++; + pRect++; + } + + XRenderSetPictureClipRectangles(dmxScreen->beDisplay, + pPictPriv->pict, + 0, 0, + pRects, + nRects); + xfree(pRects); + } else { + XRenderSetPictureClipRectangles(dmxScreen->beDisplay, + pPictPriv->pict, + 0, 0, NULL, 0); + } + dmxSync(dmxScreen, FALSE); + } else { + /* FIXME: Handle saving clip region when offscreen */ + } + + DMX_WRAP(ChangePictureClip, dmxChangePictureClip, dmxScreen, ps); + + return Success; +} + +/** Destroy the picture's list of clip rectangles. */ +void dmxDestroyPictureClip(PicturePtr pPicture) +{ + ScreenPtr pScreen = pPicture->pDrawable->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + PictureScreenPtr ps = GetPictureScreen(pScreen); + dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture); + + DMX_UNWRAP(DestroyPictureClip, dmxScreen, ps); +#if 1 + if (ps->DestroyPictureClip) + ps->DestroyPictureClip(pPicture); +#endif + + /* Destroy picture clip rects on back-end server */ + if (pPictPriv->pict) { + XRenderSetPictureClipRectangles(dmxScreen->beDisplay, + pPictPriv->pict, + 0, 0, NULL, 0); + dmxSync(dmxScreen, FALSE); + } else { + /* FIXME: Handle destroying clip region when offscreen */ + } + + DMX_WRAP(DestroyPictureClip, dmxDestroyPictureClip, dmxScreen, ps); +} + +/** Change the attributes of the pictures. If the picture has not yet + * been created due to lazy window creation, save the mask so that it + * can be used to appropriately initialize the picture's attributes + * when it is created later. */ +void dmxChangePicture(PicturePtr pPicture, Mask mask) +{ + ScreenPtr pScreen = pPicture->pDrawable->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + PictureScreenPtr ps = GetPictureScreen(pScreen); + dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture); + + DMX_UNWRAP(ChangePicture, dmxScreen, ps); +#if 1 + if (ps->ChangePicture) + ps->ChangePicture(pPicture, mask); +#endif + + /* Picture attribute changes are handled in ValidatePicture */ + pPictPriv->savedMask |= mask; + + DMX_WRAP(ChangePicture, dmxChangePicture, dmxScreen, ps); +} + +/** Validate the picture's attributes before rendering to it. Update + * any picture attributes that have been changed by one of the higher + * layers. */ +void dmxValidatePicture(PicturePtr pPicture, Mask mask) +{ + ScreenPtr pScreen = pPicture->pDrawable->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + PictureScreenPtr ps = GetPictureScreen(pScreen); + dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pPicture); + + DMX_UNWRAP(ValidatePicture, dmxScreen, ps); + + /* Change picture attributes on back-end server */ + if (pPictPriv->pict) { + XRenderPictureAttributes attribs; + + if (mask & CPRepeat) { + attribs.repeat = pPicture->repeatType; + } + if (mask & CPAlphaMap) { + if (pPicture->alphaMap) { + dmxPictPrivPtr pAlphaPriv; + pAlphaPriv = DMX_GET_PICT_PRIV(pPicture->alphaMap); + if (pAlphaPriv->pict) { + attribs.alpha_map = pAlphaPriv->pict; + } else { + /* FIXME: alpha picture drawable has not been created?? */ + return; /* or should this be: attribs.alpha_map = None; */ + } + } else { + attribs.alpha_map = None; + } + } + if (mask & CPAlphaXOrigin) + attribs.alpha_x_origin = pPicture->alphaOrigin.x; + if (mask & CPAlphaYOrigin) + attribs.alpha_y_origin = pPicture->alphaOrigin.y; + if (mask & CPClipXOrigin) + attribs.clip_x_origin = pPicture->clipOrigin.x; + if (mask & CPClipYOrigin) + attribs.clip_y_origin = pPicture->clipOrigin.y; + if (mask & CPClipMask) + mask &= ~CPClipMask; /* Handled in ChangePictureClip */ + if (mask & CPGraphicsExposure) + attribs.graphics_exposures = pPicture->graphicsExposures; + if (mask & CPSubwindowMode) + attribs.subwindow_mode = pPicture->subWindowMode; + if (mask & CPPolyEdge) + attribs.poly_edge = pPicture->polyEdge; + if (mask & CPPolyMode) + attribs.poly_mode = pPicture->polyMode; + if (mask & CPDither) + attribs.dither = pPicture->dither; + if (mask & CPComponentAlpha) + attribs.component_alpha = pPicture->componentAlpha; + + XRenderChangePicture(dmxScreen->beDisplay, pPictPriv->pict, + mask, &attribs); + dmxSync(dmxScreen, FALSE); + } else { + pPictPriv->savedMask |= mask; + } + +#if 1 + if (ps->ValidatePicture) + ps->ValidatePicture(pPicture, mask); +#endif + + DMX_WRAP(ValidatePicture, dmxValidatePicture, dmxScreen, ps); +} + +/** Composite a picture on the appropriate screen by combining the + * specified rectangle of the transformed src and mask operands with + * the specified rectangle of the dst using op as the compositing + * operator. For a complete description see the protocol document of + * the RENDER library. */ +void dmxComposite(CARD8 op, + PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, + INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, + CARD16 width, CARD16 height) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + PictureScreenPtr ps = GetPictureScreen(pScreen); + dmxPictPrivPtr pSrcPriv = DMX_GET_PICT_PRIV(pSrc); + dmxPictPrivPtr pMaskPriv = NULL; + dmxPictPrivPtr pDstPriv = DMX_GET_PICT_PRIV(pDst); + + if (pMask) pMaskPriv = DMX_GET_PICT_PRIV(pMask); + + DMX_UNWRAP(Composite, dmxScreen, ps); +#if 0 + if (ps->Composite) + ps->Composite(op, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, xDst, yDst, + width, height); +#endif + + /* Composite on back-end server */ + if (pSrcPriv->pict && pDstPriv->pict && + ((pMaskPriv && pMaskPriv->pict) || !pMaskPriv)) { + XRenderComposite(dmxScreen->beDisplay, + op, + pSrcPriv->pict, + pMaskPriv ? pMaskPriv->pict : None, + pDstPriv->pict, + xSrc, ySrc, + xMask, yMask, + xDst, yDst, + width, height); + dmxSync(dmxScreen, FALSE); + } + + + DMX_WRAP(Composite, dmxComposite, dmxScreen, ps); +} + +/** Null function to catch when/if RENDER calls lower level mi hooks. + * Compositing glyphs is handled by dmxProcRenderCompositeGlyphs(). + * This function should never be called. */ +void dmxGlyphs(CARD8 op, + PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, INT16 ySrc, + int nlists, GlyphListPtr lists, GlyphPtr *glyphs) +{ + /* This won't work, so we need to wrap ProcRenderCompositeGlyphs */ +} + +/** Fill a rectangle on the appropriate screen by combining the color + * with the dest picture in the area specified by the list of + * rectangles. For a complete description see the protocol document of + * the RENDER library. */ +void dmxCompositeRects(CARD8 op, + PicturePtr pDst, + xRenderColor *color, + int nRect, xRectangle *rects) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + PictureScreenPtr ps = GetPictureScreen(pScreen); + dmxPictPrivPtr pPictPriv = DMX_GET_PICT_PRIV(pDst); + + DMX_UNWRAP(CompositeRects, dmxScreen, ps); +#if 0 + if (ps->CompositeRects) + ps->CompositeRects(op, pDst, color, nRect, rects); +#endif + + /* CompositeRects on back-end server */ + if (pPictPriv->pict) { + XRenderFillRectangles(dmxScreen->beDisplay, + op, + pPictPriv->pict, + (XRenderColor *)color, + (XRectangle *)rects, + nRect); + dmxSync(dmxScreen, FALSE); + } + + DMX_WRAP(CompositeRects, dmxCompositeRects, dmxScreen, ps); +} + +/** Indexed color visuals are not yet supported. */ +Bool dmxInitIndexed(ScreenPtr pScreen, PictFormatPtr pFormat) +{ + return TRUE; +} + +/** Indexed color visuals are not yet supported. */ +void dmxCloseIndexed(ScreenPtr pScreen, PictFormatPtr pFormat) +{ +} + +/** Indexed color visuals are not yet supported. */ +void dmxUpdateIndexed(ScreenPtr pScreen, PictFormatPtr pFormat, + int ndef, xColorItem *pdef) +{ +} + +/** Composite a list of trapezoids on the appropriate screen. For a + * complete description see the protocol document of the RENDER + * library. */ +void dmxTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, INT16 ySrc, + int ntrap, xTrapezoid *traps) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + PictureScreenPtr ps = GetPictureScreen(pScreen); + dmxPictPrivPtr pSrcPriv = DMX_GET_PICT_PRIV(pSrc); + dmxPictPrivPtr pDstPriv = DMX_GET_PICT_PRIV(pDst); + + DMX_UNWRAP(Trapezoids, dmxScreen, ps); +#if 0 + if (ps->Trapezoids) + ps->Trapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntrap, *traps); +#endif + + /* Draw trapezoids on back-end server */ + if (pDstPriv->pict) { + XRenderPictFormat *pFormat; + + pFormat = dmxFindFormat(dmxScreen, maskFormat); + if (!pFormat) { + /* FIXME: Error! */ + } + + XRenderCompositeTrapezoids(dmxScreen->beDisplay, + op, + pSrcPriv->pict, + pDstPriv->pict, + pFormat, + xSrc, ySrc, + (XTrapezoid *)traps, + ntrap); + dmxSync(dmxScreen, FALSE); + } + + DMX_WRAP(Trapezoids, dmxTrapezoids, dmxScreen, ps); +} + +/** Composite a list of triangles on the appropriate screen. For a + * complete description see the protocol document of the RENDER + * library. */ +void dmxTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, INT16 ySrc, + int ntri, xTriangle *tris) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + PictureScreenPtr ps = GetPictureScreen(pScreen); + dmxPictPrivPtr pSrcPriv = DMX_GET_PICT_PRIV(pSrc); + dmxPictPrivPtr pDstPriv = DMX_GET_PICT_PRIV(pDst); + + DMX_UNWRAP(Triangles, dmxScreen, ps); +#if 0 + if (ps->Triangles) + ps->Triangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, *tris); +#endif + + /* Draw trapezoids on back-end server */ + if (pDstPriv->pict) { + XRenderPictFormat *pFormat; + + pFormat = dmxFindFormat(dmxScreen, maskFormat); + if (!pFormat) { + /* FIXME: Error! */ + } + + XRenderCompositeTriangles(dmxScreen->beDisplay, + op, + pSrcPriv->pict, + pDstPriv->pict, + pFormat, + xSrc, ySrc, + (XTriangle *)tris, + ntri); + dmxSync(dmxScreen, FALSE); + } + + DMX_WRAP(Triangles, dmxTriangles, dmxScreen, ps); +} + +/** Composite a triangle strip on the appropriate screen. For a + * complete description see the protocol document of the RENDER + * library. */ +void dmxTriStrip(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, INT16 ySrc, + int npoint, xPointFixed *points) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + PictureScreenPtr ps = GetPictureScreen(pScreen); + dmxPictPrivPtr pSrcPriv = DMX_GET_PICT_PRIV(pSrc); + dmxPictPrivPtr pDstPriv = DMX_GET_PICT_PRIV(pDst); + + DMX_UNWRAP(TriStrip, dmxScreen, ps); +#if 0 + if (ps->TriStrip) + ps->TriStrip(op, pSrc, pDst, maskFormat, xSrc, ySrc, npoint, *points); +#endif + + /* Draw trapezoids on back-end server */ + if (pDstPriv->pict) { + XRenderPictFormat *pFormat; + + pFormat = dmxFindFormat(dmxScreen, maskFormat); + if (!pFormat) { + /* FIXME: Error! */ + } + + XRenderCompositeTriStrip(dmxScreen->beDisplay, + op, + pSrcPriv->pict, + pDstPriv->pict, + pFormat, + xSrc, ySrc, + (XPointFixed *)points, + npoint); + dmxSync(dmxScreen, FALSE); + } + + DMX_WRAP(TriStrip, dmxTriStrip, dmxScreen, ps); +} + +/** Composite a triangle fan on the appropriate screen. For a complete + * description see the protocol document of the RENDER library. */ +void dmxTriFan(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, + INT16 xSrc, INT16 ySrc, + int npoint, xPointFixed *points) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + PictureScreenPtr ps = GetPictureScreen(pScreen); + dmxPictPrivPtr pSrcPriv = DMX_GET_PICT_PRIV(pSrc); + dmxPictPrivPtr pDstPriv = DMX_GET_PICT_PRIV(pDst); + + DMX_UNWRAP(TriFan, dmxScreen, ps); +#if 0 + if (ps->TriFan) + ps->TriFan(op, pSrc, pDst, maskFormat, xSrc, ySrc, npoint, *points); +#endif + + /* Draw trapezoids on back-end server */ + if (pDstPriv->pict) { + XRenderPictFormat *pFormat; + + pFormat = dmxFindFormat(dmxScreen, maskFormat); + if (!pFormat) { + /* FIXME: Error! */ + } + + XRenderCompositeTriFan(dmxScreen->beDisplay, + op, + pSrcPriv->pict, + pDstPriv->pict, + pFormat, + xSrc, ySrc, + (XPointFixed *)points, + npoint); + dmxSync(dmxScreen, FALSE); + } + + DMX_WRAP(TriFan, dmxTriFan, dmxScreen, ps); +} |