summaryrefslogtreecommitdiff
path: root/uxa/uxa-render.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-04-14 21:14:34 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2010-05-08 19:35:07 +0100
commita7b800513fcc94e063dfd68d2f63b6bab7fae47d (patch)
tree8fbb87b6ed2152a338433f5e14d371650faa3790 /uxa/uxa-render.c
parent8562b7bc6740eef2602af76b8685388efd2d4d37 (diff)
uxa: Extract sub-region from in-memory buffers.
If the buffer is too large or not suitable for a GPU operation, we currently fallback and perform the composite on the CPU. An alternative is too extract the small region out of the source (as usually the sample extents are much smaller than the actual surface size) and try the composite with the new surface. The effect is particularly noticeable on pathological websites that use very large background images. For example, http://www.woodtv.com/ uses a 1299x15000 pattern that is obscured by another opaque pattern. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'uxa/uxa-render.c')
-rw-r--r--uxa/uxa-render.c206
1 files changed, 183 insertions, 23 deletions
diff --git a/uxa/uxa-render.c b/uxa/uxa-render.c
index 30934d0d..b2e88c47 100644
--- a/uxa/uxa-render.c
+++ b/uxa/uxa-render.c
@@ -577,17 +577,142 @@ uxa_acquire_pattern(ScreenPtr pScreen,
}
}
+static Bool
+transform_is_integer_translation(PictTransformPtr t, int *tx, int *ty)
+{
+ if (t == NULL) {
+ *tx = *ty = 0;
+ return TRUE;
+ }
+
+ if (t->matrix[0][0] != IntToxFixed(1) ||
+ t->matrix[0][1] != 0 ||
+ t->matrix[1][0] != 0 ||
+ t->matrix[1][1] != IntToxFixed(1) ||
+ t->matrix[2][0] != 0 ||
+ t->matrix[2][1] != 0)
+ return FALSE;
+
+ if (xFixedFrac(t->matrix[0][2]) != 0 ||
+ xFixedFrac(t->matrix[1][2]) != 0)
+ return FALSE;
+
+ *tx = xFixedToInt(t->matrix[0][2]);
+ *ty = xFixedToInt(t->matrix[1][2]);
+ return TRUE;
+}
+
+static PicturePtr
+uxa_render_picture(ScreenPtr screen,
+ PicturePtr src,
+ INT16 x, INT16 y,
+ CARD16 width, CARD16 height)
+{
+ PicturePtr picture;
+ pixman_format_code_t format;
+ int ret = 0;
+
+ format = src->format |
+ (BitsPerPixel(src->pDrawable->depth) << 24);
+
+ picture = uxa_picture_for_pixman_format(screen, format, width, height);
+ if (!picture)
+ return 0;
+
+ if (uxa_prepare_access(picture->pDrawable, UXA_ACCESS_RW)) {
+ if (uxa_prepare_access(src->pDrawable, UXA_ACCESS_RO)) {
+ ret = 1;
+ fbComposite(PictOpSrc, src, NULL, picture,
+ x, y, 0, 0, 0, 0, width, height);
+ uxa_finish_access(src->pDrawable);
+ }
+ uxa_finish_access(picture->pDrawable);
+ }
+
+ if (!ret) {
+ FreePicture(picture, 0);
+ return 0;
+ }
+
+ return picture;
+}
+
+static PicturePtr
+uxa_acquire_drawable(ScreenPtr pScreen,
+ PicturePtr pSrc,
+ INT16 x, INT16 y,
+ CARD16 width, CARD16 height,
+ INT16 * out_x, INT16 * out_y,
+ Bool force)
+{
+ PixmapPtr pPixmap;
+ PicturePtr pDst;
+ GCPtr pGC;
+ int depth, error;
+ int tx, ty;
+
+ if (!force && uxa_drawable_is_offscreen(pSrc->pDrawable)) {
+ *out_x = x + pSrc->pDrawable->x;
+ *out_y = y + pSrc->pDrawable->y;
+ return pSrc;
+ }
+
+ depth = pSrc->pDrawable->depth;
+ if (depth == 1 || !transform_is_integer_translation(pSrc->transform, &tx, &ty)) {
+ /* XXX extract the sample extents and do the transformation on the GPU */
+ pDst = uxa_render_picture(pScreen, pSrc, x, y, width, height);
+ goto done;
+ }
+
+ pPixmap = pScreen->CreatePixmap(pScreen, width, height, depth, 0);
+ if (!pPixmap)
+ return 0;
+
+ /* Skip the copy if the result remains in memory and not a bo */
+ if (!uxa_drawable_is_offscreen(&pPixmap->drawable)) {
+ pScreen->DestroyPixmap(pPixmap);
+ *out_x = x + pSrc->pDrawable->x;
+ *out_y = y + pSrc->pDrawable->y;
+ return pSrc;
+ }
+
+ pGC = GetScratchGC(depth, pScreen);
+ if (!pGC) {
+ pScreen->DestroyPixmap(pPixmap);
+ return 0;
+ }
+
+ ValidateGC(&pPixmap->drawable, pGC);
+ pGC->ops->CopyArea(pSrc->pDrawable, &pPixmap->drawable, pGC,
+ x + tx, y + ty, width, height, 0, 0);
+ FreeScratchGC(pGC);
+
+ pDst = CreatePicture(0, &pPixmap->drawable,
+ PictureMatchFormat(pScreen, depth, pSrc->format),
+ 0, 0, serverClient, &error);
+ pScreen->DestroyPixmap(pPixmap);
+ ValidatePicture(pDst);
+
+done:
+ pDst->componentAlpha = pSrc->componentAlpha;
+ *out_x = x;
+ *out_y = y;
+ return pDst;
+}
+
static PicturePtr
uxa_acquire_source(ScreenPtr pScreen,
PicturePtr pPict,
INT16 x, INT16 y,
- CARD16 width, CARD16 height, INT16 * out_x, INT16 * out_y)
+ CARD16 width, CARD16 height,
+ INT16 * out_x, INT16 * out_y,
+ Bool force)
{
- if (pPict->pDrawable) {
- *out_x = x + pPict->pDrawable->x;
- *out_y = y + pPict->pDrawable->y;
- return pPict;
- }
+ if (pPict->pDrawable)
+ return uxa_acquire_drawable(pScreen, pPict,
+ x, y, width, height,
+ out_x, out_y,
+ force);
*out_x = 0;
*out_y = 0;
@@ -599,13 +724,15 @@ static PicturePtr
uxa_acquire_mask(ScreenPtr pScreen,
PicturePtr pPict,
INT16 x, INT16 y,
- INT16 width, INT16 height, INT16 * out_x, INT16 * out_y)
+ INT16 width, INT16 height,
+ INT16 * out_x, INT16 * out_y,
+ Bool force)
{
- if (pPict->pDrawable) {
- *out_x = x + pPict->pDrawable->x;
- *out_y = y + pPict->pDrawable->y;
- return pPict;
- }
+ if (pPict->pDrawable)
+ return uxa_acquire_drawable(pScreen, pPict,
+ x, y, width, height,
+ out_x, out_y,
+ force);
*out_x = 0;
*out_y = 0;
@@ -736,33 +863,41 @@ uxa_try_driver_composite(CARD8 op,
PicturePtr pSrc,
PicturePtr pMask,
PicturePtr pDst,
- INT16 xSrc,
- INT16 ySrc,
- INT16 xMask,
- INT16 yMask,
- INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
+ INT16 xSrc, INT16 ySrc,
+ INT16 xMask, INT16 yMask,
+ INT16 xDst, INT16 yDst,
+ CARD16 width, CARD16 height)
{
uxa_screen_t *uxa_screen = uxa_get_screen(pDst->pDrawable->pScreen);
RegionRec region;
BoxPtr pbox;
int nbox;
+ INT16 _xSrc = xSrc, _ySrc = ySrc;
+ INT16 _xMask = xMask, _yMask = yMask;
int src_off_x, src_off_y, mask_off_x, mask_off_y, dst_off_x, dst_off_y;
PixmapPtr pSrcPix, pMaskPix = NULL, pDstPix;
PicturePtr localSrc, localMask = NULL;
+ pDstPix =
+ uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y);
+ if (!pDstPix)
+ return -1;
+
xDst += pDst->pDrawable->x;
yDst += pDst->pDrawable->y;
localSrc = uxa_acquire_source(pDst->pDrawable->pScreen,
pSrc, xSrc, ySrc, width, height,
- &xSrc, &ySrc);
+ &xSrc, &ySrc,
+ FALSE);
if (!localSrc)
return 0;
if (pMask) {
localMask = uxa_acquire_mask(pDst->pDrawable->pScreen,
pMask, xMask, yMask, width, height,
- &xMask, &yMask);
+ &xMask, &yMask,
+ FALSE);
if (!localMask) {
if (localSrc != pSrc)
FreePicture(localSrc, 0);
@@ -771,9 +906,37 @@ uxa_try_driver_composite(CARD8 op,
}
}
+recheck:
if (uxa_screen->info->check_composite &&
!(*uxa_screen->info->check_composite) (op, localSrc, localMask,
pDst)) {
+ if (localSrc == pSrc || (localMask && localMask == pMask)) {
+ if (localSrc == pSrc) {
+ localSrc = uxa_acquire_source(pDst->pDrawable->pScreen,
+ pSrc, _xSrc, _ySrc, width, height,
+ &xSrc, &ySrc, TRUE);
+ if (!localSrc || localSrc == pSrc) {
+ if (localMask && localMask != pMask)
+ FreePicture(localMask, 0);
+ return -(localSrc == pSrc);
+ }
+ }
+
+ if (localMask && localMask == pMask) {
+ localMask = uxa_acquire_mask(pDst->pDrawable->pScreen,
+ pMask, _xMask, _yMask, width, height,
+ &xMask, &yMask, TRUE);
+ if (!localMask || localMask == pMask) {
+ if (localSrc != pSrc)
+ FreePicture(localSrc, 0);
+
+ return -(localMask == pMask);
+ }
+ }
+
+ goto recheck;
+ }
+
if (localSrc != pSrc)
FreePicture(localSrc, 0);
if (localMask && localMask != pMask)
@@ -793,9 +956,6 @@ uxa_try_driver_composite(CARD8 op,
return 1;
}
- pDstPix =
- uxa_get_offscreen_pixmap(pDst->pDrawable, &dst_off_x, &dst_off_y);
-
pSrcPix = uxa_get_offscreen_pixmap(localSrc->pDrawable,
&src_off_x, &src_off_y);
@@ -803,7 +963,7 @@ uxa_try_driver_composite(CARD8 op,
pMaskPix = uxa_get_offscreen_pixmap(localMask->pDrawable,
&mask_off_x, &mask_off_y);
- if (!pDstPix || !pSrcPix || (localMask && !pMaskPix)) {
+ if (!pSrcPix || (localMask && !pMaskPix)) {
REGION_UNINIT(pDst->pDrawable->pScreen, &region);
if (localSrc != pSrc)