diff options
Diffstat (limited to 'src/vivante_unaccel_render.c')
-rw-r--r-- | src/vivante_unaccel_render.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/src/vivante_unaccel_render.c b/src/vivante_unaccel_render.c new file mode 100644 index 0000000..42aaa4a --- /dev/null +++ b/src/vivante_unaccel_render.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2012 Russell King. + * + * Based in part on code from the Intel Xorg driver. + * + * Unaccelerated drawing functions for Vivante GPU. These prepare + * access to the drawable prior to passing on the call to the Xorg + * Server's fb layer (or pixman layer.) + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "fb.h" +#include "fbpict.h" +#include "mipict.h" + +#include "vivante_unaccel.h" +#include "vivante_utils.h" + +static void vivante_prepare_picture(PicturePtr pPicture, int access) +{ + if (pPicture->pDrawable) { + vivante_prepare_drawable(pPicture->pDrawable, access); + if (pPicture->alphaMap) + vivante_prepare_drawable(pPicture->alphaMap->pDrawable, access); + } +} + +static void vivante_finish_picture(PicturePtr pPicture, int access) +{ + if (pPicture->pDrawable) { + if (pPicture->alphaMap) + vivante_finish_drawable(pPicture->alphaMap->pDrawable, access); + vivante_finish_drawable(pPicture->pDrawable, access); + } +} + +static void GlyphExtents(int nlist, GlyphListPtr list, GlyphPtr *glyphs, + BoxPtr extents) +{ + int x1, y1, x2, y2, n, x, y; + GlyphPtr glyph; + + x = y = 0; + extents->x1 = extents->y1 = MAXSHORT; + extents->x2 = extents->y2 = MINSHORT; + while (nlist--) { + x += list->xOff; + y += list->yOff; + n = list->len; + list++; + while (n--) { + glyph = *glyphs++; + x1 = x - glyph->info.x; + if (x1 < MINSHORT) + x1 = MINSHORT; + y1 = y - glyph->info.y; + if (y1 < MINSHORT) + y1 = MINSHORT; + x2 = x1 + glyph->info.width; + if (x2 > MAXSHORT) + x2 = MAXSHORT; + y2 = y1 + glyph->info.height; + if (y2 > MAXSHORT) + y2 = MAXSHORT; + if (x1 < extents->x1) + extents->x1 = x1; + if (x2 > extents->x2) + extents->x2 = x2; + if (y1 < extents->y1) + extents->y1 = y1; + if (y2 > extents->y2) + extents->y2 = y2; + x += glyph->info.xOff; + y += glyph->info.yOff; + } + } +} + +#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) +#ifndef GLYPH_HAS_GLYPH_PICTURE_ACCESSOR +#define GetGlyphPicture(g, s) GlyphPicture((g))[(s)->myNum] +#define SetGlyphPicture(g, s, p) GlyphPicture((g))[(s)->myNum] = p +#endif + +void vivante_unaccel_Glyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist, + GlyphListPtr list, GlyphPtr * glyphs) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PixmapPtr pMaskPixmap = NULL; + PicturePtr pMask; + int width = 0, height = 0, x, y, n; + int xDst = list->xOff, yDst = list->yOff; + BoxRec extents = { 0, 0, 0, 0 }; + + if (maskFormat) { + xRectangle rect; + CARD32 component_alpha; + GCPtr pGC; + int error; + + GlyphExtents(nlist, list, glyphs, &extents); + if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) + return; + + width = extents.x2 - extents.x1; + height = extents.y2 - extents.y1; + pMaskPixmap = pScreen->CreatePixmap(pScreen, width, height, + maskFormat->depth, + CREATE_PIXMAP_USAGE_SCRATCH); + if (!pMaskPixmap) + return; + + component_alpha = NeedsComponent(maskFormat->format); + pMask = CreatePicture(0, &pMaskPixmap->drawable, maskFormat, + CPComponentAlpha, &component_alpha, serverClient, &error); + if (!pMask) { + pScreen->DestroyPixmap(pMaskPixmap); + return; + } + + pGC = GetScratchGC(pMaskPixmap->drawable.depth, pScreen); + ValidateGC(&pMaskPixmap->drawable, pGC); + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + pGC->ops->PolyFillRect(&pMaskPixmap->drawable, pGC, 1, &rect); + FreeScratchGC(pGC); + x = -extents.x1; + y = -extents.y1; + } else { + pMask = pDst; + x = 0; + y = 0; + } + + while (nlist--) { + x += list->xOff; + y += list->yOff; + n = list->len; + while (n--) { + GlyphPtr glyph = *glyphs++; + PicturePtr g = GetGlyphPicture(glyph, pScreen); + + if (g) { + int dstx = x - glyph->info.x; + int dsty = y - glyph->info.y; + if (maskFormat) { + CompositePicture(PictOpAdd, g, NULL, pMask, + 0, 0, 0, 0, dstx, dsty, + glyph->info.width, glyph->info.height); + } else { + CompositePicture(op, pSrc, g, pDst, + xSrc + dstx - xDst, + ySrc + dsty - yDst, + 0, 0, dstx, dsty, + glyph->info.width, glyph->info.height); + } + } + x += glyph->info.xOff; + y += glyph->info.yOff; + } + list++; + } + + if (maskFormat) { + x = extents.x1; + y = extents.y1; + CompositePicture(op, pSrc, pMask, pDst, + xSrc + x - xDst, ySrc + y - yDst, 0, 0, x, y, + width, height); + FreePicture(pMask, 0); + pScreen->DestroyPixmap(pMaskPixmap); + } +} + +void vivante_unaccel_Triangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int ntri, xTriangle *tri) +{ + vivante_prepare_picture(pDst, ACCESS_RW); + vivante_prepare_picture(pSrc, ACCESS_RO); + fbTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tri); + vivante_finish_picture(pSrc, ACCESS_RO); + vivante_finish_picture(pDst, ACCESS_RW); +} + +void vivante_unaccel_Trapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int ntrap, + xTrapezoid * traps) +{ + vivante_prepare_picture(pDst, ACCESS_RW); + vivante_prepare_picture(pSrc, ACCESS_RO); + fbTrapezoids(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntrap, traps); + vivante_finish_picture(pSrc, ACCESS_RO); + vivante_finish_picture(pDst, ACCESS_RW); +} + +void vivante_unaccel_Composite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, + PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, CARD16 w, CARD16 h) +{ + vivante_prepare_picture(pDst, ACCESS_RW); + vivante_prepare_picture(pSrc, ACCESS_RO); + if (pMask) + vivante_prepare_picture(pMask, ACCESS_RO); + fbComposite(op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, w, h); + if (pMask) + vivante_finish_picture(pMask, ACCESS_RO); + vivante_finish_picture(pSrc, ACCESS_RO); + vivante_finish_picture(pDst, ACCESS_RW); +} + +void vivante_unaccel_AddTriangles(PicturePtr pPicture, INT16 x_off, INT16 y_off, + int ntri, xTriangle *tris) +{ + vivante_prepare_picture(pPicture, ACCESS_RW); + fbAddTriangles(pPicture, x_off, y_off, ntri, tris); + vivante_finish_picture(pPicture, ACCESS_RW); +} + +void vivante_unaccel_AddTraps(PicturePtr pPicture, INT16 x_off, INT16 y_off, + int ntrap, xTrap *traps) +{ + vivante_prepare_picture(pPicture, ACCESS_RW); + fbAddTraps(pPicture, x_off, y_off, ntrap, traps); + vivante_finish_picture(pPicture, ACCESS_RW); +} |