]> git.pld-linux.org Git - packages/xorg-xserver-server.git/blame - xorg-xserver-server-exa.patch
- outdated
[packages/xorg-xserver-server.git] / xorg-xserver-server-exa.patch
CommitLineData
33d29f3f
AM
1From e99347a3e82e6db47dd482169b6799968afc3893 Mon Sep 17 00:00:00 2001
2From: Dave Airlie <airlied@redhat.com>
3Date: Wed, 20 Aug 2008 10:11:07 -0400
4Subject: [PATCH] Upgrade to master EXA
5
6---
453260b6 7
453260b6
AM
8
9diff --git a/exa/Makefile.am b/exa/Makefile.am
10index e2f7ed3..2b3f1e4 100644
11--- a/exa/Makefile.am
12+++ b/exa/Makefile.am
13@@ -18,6 +18,7 @@ libexa_la_SOURCES = \
14 exa.c \
15 exa.h \
16 exa_accel.c \
17+ exa_glyphs.c \
18 exa_migration.c \
19 exa_offscreen.c \
20 exa_render.c \
21diff --git a/exa/exa.c b/exa/exa.c
33d29f3f 22index ccf148a..12c1549 100644
453260b6
AM
23--- a/exa/exa.c
24+++ b/exa/exa.c
33d29f3f
AM
25@@ -35,8 +35,6 @@
26 #include <stdlib.h>
27
28 #include "exa_priv.h"
29-#include <X11/fonts/fontstruct.h>
30-#include "dixfontstr.h"
31 #include "exa.h"
32 #include "cw.h"
33
34@@ -161,7 +159,7 @@ exaPixmapDirty (PixmapPtr pPix, int x1, int y1, int x2, int y2)
35 RegionPtr pDamageReg;
36 RegionRec region;
37
38- if (!pExaPixmap)
39+ if (!pExaPixmap || !pExaPixmap->pDamage)
40 return;
41
42 box.x1 = max(x1, 0);
43@@ -261,6 +259,21 @@ exaSetFbPitch(ExaScreenPrivPtr pExaScr, ExaPixmapPrivPtr pExaPixmap,
44 pExaScr->info->pixmapPitchAlign);
45 }
46
47+
48+static void
49+ExaDamageReport(DamagePtr pDamage, RegionPtr pReg, void *pClosure)
50+{
51+ PixmapPtr pPixmap = pClosure;
52+ ExaPixmapPriv(pPixmap);
53+ RegionPtr pDamageReg = DamageRegion(pDamage);
54+
55+ if (pExaPixmap->pendingDamage) {
56+ REGION_UNION(pScreen, pDamageReg, pDamageReg, pReg);
57+ pExaPixmap->pendingDamage = FALSE;
58+ }
59+}
60+
61+
62 /**
63 * exaCreatePixmap() creates a new pixmap.
64 *
65@@ -321,6 +334,7 @@ exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth,
66 paddedWidth, NULL);
67 pExaPixmap->score = EXA_PIXMAP_SCORE_PINNED;
68 pExaPixmap->fb_ptr = NULL;
69+ pExaPixmap->pDamage = NULL;
70 } else {
71 pExaPixmap->driverPriv = NULL;
72 /* Scratch pixmaps may have w/h equal to zero, and may not be
73@@ -345,21 +359,22 @@ exaCreatePixmap(ScreenPtr pScreen, int w, int h, int depth,
74 fbDestroyPixmap(pPixmap);
75 return NULL;
76 }
77- }
78-
79- pExaPixmap->area = NULL;
80
81- /* Set up damage tracking */
82- pExaPixmap->pDamage = DamageCreate (NULL, NULL, DamageReportNone, TRUE,
83- pScreen, pPixmap);
84+ /* Set up damage tracking */
85+ pExaPixmap->pDamage = DamageCreate (ExaDamageReport, NULL,
86+ DamageReportRawRegion, TRUE,
87+ pScreen, pPixmap);
88
89- if (pExaPixmap->pDamage == NULL) {
90- fbDestroyPixmap (pPixmap);
91- return NULL;
92- }
93+ if (pExaPixmap->pDamage == NULL) {
94+ fbDestroyPixmap (pPixmap);
95+ return NULL;
96+ }
97
98- DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage);
99- DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE);
100+ DamageRegister (&pPixmap->drawable, pExaPixmap->pDamage);
101+ DamageSetReportAfterOp (pExaPixmap->pDamage, TRUE);
102+ }
103+
104+ pExaPixmap->area = NULL;
105
106 /* None of the pixmap bits are valid initially */
107 REGION_NULL(pScreen, &pExaPixmap->validSys);
108@@ -656,34 +671,25 @@ exaCreateGC (GCPtr pGC)
109 return TRUE;
110 }
111
112-void
113-exaPrepareAccessWindow(WindowPtr pWin)
114+static Bool
115+exaChangeWindowAttributes(WindowPtr pWin, unsigned long mask)
116 {
117- if (pWin->backgroundState == BackgroundPixmap)
118+ Bool ret;
119+
120+ if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap)
121 exaPrepareAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC);
122
123- if (pWin->borderIsPixel == FALSE)
124- exaPrepareAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_SRC);
125-}
126+ if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE)
127+ exaPrepareAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK);
128
129-void
130-exaFinishAccessWindow(WindowPtr pWin)
131-{
132- if (pWin->backgroundState == BackgroundPixmap)
133- exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC);
134+ ret = fbChangeWindowAttributes(pWin, mask);
135
136- if (pWin->borderIsPixel == FALSE)
137- exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_SRC);
138-}
139+ if ((mask & CWBorderPixmap) && pWin->borderIsPixel == FALSE)
140+ exaFinishAccess(&pWin->border.pixmap->drawable, EXA_PREPARE_MASK);
141
142-static Bool
143-exaChangeWindowAttributes(WindowPtr pWin, unsigned long mask)
144-{
145- Bool ret;
146+ if ((mask & CWBackPixmap) && pWin->backgroundState == BackgroundPixmap)
147+ exaFinishAccess(&pWin->background.pixmap->drawable, EXA_PREPARE_SRC);
148
149- exaPrepareAccessWindow(pWin);
150- ret = fbChangeWindowAttributes(pWin, mask);
151- exaFinishAccessWindow(pWin);
152 return ret;
153 }
154
155@@ -737,6 +743,9 @@ exaCloseScreen(int i, ScreenPtr pScreen)
453260b6
AM
156 PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
157 #endif
158
33d29f3f
AM
159+ if (ps->Glyphs == exaGlyphs)
160+ exaGlyphsFini(pScreen);
453260b6
AM
161+
162 pScreen->CreateGC = pExaScr->SavedCreateGC;
163 pScreen->CloseScreen = pExaScr->SavedCloseScreen;
164 pScreen->GetImage = pExaScr->SavedGetImage;
33d29f3f 165@@ -750,8 +759,9 @@ exaCloseScreen(int i, ScreenPtr pScreen)
453260b6
AM
166 #ifdef RENDER
167 if (ps) {
168 ps->Composite = pExaScr->SavedComposite;
169+ ps->Glyphs = pExaScr->SavedGlyphs;
170 ps->Trapezoids = pExaScr->SavedTrapezoids;
33d29f3f 171- ps->AddTraps = pExaScr->SavedAddTraps;
453260b6 172+ ps->Triangles = pExaScr->SavedTriangles;
453260b6
AM
173 }
174 #endif
33d29f3f
AM
175
176@@ -913,14 +923,16 @@ exaDriverInit (ScreenPtr pScreen,
453260b6
AM
177 pExaScr->SavedComposite = ps->Composite;
178 ps->Composite = exaComposite;
179
33d29f3f
AM
180+ if (pScreenInfo->PrepareComposite) {
181+ pExaScr->SavedGlyphs = ps->Glyphs;
182+ ps->Glyphs = exaGlyphs;
183+ }
453260b6
AM
184+
185 pExaScr->SavedTriangles = ps->Triangles;
186 ps->Triangles = exaTriangles;
187
33d29f3f
AM
188 pExaScr->SavedTrapezoids = ps->Trapezoids;
189 ps->Trapezoids = exaTrapezoids;
190-
191- pExaScr->SavedAddTraps = ps->AddTraps;
192- ps->AddTraps = ExaCheckAddTraps;
193 }
194 #endif
195
196@@ -968,6 +980,9 @@ exaDriverInit (ScreenPtr pScreen,
453260b6
AM
197 }
198 }
199
33d29f3f
AM
200+ if (ps->Glyphs == exaGlyphs)
201+ exaGlyphsInit(pScreen);
453260b6
AM
202+
203 LogMessage(X_INFO, "EXA(%d): Driver registered support for the following"
204 " operations:\n", pScreen->myNum);
205 assert(pScreenInfo->PrepareSolid != NULL);
33d29f3f
AM
206diff --git a/exa/exa.h b/exa/exa.h
207index 2562094..8d9bcea 100644
208--- a/exa/exa.h
209+++ b/exa/exa.h
210@@ -744,21 +744,36 @@ typedef struct _ExaDriver {
211
212 /** @} */
213
214+/* in exa.c */
215 ExaDriverPtr
216 exaDriverAlloc(void);
217
218 Bool
219-exaDriverInit(ScreenPtr pScreen,
220+exaDriverInit(ScreenPtr pScreen,
221 ExaDriverPtr pScreenInfo);
222
223 void
224-exaDriverFini(ScreenPtr pScreen);
225+exaDriverFini(ScreenPtr pScreen);
226
227 void
228 exaMarkSync(ScreenPtr pScreen);
229 void
230 exaWaitSync(ScreenPtr pScreen);
231
232+unsigned long
233+exaGetPixmapOffset(PixmapPtr pPix);
234+
235+unsigned long
236+exaGetPixmapPitch(PixmapPtr pPix);
237+
238+unsigned long
239+exaGetPixmapSize(PixmapPtr pPix);
240+
241+void *
242+exaGetPixmapDriverPrivate(PixmapPtr p);
243+
244+
245+/* in exa_offscreen.c */
246 ExaOffscreenArea *
247 exaOffscreenAlloc(ScreenPtr pScreen, int size, int align,
248 Bool locked,
361c468e 249@@ -786,15 +786,6 @@
33d29f3f
AM
250 void
251 ExaOffscreenMarkUsed (PixmapPtr pPixmap);
252
253-unsigned long
254-exaGetPixmapOffset(PixmapPtr pPix);
255-
256-unsigned long
257-exaGetPixmapPitch(PixmapPtr pPix);
258-
259-unsigned long
260-exaGetPixmapSize(PixmapPtr pPix);
261-
262 void
263 exaEnableDisableFBAccess (int index, Bool enable);
264
361c468e 265@@ -808,9 +799,6 @@
33d29f3f
AM
266 void
267 exaMoveOutPixmap (PixmapPtr pPixmap);
268
269-void *
270-exaGetPixmapDriverPrivate(PixmapPtr p);
361c468e 271-
33d29f3f
AM
272 CARD32
273 exaGetPixmapFirstPixel (PixmapPtr pPixmap);
274
33d29f3f
AM
275diff --git a/exa/exa_accel.c b/exa/exa_accel.c
276index 3ec9625..1c07a0b 100644
277--- a/exa/exa_accel.c
278+++ b/exa/exa_accel.c
279@@ -144,7 +144,6 @@ exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
280 ExaScreenPriv (pDrawable->pScreen);
281 PixmapPtr pPix = exaGetDrawablePixmap (pDrawable);
282 ExaPixmapPriv(pPix);
283- ExaMigrationRec pixmaps[1];
284 RegionPtr pClip;
285 BoxPtr pbox;
286 int nbox;
287@@ -166,11 +165,16 @@ exaDoPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y,
288 if (pExaScr->swappedOut)
289 return FALSE;
290
291- pixmaps[0].as_dst = TRUE;
292- pixmaps[0].as_src = FALSE;
293- pixmaps[0].pPix = pPix;
294- pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage);
295- exaDoMigration (pixmaps, 1, TRUE);
296+ if (pExaPixmap->pDamage) {
297+ ExaMigrationRec pixmaps[1];
298+
299+ pixmaps[0].as_dst = TRUE;
300+ pixmaps[0].as_src = FALSE;
301+ pixmaps[0].pPix = pPix;
302+ pixmaps[0].pReg = DamagePendingRegion(pExaPixmap->pDamage);
303+
304+ exaDoMigration (pixmaps, 1, TRUE);
305+ }
306
307 pPix = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
308
309@@ -441,16 +445,36 @@ exaCopyNtoN (DrawablePtr pSrcDrawable,
310 pDstExaPixmap = ExaGetPixmapPriv (pDstPixmap);
311
312 /* Check whether the accelerator can use this pixmap.
313- * FIXME: If it cannot, use temporary pixmaps so that the drawing
314- * happens within limits.
315+ * If the pitch of the pixmaps is out of range, there's nothing
316+ * we can do but fall back to software rendering.
317 */
318- if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked)
319- {
320+ if (pSrcExaPixmap->accel_blocked & EXA_RANGE_PITCH ||
321+ pDstExaPixmap->accel_blocked & EXA_RANGE_PITCH)
322 goto fallback;
323- } else {
324- exaDoMigration (pixmaps, 2, TRUE);
325+
326+ /* If the width or the height of either of the pixmaps
327+ * is out of range, check whether the boxes are actually out of the
328+ * addressable range as well. If they aren't, we can still do
329+ * the copying in hardware.
330+ */
331+ if (pSrcExaPixmap->accel_blocked || pDstExaPixmap->accel_blocked) {
332+ int i;
333+
334+ for (i = 0; i < nbox; i++) {
335+ /* src */
336+ if ((pbox[i].x2 + dx + src_off_x) >= pExaScr->info->maxX ||
337+ (pbox[i].y2 + dy + src_off_y) >= pExaScr->info->maxY)
338+ goto fallback;
339+
340+ /* dst */
341+ if ((pbox[i].x2 + dst_off_x) >= pExaScr->info->maxX ||
342+ (pbox[i].y2 + dst_off_y) >= pExaScr->info->maxY)
343+ goto fallback;
344+ }
345 }
346
347+ exaDoMigration (pixmaps, 2, TRUE);
348+
349 /* Mixed directions must be handled specially if the card is lame */
350 if ((pExaScr->info->flags & EXA_TWO_BITBLT_DIRECTIONS) &&
351 reverse != upsidedown) {
352@@ -860,16 +884,23 @@ exaImageGlyphBlt (DrawablePtr pDrawable,
353 FbBits depthMask;
354 PixmapPtr pPixmap = exaGetDrawablePixmap(pDrawable);
355 ExaPixmapPriv(pPixmap);
356- RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
357- BoxRec extents = *REGION_EXTENTS(pScreen, pending_damage);
358+ RegionPtr pending_damage = NULL;
359+ BoxRec extents;
360 int xoff, yoff;
361
362- if (extents.x1 >= extents.x2 || extents.y1 >= extents.y2)
363- return;
364+ if (pExaPixmap->pDamage)
365+ pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
366+
367+ if (pending_damage) {
368+ extents = *REGION_EXTENTS(pScreen, pending_damage);
369+
370+ if (extents.x1 >= extents.x2 || extents.y1 >= extents.y2)
371+ return;
372
373- depthMask = FbFullMask(pDrawable->depth);
374+ depthMask = FbFullMask(pDrawable->depth);
375+ }
376
377- if ((pGC->planemask & depthMask) != depthMask)
378+ if (!pending_damage || (pGC->planemask & depthMask) != depthMask)
379 {
380 ExaCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase);
381 return;
382@@ -1103,6 +1134,7 @@ exaFillRegionTiled (DrawablePtr pDrawable,
383 int nbox = REGION_NUM_RECTS (pRegion);
384 BoxPtr pBox = REGION_RECTS (pRegion);
385 Bool ret = FALSE;
386+ int i;
387
388 tileWidth = pTile->drawable.width;
389 tileHeight = pTile->drawable.height;
390@@ -1125,14 +1157,11 @@ exaFillRegionTiled (DrawablePtr pDrawable,
391 pixmaps[1].pPix = pTile;
392 pixmaps[1].pReg = NULL;
393
394- exaGetDrawableDeltas(pDrawable, pPixmap, &xoff, &yoff);
395- REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
396-
397 pExaPixmap = ExaGetPixmapPriv (pPixmap);
398
399 if (pExaPixmap->accel_blocked || pTileExaPixmap->accel_blocked)
400 {
401- goto out;
402+ return FALSE;
403 } else {
404 exaDoMigration (pixmaps, 2, TRUE);
405 }
406@@ -1140,24 +1169,33 @@ exaFillRegionTiled (DrawablePtr pDrawable,
407 pPixmap = exaGetOffscreenPixmap (pDrawable, &xoff, &yoff);
408
409 if (!pPixmap || !exaPixmapIsOffscreen(pTile))
410- goto out;
411+ return FALSE;
412
413 if ((*pExaScr->info->PrepareCopy) (pTile, pPixmap, 1, 1, alu, planemask))
414 {
415- while (nbox--)
416+ if (xoff || yoff)
417+ REGION_TRANSLATE(pScreen, pRegion, xoff, yoff);
418+
419+ for (i = 0; i < nbox; i++)
420 {
421- int height = pBox->y2 - pBox->y1;
422- int dstY = pBox->y1;
423+ int height = pBox[i].y2 - pBox[i].y1;
424+ int dstY = pBox[i].y1;
425 int tileY;
426
427+ if (alu == GXcopy)
428+ height = min(height, tileHeight);
429+
430 modulus(dstY - yoff - pDrawable->y - pPatOrg->y, tileHeight, tileY);
431
432 while (height > 0) {
433- int width = pBox->x2 - pBox->x1;
434- int dstX = pBox->x1;
435+ int width = pBox[i].x2 - pBox[i].x1;
436+ int dstX = pBox[i].x1;
437 int tileX;
438 int h = tileHeight - tileY;
439
440+ if (alu == GXcopy)
441+ width = min(width, tileWidth);
442+
443 if (h > height)
444 h = height;
445 height -= h;
446@@ -1179,17 +1217,57 @@ exaFillRegionTiled (DrawablePtr pDrawable,
447 dstY += h;
448 tileY = 0;
449 }
450- pBox++;
451 }
452 (*pExaScr->info->DoneCopy) (pPixmap);
453+
454+ /* With GXcopy, we only need to do the basic algorithm up to the tile
455+ * size; then, we can just keep doubling the destination in each
456+ * direction until it fills the box. This way, the number of copy
457+ * operations is O(log(rx)) + O(log(ry)) instead of O(rx * ry), where
458+ * rx/ry is the ratio between box and tile width/height. This can make
459+ * a big difference if each driver copy incurs a significant constant
460+ * overhead.
461+ */
462+ if (alu != GXcopy)
463+ ret = TRUE;
464+ else if ((*pExaScr->info->PrepareCopy) (pPixmap, pPixmap, 1, 1, alu,
465+ planemask)) {
466+ for (i = 0; i < nbox; i++)
467+ {
468+ int dstX = pBox[i].x1 + tileWidth;
469+ int dstY = pBox[i].y1 + tileHeight;
470+ int width = min(pBox[i].x2 - dstX, tileWidth);
471+ int height = min(pBox[i].y2 - pBox[i].y1, tileHeight);
472+
473+ while (dstX < pBox[i].x2) {
474+ (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
475+ dstX, pBox[i].y1, width, height);
476+ dstX += width;
477+ width = min(pBox[i].x2 - dstX, width * 2);
478+ }
479+
480+ width = pBox[i].x2 - pBox[i].x1;
481+ height = min(pBox[i].y2 - dstY, tileHeight);
482+
483+ while (dstY < pBox[i].y2) {
484+ (*pExaScr->info->Copy) (pPixmap, pBox[i].x1, pBox[i].y1,
485+ pBox[i].x1, dstY, width, height);
486+ dstY += height;
487+ height = min(pBox[i].y2 - dstY, height * 2);
488+ }
489+ }
490+
491+ (*pExaScr->info->DoneCopy) (pPixmap);
492+
493+ ret = TRUE;
494+ }
495+
496 exaMarkSync(pDrawable->pScreen);
497
498- ret = TRUE;
499+ if (xoff || yoff)
500+ REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
501 }
502
503-out:
504- REGION_TRANSLATE(pScreen, pRegion, -xoff, -yoff);
505-
506 return ret;
507 }
508
453260b6
AM
509diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c
510new file mode 100644
33d29f3f 511index 0000000..b23e7f6
453260b6
AM
512--- /dev/null
513+++ b/exa/exa_glyphs.c
33d29f3f 514@@ -0,0 +1,897 @@
453260b6
AM
515+/*
516+ * Copyright © 2008 Red Hat, Inc.
517+ * Partly based on code Copyright © 2000 SuSE, Inc.
518+ *
519+ * Permission to use, copy, modify, distribute, and sell this software and its
520+ * documentation for any purpose is hereby granted without fee, provided that
521+ * the above copyright notice appear in all copies and that both that
522+ * copyright notice and this permission notice appear in supporting
523+ * documentation, and that the name of Red Hat not be used in advertising or
524+ * publicity pertaining to distribution of the software without specific,
525+ * written prior permission. Red Hat makes no representations about the
526+ * suitability of this software for any purpose. It is provided "as is"
527+ * without express or implied warranty.
528+ *
529+ * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
530+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat
531+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
532+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
533+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
534+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
535+ *
536+ * Permission to use, copy, modify, distribute, and sell this software and its
537+ * documentation for any purpose is hereby granted without fee, provided that
538+ * the above copyright notice appear in all copies and that both that
539+ * copyright notice and this permission notice appear in supporting
540+ * documentation, and that the name of SuSE not be used in advertising or
541+ * publicity pertaining to distribution of the software without specific,
542+ * written prior permission. SuSE makes no representations about the
543+ * suitability of this software for any purpose. It is provided "as is"
544+ * without express or implied warranty.
545+ *
546+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
547+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
548+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
549+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
550+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
551+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
552+ *
553+ * Author: Owen Taylor <otaylor@fishsoup.net>
554+ * Based on code by: Keith Packard
555+ */
556+
557+#ifdef HAVE_DIX_CONFIG_H
558+#include <dix-config.h>
559+#endif
560+
561+#include <stdlib.h>
562+
563+#include "exa_priv.h"
564+
565+#include "mipict.h"
566+
567+#if DEBUG_GLYPH_CACHE
568+#define DBG_GLYPH_CACHE(a) ErrorF a
569+#else
570+#define DBG_GLYPH_CACHE(a)
571+#endif
572+
453260b6
AM
573+/* Width of the pixmaps we use for the caches; this should be less than
574+ * max texture size of the driver; this may need to actually come from
575+ * the driver.
576+ */
577+#define CACHE_PICTURE_WIDTH 1024
578+
579+/* Maximum number of glyphs we buffer on the stack before flushing
580+ * rendering to the mask or destination surface.
581+ */
582+#define GLYPH_BUFFER_SIZE 256
583+
584+typedef struct {
585+ PicturePtr source;
33d29f3f 586+ ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE];
453260b6
AM
587+ int count;
588+} ExaGlyphBuffer, *ExaGlyphBufferPtr;
589+
590+typedef enum {
591+ ExaGlyphSuccess, /* Glyph added to render buffer */
592+ ExaGlyphFail, /* out of memory, etc */
593+ ExaGlyphNeedFlush, /* would evict a glyph already in the buffer */
594+} ExaGlyphCacheResult;
595+
596+void
597+exaGlyphsInit(ScreenPtr pScreen)
598+{
599+ ExaScreenPriv(pScreen);
600+ int i = 0;
601+
602+ memset(pExaScr->glyphCaches, 0, sizeof(pExaScr->glyphCaches));
603+
604+ pExaScr->glyphCaches[i].format = PICT_a8;
605+ pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16;
606+ i++;
607+ pExaScr->glyphCaches[i].format = PICT_a8;
608+ pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32;
609+ i++;
610+ pExaScr->glyphCaches[i].format = PICT_a8r8g8b8;
611+ pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16;
612+ i++;
613+ pExaScr->glyphCaches[i].format = PICT_a8r8g8b8;
614+ pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32;
615+ i++;
616+
617+ assert(i == EXA_NUM_GLYPH_CACHES);
618+
619+ for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
620+ pExaScr->glyphCaches[i].columns = CACHE_PICTURE_WIDTH / pExaScr->glyphCaches[i].glyphWidth;
621+ pExaScr->glyphCaches[i].size = 256;
622+ pExaScr->glyphCaches[i].hashSize = 557;
623+ }
624+}
625+
626+static void
627+exaUnrealizeGlyphCaches(ScreenPtr pScreen,
628+ unsigned int format)
629+{
630+ ExaScreenPriv(pScreen);
631+ int i;
632+
633+ for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
634+ ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
635+
636+ if (cache->format != format)
637+ continue;
638+
639+ if (cache->picture) {
640+ FreePicture ((pointer) cache->picture, (XID) 0);
641+ cache->picture = NULL;
642+ }
643+
644+ if (cache->hashEntries) {
645+ xfree(cache->hashEntries);
646+ cache->hashEntries = NULL;
647+ }
648+
649+ if (cache->glyphs) {
650+ xfree(cache->glyphs);
651+ cache->glyphs = NULL;
652+ }
653+ cache->glyphCount = 0;
654+ }
655+}
656+
657+/* All caches for a single format share a single pixmap for glyph storage,
658+ * allowing mixing glyphs of different sizes without paying a penalty
659+ * for switching between source pixmaps. (Note that for a size of font
660+ * right at the border between two sizes, we might be switching for almost
661+ * every glyph.)
662+ *
663+ * This function allocates the storage pixmap, and then fills in the
664+ * rest of the allocated structures for all caches with the given format.
665+ */
666+static Bool
667+exaRealizeGlyphCaches(ScreenPtr pScreen,
668+ unsigned int format)
669+{
670+ ExaScreenPriv(pScreen);
671+
672+ int depth = PIXMAN_FORMAT_DEPTH(format);
673+ PictFormatPtr pPictFormat;
674+ PixmapPtr pPixmap;
675+ PicturePtr pPicture;
676+ int height;
677+ int i;
678+ int error;
679+
680+ pPictFormat = PictureMatchFormat(pScreen, depth, format);
681+ if (!pPictFormat)
682+ return FALSE;
683+
684+ /* Compute the total vertical size needed for the format */
685+
686+ height = 0;
687+ for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
688+ ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
689+ int rows;
33d29f3f 690+
453260b6
AM
691+ if (cache->format != format)
692+ continue;
693+
33d29f3f 694+ cache->yOffset = height;
453260b6 695+
33d29f3f 696+ rows = (cache->size + cache->columns - 1) / cache->columns;
453260b6
AM
697+ height += rows * cache->glyphHeight;
698+ }
699+
700+ /* Now allocate the pixmap and picture */
701+
702+ pPixmap = (*pScreen->CreatePixmap) (pScreen,
703+ CACHE_PICTURE_WIDTH,
704+ height, depth, 0);
705+ if (!pPixmap)
706+ return FALSE;
707+
708+ pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
709+ 0, 0, serverClient, &error);
710+
711+ (*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */
712+
713+ if (!pPicture)
714+ return FALSE;
715+
716+ /* And store the picture in all the caches for the format */
717+
718+ for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
719+ ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
720+ int j;
721+
722+ if (cache->format != format)
723+ continue;
724+
725+ cache->picture = pPicture;
726+ cache->picture->refcnt++;
727+ cache->hashEntries = xalloc(sizeof(int) * cache->hashSize);
728+ cache->glyphs = xalloc(sizeof(ExaCachedGlyphRec) * cache->size);
729+ cache->glyphCount = 0;
730+
731+ if (!cache->hashEntries || !cache->glyphs)
732+ goto bail;
733+
734+ for (j = 0; j < cache->hashSize; j++)
735+ cache->hashEntries[j] = -1;
736+
737+ cache->evictionPosition = rand() % cache->size;
738+ }
739+
740+ /* Each cache references the picture individually */
741+ FreePicture ((pointer) pPicture, (XID) 0);
742+ return TRUE;
743+
744+bail:
745+ exaUnrealizeGlyphCaches(pScreen, format);
746+ return FALSE;
747+}
748+
749+void
750+exaGlyphsFini (ScreenPtr pScreen)
751+{
752+ ExaScreenPriv(pScreen);
753+ int i;
754+
755+ for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
756+ ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
757+
758+ if (cache->picture)
759+ exaUnrealizeGlyphCaches(pScreen, cache->format);
760+ }
761+}
762+
763+static int
764+exaGlyphCacheHashLookup(ExaGlyphCachePtr cache,
765+ GlyphPtr pGlyph)
766+{
767+ int slot;
768+
769+ slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
770+
771+ while (TRUE) { /* hash table can never be full */
772+ int entryPos = cache->hashEntries[slot];
773+ if (entryPos == -1)
774+ return -1;
775+
776+ if (memcmp(pGlyph->sha1, cache->glyphs[entryPos].sha1, sizeof(pGlyph->sha1)) == 0){
453260b6
AM
777+ return entryPos;
778+ }
779+
453260b6
AM
780+ slot--;
781+ if (slot < 0)
782+ slot = cache->hashSize - 1;
783+ }
784+}
785+
786+static void
787+exaGlyphCacheHashInsert(ExaGlyphCachePtr cache,
788+ GlyphPtr pGlyph,
789+ int pos)
790+{
791+ int slot;
792+
793+ memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1));
794+
795+ slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
796+
797+ while (TRUE) { /* hash table can never be full */
798+ if (cache->hashEntries[slot] == -1) {
453260b6
AM
799+ cache->hashEntries[slot] = pos;
800+ return;
801+ }
802+
803+ slot--;
804+ if (slot < 0)
805+ slot = cache->hashSize - 1;
806+ }
807+}
808+
809+static void
810+exaGlyphCacheHashRemove(ExaGlyphCachePtr cache,
811+ int pos)
812+{
813+ int slot;
814+ int emptiedSlot = -1;
815+
816+ slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize;
817+
818+ while (TRUE) { /* hash table can never be full */
819+ int entryPos = cache->hashEntries[slot];
820+
821+ if (entryPos == -1)
822+ return;
823+
824+ if (entryPos == pos) {
825+ cache->hashEntries[slot] = -1;
826+ emptiedSlot = slot;
827+ } else if (emptiedSlot != -1) {
828+ /* See if we can move this entry into the emptied slot, we can't
829+ * do that if if entry would have hashed between the current position
830+ * and the emptied slot. (taking wrapping into account). Bad positions
831+ * are:
832+ *
833+ * | XXXXXXXXXX |
834+ * i j
835+ *
836+ * |XXX XXXX|
837+ * j i
838+ *
839+ * i - slot, j - emptiedSlot
840+ *
841+ * (Knuth 6.4R)
842+ */
843+
844+ int entrySlot = (*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize;
845+
846+ if (!((entrySlot >= slot && entrySlot < emptiedSlot) ||
847+ (emptiedSlot < slot && (entrySlot < emptiedSlot || entrySlot >= slot))))
848+ {
849+ cache->hashEntries[emptiedSlot] = entryPos;
850+ cache->hashEntries[slot] = -1;
851+ emptiedSlot = slot;
852+ }
853+ }
854+
855+ slot--;
856+ if (slot < 0)
857+ slot = cache->hashSize - 1;
858+ }
859+}
860+
33d29f3f
AM
861+#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth)
862+#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight)
863+
864+/* The most efficient thing to way to upload the glyph to the screen
865+ * is to use the UploadToScreen() driver hook; this allows us to
866+ * pipeline glyph uploads and to avoid creating offscreen pixmaps for
867+ * glyphs that we'll never use again.
868+ */
869+static Bool
870+exaGlyphCacheUploadGlyph(ScreenPtr pScreen,
871+ ExaGlyphCachePtr cache,
872+ int pos,
873+ GlyphPtr pGlyph)
874+{
875+ ExaScreenPriv(pScreen);
876+ PicturePtr pGlyphPicture = GlyphPicture(pGlyph)[pScreen->myNum];
877+ PixmapPtr pGlyphPixmap = (PixmapPtr)pGlyphPicture->pDrawable;
878+ ExaPixmapPriv(pGlyphPixmap);
879+ PixmapPtr pCachePixmap = (PixmapPtr)cache->picture->pDrawable;
880+ ExaMigrationRec pixmaps[1];
881+
882+ if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut || pExaPixmap->accel_blocked)
883+ return FALSE;
884+
885+ /* If the glyph pixmap is already uploaded, no point in doing
886+ * things this way */
887+ if (exaPixmapIsOffscreen(pGlyphPixmap))
888+ return FALSE;
889+
890+ /* UploadToScreen only works if bpp match */
891+ if (pGlyphPixmap->drawable.bitsPerPixel != pCachePixmap->drawable.bitsPerPixel)
892+ return FALSE;
893+
894+ /* cache pixmap must be offscreen. */
895+ pixmaps[0].as_dst = TRUE;
896+ pixmaps[0].as_src = FALSE;
897+ pixmaps[0].pPix = pCachePixmap;
898+ pixmaps[0].pReg = NULL;
899+ exaDoMigration (pixmaps, 1, TRUE);
900+
901+ if (!exaPixmapIsOffscreen(pCachePixmap))
902+ return FALSE;
903+
904+ /* CACHE_{X,Y} are in pixmap coordinates, no need for cache{X,Y}off */
905+ if (!pExaScr->info->UploadToScreen(pCachePixmap,
906+ CACHE_X(pos),
907+ CACHE_Y(pos),
908+ pGlyph->info.width,
909+ pGlyph->info.height,
910+ (char *)pExaPixmap->sys_ptr,
911+ pExaPixmap->sys_pitch))
912+ return FALSE;
913+
914+ /* This pixmap should never be bound to a window, so no need to offset coordinates. */
915+ exaPixmapDirty (pCachePixmap,
916+ CACHE_X(pos),
917+ CACHE_Y(pos),
918+ CACHE_X(pos) + pGlyph->info.width,
919+ CACHE_Y(pos) + pGlyph->info.height);
920+
921+ return TRUE;
922+}
923+
453260b6
AM
924+static ExaGlyphCacheResult
925+exaGlyphCacheBufferGlyph(ScreenPtr pScreen,
926+ ExaGlyphCachePtr cache,
927+ ExaGlyphBufferPtr buffer,
928+ GlyphPtr pGlyph,
929+ int xGlyph,
930+ int yGlyph)
931+{
33d29f3f 932+ ExaCompositeRectPtr rect;
453260b6
AM
933+ int pos;
934+
935+ if (buffer->source && buffer->source != cache->picture)
936+ return ExaGlyphNeedFlush;
937+
938+ if (!cache->picture) {
939+ if (!exaRealizeGlyphCaches(pScreen, cache->format))
940+ return ExaGlyphFail;
941+ }
942+
943+ DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n",
944+ cache->glyphWidth, cache->glyphHeight, cache->format == PICT_a8 ? "A" : "ARGB",
945+ (long)*(CARD32 *) pGlyph->sha1));
946+
947+ pos = exaGlyphCacheHashLookup(cache, pGlyph);
948+ if (pos != -1) {
949+ DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos));
950+ } else {
951+ if (cache->glyphCount < cache->size) {
952+ /* Space remaining; we fill from the start */
953+ pos = cache->glyphCount;
954+ cache->glyphCount++;
955+ DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos));
956+
957+ exaGlyphCacheHashInsert(cache, pGlyph, pos);
958+
959+ } else {
960+ /* Need to evict an entry. We have to see if any glyphs
961+ * already in the output buffer were at this position in
962+ * the cache
963+ */
964+
965+ pos = cache->evictionPosition;
966+ DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos));
967+ if (buffer->count) {
968+ int x, y;
969+ int i;
970+
33d29f3f
AM
971+ x = CACHE_X(pos);
972+ y = CACHE_Y(pos);
453260b6
AM
973+
974+ for (i = 0; i < buffer->count; i++) {
33d29f3f 975+ if (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y) {
453260b6
AM
976+ DBG_GLYPH_CACHE((" must flush buffer\n"));
977+ return ExaGlyphNeedFlush;
978+ }
979+ }
980+ }
981+
982+ /* OK, we're all set, swap in the new glyph */
983+ exaGlyphCacheHashRemove(cache, pos);
984+ exaGlyphCacheHashInsert(cache, pGlyph, pos);
985+
986+ /* And pick a new eviction position */
987+ cache->evictionPosition = rand() % cache->size;
988+ }
989+
33d29f3f
AM
990+ /* Now actually upload the glyph into the cache picture; if
991+ * we can't do it with UploadToScreen (because the glyph is
992+ * offscreen, etc), we fall back to CompositePicture.
993+ */
994+ if (!exaGlyphCacheUploadGlyph(pScreen, cache, pos, pGlyph)) {
995+ CompositePicture (PictOpSrc,
996+ GlyphPicture(pGlyph)[pScreen->myNum],
997+ None,
998+ cache->picture,
999+ 0, 0,
1000+ 0, 0,
1001+ CACHE_X(pos),
1002+ CACHE_Y(pos),
1003+ pGlyph->info.width,
1004+ pGlyph->info.height);
1005+ }
453260b6 1006+
453260b6
AM
1007+ }
1008+
1009+
1010+ buffer->source = cache->picture;
1011+
33d29f3f
AM
1012+ rect = &buffer->rects[buffer->count];
1013+ rect->xSrc = CACHE_X(pos);
1014+ rect->ySrc = CACHE_Y(pos);
1015+ rect->xDst = xGlyph - pGlyph->info.x;
1016+ rect->yDst = yGlyph - pGlyph->info.y;
1017+ rect->width = pGlyph->info.width;
1018+ rect->height = pGlyph->info.height;
453260b6
AM
1019+
1020+ buffer->count++;
1021+
1022+ return ExaGlyphSuccess;
1023+}
1024+
33d29f3f
AM
1025+#undef CACHE_X
1026+#undef CACHE_Y
1027+
453260b6
AM
1028+static ExaGlyphCacheResult
1029+exaBufferGlyph(ScreenPtr pScreen,
1030+ ExaGlyphBufferPtr buffer,
1031+ GlyphPtr pGlyph,
1032+ int xGlyph,
1033+ int yGlyph)
1034+{
1035+ ExaScreenPriv(pScreen);
1036+ unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format;
1037+ int width = pGlyph->info.width;
33d29f3f
AM
1038+ int height = pGlyph->info.height;
1039+ ExaCompositeRectPtr rect;
453260b6
AM
1040+ PicturePtr source;
1041+ int i;
1042+
1043+ if (buffer->count == GLYPH_BUFFER_SIZE)
1044+ return ExaGlyphNeedFlush;
33d29f3f
AM
1045+
1046+ if (PICT_FORMAT_BPP(format) == 1)
1047+ format = PICT_a8;
453260b6
AM
1048+
1049+ for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
1050+ ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
1051+
1052+ if (format == cache->format &&
1053+ width <= cache->glyphWidth &&
1054+ height <= cache->glyphHeight) {
1055+ ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen, &pExaScr->glyphCaches[i],
1056+ buffer,
1057+ pGlyph, xGlyph, yGlyph);
1058+ switch (result) {
1059+ case ExaGlyphFail:
1060+ break;
1061+ case ExaGlyphSuccess:
1062+ case ExaGlyphNeedFlush:
1063+ return result;
1064+ }
1065+ }
1066+ }
1067+
1068+ /* Couldn't find the glyph in the cache, use the glyph picture directly */
1069+
1070+ source = GlyphPicture(pGlyph)[pScreen->myNum];
1071+ if (buffer->source && buffer->source != source)
1072+ return ExaGlyphNeedFlush;
1073+
1074+ buffer->source = source;
1075+
33d29f3f
AM
1076+ rect = &buffer->rects[buffer->count];
1077+ rect->xSrc = 0;
1078+ rect->ySrc = 0;
1079+ rect->xDst = xGlyph - pGlyph->info.x;
1080+ rect->yDst = yGlyph - pGlyph->info.y;
1081+ rect->width = pGlyph->info.width;
1082+ rect->height = pGlyph->info.height;
453260b6
AM
1083+
1084+ buffer->count++;
1085+
1086+ return ExaGlyphSuccess;
1087+}
1088+
1089+static void
1090+exaGlyphsToMask(PicturePtr pMask,
1091+ ExaGlyphBufferPtr buffer)
1092+{
33d29f3f
AM
1093+ exaCompositeRects(PictOpAdd, buffer->source, pMask,
1094+ buffer->count, buffer->rects);
1095+
1096+ buffer->count = 0;
1097+ buffer->source = NULL;
1098+}
453260b6
AM
1099+
1100+static void
1101+exaGlyphsToDst(CARD8 op,
1102+ PicturePtr pSrc,
1103+ PicturePtr pDst,
1104+ ExaGlyphBufferPtr buffer,
1105+ INT16 xSrc,
1106+ INT16 ySrc,
1107+ INT16 xDst,
1108+ INT16 yDst)
1109+{
1110+ int i;
1111+
1112+ for (i = 0; i < buffer->count; i++) {
33d29f3f 1113+ ExaCompositeRectPtr rect = &buffer->rects[i];
453260b6
AM
1114+
1115+ CompositePicture (op,
1116+ pSrc,
1117+ buffer->source,
1118+ pDst,
33d29f3f
AM
1119+ xSrc + rect->xDst - xDst,
1120+ ySrc + rect->yDst - yDst,
1121+ rect->xSrc,
1122+ rect->ySrc,
1123+ rect->xDst,
1124+ rect->yDst,
1125+ rect->width,
1126+ rect->height);
453260b6
AM
1127+ }
1128+
1129+ buffer->count = 0;
1130+ buffer->source = NULL;
1131+}
1132+
1133+/* Cut and paste from render/glyph.c - probably should export it instead */
1134+static void
1135+GlyphExtents (int nlist,
1136+ GlyphListPtr list,
1137+ GlyphPtr *glyphs,
1138+ BoxPtr extents)
1139+{
1140+ int x1, x2, y1, y2;
1141+ int n;
1142+ GlyphPtr glyph;
1143+ int x, y;
1144+
1145+ x = 0;
1146+ y = 0;
1147+ extents->x1 = MAXSHORT;
1148+ extents->x2 = MINSHORT;
1149+ extents->y1 = MAXSHORT;
1150+ extents->y2 = MINSHORT;
1151+ while (nlist--)
1152+ {
1153+ x += list->xOff;
1154+ y += list->yOff;
1155+ n = list->len;
1156+ list++;
1157+ while (n--)
1158+ {
1159+ glyph = *glyphs++;
1160+ x1 = x - glyph->info.x;
1161+ if (x1 < MINSHORT)
1162+ x1 = MINSHORT;
1163+ y1 = y - glyph->info.y;
1164+ if (y1 < MINSHORT)
1165+ y1 = MINSHORT;
1166+ x2 = x1 + glyph->info.width;
1167+ if (x2 > MAXSHORT)
1168+ x2 = MAXSHORT;
1169+ y2 = y1 + glyph->info.height;
1170+ if (y2 > MAXSHORT)
1171+ y2 = MAXSHORT;
1172+ if (x1 < extents->x1)
1173+ extents->x1 = x1;
1174+ if (x2 > extents->x2)
1175+ extents->x2 = x2;
1176+ if (y1 < extents->y1)
1177+ extents->y1 = y1;
1178+ if (y2 > extents->y2)
1179+ extents->y2 = y2;
1180+ x += glyph->info.xOff;
1181+ y += glyph->info.yOff;
1182+ }
1183+ }
1184+}
1185+
33d29f3f
AM
1186+/**
1187+ * Returns TRUE if the glyphs in the lists intersect. Only checks based on
1188+ * bounding box, which appears to be good enough to catch most cases at least.
1189+ */
1190+static Bool
1191+exaGlyphsIntersect(int nlist, GlyphListPtr list, GlyphPtr *glyphs)
1192+{
1193+ int x1, x2, y1, y2;
1194+ int n;
1195+ GlyphPtr glyph;
1196+ int x, y;
1197+ BoxRec extents;
1198+ Bool first = TRUE;
1199+
1200+ x = 0;
1201+ y = 0;
1202+ while (nlist--) {
1203+ x += list->xOff;
1204+ y += list->yOff;
1205+ n = list->len;
1206+ list++;
1207+ while (n--) {
1208+ glyph = *glyphs++;
1209+
1210+ if (glyph->info.width == 0 || glyph->info.height == 0) {
1211+ x += glyph->info.xOff;
1212+ y += glyph->info.yOff;
1213+ continue;
1214+ }
1215+
1216+ x1 = x - glyph->info.x;
1217+ if (x1 < MINSHORT)
1218+ x1 = MINSHORT;
1219+ y1 = y - glyph->info.y;
1220+ if (y1 < MINSHORT)
1221+ y1 = MINSHORT;
1222+ x2 = x1 + glyph->info.width;
1223+ if (x2 > MAXSHORT)
1224+ x2 = MAXSHORT;
1225+ y2 = y1 + glyph->info.height;
1226+ if (y2 > MAXSHORT)
1227+ y2 = MAXSHORT;
1228+
1229+ if (first) {
1230+ extents.x1 = x1;
1231+ extents.y1 = y1;
1232+ extents.x2 = x2;
1233+ extents.y2 = y2;
1234+ first = FALSE;
1235+ } else {
1236+ if (x1 < extents.x2 && x2 > extents.x1 &&
1237+ y1 < extents.y2 && y2 > extents.y1)
1238+ {
1239+ return TRUE;
1240+ }
1241+
1242+ if (x1 < extents.x1)
1243+ extents.x1 = x1;
1244+ if (x2 > extents.x2)
1245+ extents.x2 = x2;
1246+ if (y1 < extents.y1)
1247+ extents.y1 = y1;
1248+ if (y2 > extents.y2)
1249+ extents.y2 = y2;
1250+ }
1251+ x += glyph->info.xOff;
1252+ y += glyph->info.yOff;
1253+ }
1254+ }
1255+
1256+ return FALSE;
1257+}
1258+
453260b6
AM
1259+#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
1260+
1261+void
1262+exaGlyphs (CARD8 op,
1263+ PicturePtr pSrc,
1264+ PicturePtr pDst,
1265+ PictFormatPtr maskFormat,
1266+ INT16 xSrc,
1267+ INT16 ySrc,
1268+ int nlist,
1269+ GlyphListPtr list,
1270+ GlyphPtr *glyphs)
1271+{
1272+ PicturePtr pPicture;
1273+ PixmapPtr pMaskPixmap = 0;
1274+ PicturePtr pMask;
1275+ ScreenPtr pScreen = pDst->pDrawable->pScreen;
1276+ int width = 0, height = 0;
1277+ int x, y;
1278+ int xDst = list->xOff, yDst = list->yOff;
1279+ int n;
1280+ GlyphPtr glyph;
1281+ int error;
1282+ BoxRec extents = {0, 0, 0, 0};
1283+ CARD32 component_alpha;
1284+ ExaGlyphBuffer buffer;
1285+
33d29f3f
AM
1286+ /* If we don't have a mask format but all the glyphs have the same format
1287+ * and don't intersect, use the glyph format as mask format for the full
1288+ * benefits of the glyph cache.
1289+ */
1290+ if (!maskFormat) {
1291+ Bool sameFormat = TRUE;
1292+ int i;
1293+
1294+ maskFormat = list[0].format;
1295+
1296+ for (i = 0; i < nlist; i++) {
1297+ if (maskFormat->format != list[i].format->format) {
1298+ sameFormat = FALSE;
1299+ break;
1300+ }
1301+ }
1302+
1303+ if (!sameFormat || (maskFormat->depth != 1 &&
1304+ exaGlyphsIntersect(nlist, list, glyphs))) {
1305+ maskFormat = NULL;
1306+ }
1307+ }
1308+
453260b6
AM
1309+ if (maskFormat)
1310+ {
1311+ GCPtr pGC;
1312+ xRectangle rect;
1313+
1314+ GlyphExtents (nlist, list, glyphs, &extents);
1315+
1316+ if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
1317+ return;
1318+ width = extents.x2 - extents.x1;
1319+ height = extents.y2 - extents.y1;
33d29f3f
AM
1320+
1321+ if (maskFormat->depth == 1) {
1322+ PictFormatPtr a8Format = PictureMatchFormat (pScreen, 8, PICT_a8);
1323+
1324+ if (a8Format)
1325+ maskFormat = a8Format;
1326+ }
1327+
453260b6
AM
1328+ pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
1329+ maskFormat->depth,
1330+ CREATE_PIXMAP_USAGE_SCRATCH);
1331+ if (!pMaskPixmap)
1332+ return;
1333+ component_alpha = NeedsComponent(maskFormat->format);
1334+ pMask = CreatePicture (0, &pMaskPixmap->drawable,
1335+ maskFormat, CPComponentAlpha, &component_alpha,
1336+ serverClient, &error);
1337+ if (!pMask)
1338+ {
1339+ (*pScreen->DestroyPixmap) (pMaskPixmap);
1340+ return;
1341+ }
1342+ pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen);
1343+ ValidateGC (&pMaskPixmap->drawable, pGC);
1344+ rect.x = 0;
1345+ rect.y = 0;
1346+ rect.width = width;
1347+ rect.height = height;
1348+ (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
1349+ FreeScratchGC (pGC);
1350+ x = -extents.x1;
1351+ y = -extents.y1;
1352+ }
1353+ else
1354+ {
1355+ pMask = pDst;
1356+ x = 0;
1357+ y = 0;
1358+ }
1359+ buffer.count = 0;
1360+ buffer.source = NULL;
1361+ while (nlist--)
1362+ {
1363+ x += list->xOff;
1364+ y += list->yOff;
1365+ n = list->len;
1366+ while (n--)
1367+ {
1368+ glyph = *glyphs++;
1369+ pPicture = GlyphPicture (glyph)[pScreen->myNum];
1370+
33d29f3f
AM
1371+ if (glyph->info.width > 0 && glyph->info.height > 0 &&
1372+ exaBufferGlyph(pScreen, &buffer, glyph, x, y) == ExaGlyphNeedFlush)
453260b6
AM
1373+ {
1374+ if (maskFormat)
1375+ exaGlyphsToMask(pMask, &buffer);
1376+ else
1377+ exaGlyphsToDst(op, pSrc, pDst, &buffer,
1378+ xSrc, ySrc, xDst, yDst);
1379+
1380+ exaBufferGlyph(pScreen, &buffer, glyph, x, y);
1381+ }
1382+
1383+ x += glyph->info.xOff;
1384+ y += glyph->info.yOff;
1385+ }
1386+ list++;
1387+ }
1388+
1389+ if (maskFormat)
1390+ exaGlyphsToMask(pMask, &buffer);
1391+ else
1392+ exaGlyphsToDst(op, pSrc, pDst, &buffer,
1393+ xSrc, ySrc, xDst, yDst);
1394+
1395+ if (maskFormat)
1396+ {
1397+ x = extents.x1;
1398+ y = extents.y1;
1399+ CompositePicture (op,
1400+ pSrc,
1401+ pMask,
1402+ pDst,
1403+ xSrc + x - xDst,
1404+ ySrc + y - yDst,
1405+ 0, 0,
1406+ x, y,
1407+ width, height);
1408+ FreePicture ((pointer) pMask, (XID) 0);
1409+ (*pScreen->DestroyPixmap) (pMaskPixmap);
1410+ }
1411+}
33d29f3f
AM
1412diff --git a/exa/exa_migration.c b/exa/exa_migration.c
1413index 5f22474..2bb2ad9 100644
1414--- a/exa/exa_migration.c
1415+++ b/exa/exa_migration.c
1416@@ -33,8 +33,6 @@
1417 #include <string.h>
1418
1419 #include "exa_priv.h"
1420-#include <X11/fonts/fontstruct.h>
1421-#include "dixfontstr.h"
1422 #include "exa.h"
1423 #include "cw.h"
1424
1425@@ -45,6 +43,39 @@
1426 #endif
1427
1428 /**
1429+ * Returns TRUE if the pixmap has damage.
1430+ * EXA only migrates the parts of a destination
1431+ * that are affected by rendering.
1432+ * It uses the current damage as indication.
1433+ * So anything that does not need to be updated won't be.
1434+ * For clarity this seperate function was made.
1435+ * Note that some situations don't use this,
1436+ * because their calls are wrapped by the damage layer.
1437+ */
1438+Bool
1439+exaDamageDestForMigration(DrawablePtr pDrawable, PixmapPtr pPix, RegionPtr region)
1440+{
1441+ ScreenPtr pScreen = pDrawable->pScreen;
1442+ (void) pScreen; /* the macros don't use pScreen currently */
1443+ ExaPixmapPriv (pPix);
1444+ int x_offset, y_offset;
1445+ RegionPtr pending_damage;
1446+
1447+ if (!pExaPixmap->pDamage)
1448+ return FALSE;
1449+
1450+ exaGetDrawableDeltas(pDrawable, pPix, &x_offset, &y_offset);
1451+
1452+ REGION_TRANSLATE(pScreen, region, x_offset, y_offset);
1453+ pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
1454+ REGION_UNION(pScreen, pending_damage, pending_damage, region);
1455+ /* Restore region as we got it. */
1456+ REGION_TRANSLATE(pScreen, region, -x_offset, -y_offset);
1457+
1458+ return TRUE;
1459+}
1460+
1461+/**
1462 * Returns TRUE if the pixmap is not movable. This is the case where it's a
1463 * fake pixmap for the frontbuffer (no pixmap private) or it's a scratch
1464 * pixmap created by some other X Server internals (the score says it's
1465@@ -211,9 +242,9 @@ exaCopyDirty(ExaMigrationPtr migrate, RegionPtr pValidDst, RegionPtr pValidSrc,
1466 pBox->x1, pBox->y1,
1467 pBox->x2 - pBox->x1,
1468 pBox->y2 - pBox->y1,
1469- pExaPixmap->sys_ptr
1470+ (char *) (pExaPixmap->sys_ptr
1471 + pBox->y1 * pExaPixmap->sys_pitch
1472- + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8,
1473+ + pBox->x1 * pPixmap->drawable.bitsPerPixel / 8),
1474 pExaPixmap->sys_pitch))
1475 {
1476 if (!access_prepared) {
1477@@ -301,6 +332,9 @@ exaDoMoveInPixmap (ExaMigrationPtr migrate)
1478 ExaScreenPriv (pScreen);
1479 ExaPixmapPriv (pPixmap);
1480
1481+ if (migrate->as_dst)
1482+ pExaPixmap->pendingDamage = TRUE;
1483+
1484 /* If we're VT-switched away, no touching card memory allowed. */
1485 if (pExaScr->swappedOut)
1486 return;
1487@@ -369,6 +403,9 @@ exaDoMoveOutPixmap (ExaMigrationPtr migrate)
1488 PixmapPtr pPixmap = migrate->pPix;
1489 ExaPixmapPriv (pPixmap);
1490
1491+ if (migrate->as_dst)
1492+ pExaPixmap->pendingDamage = TRUE;
1493+
1494 if (!pExaPixmap->area || exaPixmapIsPinned(pPixmap))
1495 return;
1496
453260b6 1497diff --git a/exa/exa_priv.h b/exa/exa_priv.h
33d29f3f 1498index e4b6b54..0ebe07b 100644
453260b6
AM
1499--- a/exa/exa_priv.h
1500+++ b/exa/exa_priv.h
1501@@ -61,6 +61,7 @@
1502 #define DEBUG_MIGRATE 0
1503 #define DEBUG_PIXMAP 0
1504 #define DEBUG_OFFSCREEN 0
1505+#define DEBUG_GLYPH_CACHE 0
1506
1507 #if DEBUG_TRACE_FALL
1508 #define EXA_FALLBACK(x) \
33d29f3f 1509@@ -95,6 +96,38 @@ enum ExaMigrationHeuristic {
453260b6
AM
1510 ExaMigrationSmart
1511 };
1512
1513+typedef struct {
1514+ unsigned char sha1[20];
1515+} ExaCachedGlyphRec, *ExaCachedGlyphPtr;
1516+
1517+typedef struct {
1518+ /* The identity of the cache, statically configured at initialization */
1519+ unsigned int format;
1520+ int glyphWidth;
1521+ int glyphHeight;
1522+
1523+ int size; /* Size of cache; eventually this should be dynamically determined */
1524+
1525+ /* Hash table mapping from glyph sha1 to position in the glyph; we use
1526+ * open addressing with a hash table size determined based on size and large
1527+ * enough so that we always have a good amount of free space, so we can
1528+ * use linear probing. (Linear probing is preferrable to double hashing
1529+ * here because it allows us to easily remove entries.)
1530+ */
1531+ int *hashEntries;
1532+ int hashSize;
1533+
1534+ ExaCachedGlyphPtr glyphs;
1535+ int glyphCount; /* Current number of glyphs */
1536+
1537+ PicturePtr picture; /* Where the glyphs of the cache are stored */
33d29f3f 1538+ int yOffset; /* y location within the picture where the cache starts */
453260b6
AM
1539+ int columns; /* Number of columns the glyphs are layed out in */
1540+ int evictionPosition; /* Next random position to evict a glyph */
1541+} ExaGlyphCacheRec, *ExaGlyphCachePtr;
1542+
1543+#define EXA_NUM_GLYPH_CACHES 4
1544+
1545 typedef void (*EnableDisableFBAccessProcPtr)(int, Bool);
1546 typedef struct {
1547 ExaDriverPtr info;
33d29f3f
AM
1548@@ -114,7 +147,6 @@ typedef struct {
1549 TrianglesProcPtr SavedTriangles;
1550 GlyphsProcPtr SavedGlyphs;
1551 TrapezoidsProcPtr SavedTrapezoids;
1552- AddTrapsProcPtr SavedAddTraps;
1553 #endif
1554
1555 Bool swappedOut;
1556@@ -123,6 +155,8 @@ typedef struct {
453260b6
AM
1557 unsigned disableFbCount;
1558 Bool optimize_migration;
1559 unsigned offScreenCounter;
1560+
1561+ ExaGlyphCacheRec glyphCaches[EXA_NUM_GLYPH_CACHES];
1562 } ExaScreenPrivRec, *ExaScreenPrivPtr;
1563
1564 /*
33d29f3f
AM
1565@@ -192,6 +226,7 @@ typedef struct {
1566 * location.
1567 */
1568 DamagePtr pDamage;
1569+ Bool pendingDamage;
1570 /**
1571 * The valid regions mark the valid bits (at least, as they're derived from
1572 * damage, which may be overreported) of a pixmap's system and FB copies.
1573@@ -210,18 +245,21 @@ typedef struct _ExaMigrationRec {
453260b6
AM
1574 RegionPtr pReg;
1575 } ExaMigrationRec, *ExaMigrationPtr;
1576
1577+typedef struct {
1578+ INT16 xSrc;
1579+ INT16 ySrc;
1580+ INT16 xDst;
1581+ INT16 yDst;
1582+ INT16 width;
1583+ INT16 height;
1584+} ExaCompositeRectRec, *ExaCompositeRectPtr;
1585+
1586 /**
1587 * exaDDXDriverInit must be implemented by the DDX using EXA, and is the place
1588 * to set EXA options or hook in screen functions to handle using EXA as the AA.
33d29f3f
AM
1589 */
1590 void exaDDXDriverInit (ScreenPtr pScreen);
1591
1592-void
1593-exaPrepareAccessWindow(WindowPtr pWin);
1594-
1595-void
1596-exaFinishAccessWindow(WindowPtr pWin);
1597-
1598 /* exa_unaccel.c */
1599 void
1600 exaPrepareAccessGC(GCPtr pGC);
1601@@ -294,13 +332,6 @@ ExaCheckGetSpans (DrawablePtr pDrawable,
1602 int nspans,
1603 char *pdstStart);
1604
1605-void
1606-ExaCheckAddTraps (PicturePtr pPicture,
1607- INT16 x_off,
1608- INT16 y_off,
1609- int ntrap,
1610- xTrap *traps);
1611-
1612 /* exa_accel.c */
1613
1614 static _X_INLINE Bool
1615@@ -422,6 +453,13 @@ exaComposite(CARD8 op,
453260b6
AM
1616 CARD16 height);
1617
1618 void
1619+exaCompositeRects(CARD8 op,
1620+ PicturePtr Src,
1621+ PicturePtr pDst,
1622+ int nrect,
1623+ ExaCompositeRectPtr rects);
1624+
1625+void
1626 exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1627 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1628 int ntrap, xTrapezoid *traps);
33d29f3f
AM
1629@@ -431,6 +469,13 @@ exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1630 PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1631 int ntri, xTriangle *tris);
1632
1633+/* exa_glyph.c */
1634+void
1635+exaGlyphsInit(ScreenPtr pScreen);
1636+
1637+void
1638+exaGlyphsFini (ScreenPtr pScreen);
1639+
1640 void
1641 exaGlyphs (CARD8 op,
1642 PicturePtr pSrc,
1643@@ -449,4 +494,7 @@ exaDoMigration (ExaMigrationPtr pixmaps, int npixmaps, Bool can_accel);
1644 void
1645 exaPixmapSave (ScreenPtr pScreen, ExaOffscreenArea *area);
1646
1647+Bool
1648+exaDamageDestForMigration(DrawablePtr pDrawable, PixmapPtr pPix, RegionPtr region);
1649+
1650 #endif /* EXAPRIV_H */
453260b6 1651diff --git a/exa/exa_render.c b/exa/exa_render.c
33d29f3f 1652index 1d7b897..bafa309 100644
453260b6
AM
1653--- a/exa/exa_render.c
1654+++ b/exa/exa_render.c
1655@@ -332,6 +332,228 @@ exaTryDriverSolidFill(PicturePtr pSrc,
1656 }
1657
1658 static int
1659+exaTryDriverCompositeRects(CARD8 op,
1660+ PicturePtr pSrc,
1661+ PicturePtr pDst,
1662+ int nrect,
1663+ ExaCompositeRectPtr rects)
1664+{
1665+ ExaScreenPriv (pDst->pDrawable->pScreen);
1666+ int src_off_x, src_off_y, dst_off_x, dst_off_y;
1667+ PixmapPtr pSrcPix, pDstPix;
1668+ ExaPixmapPrivPtr pSrcExaPix, pDstExaPix;
1669+ struct _Pixmap scratch;
1670+ ExaMigrationRec pixmaps[2];
1671+
33d29f3f
AM
1672+ if (!pExaScr->info->PrepareComposite)
1673+ return -1;
1674+
453260b6
AM
1675+ pSrcPix = exaGetDrawablePixmap(pSrc->pDrawable);
1676+ pSrcExaPix = ExaGetPixmapPriv(pSrcPix);
1677+
1678+ pDstPix = exaGetDrawablePixmap(pDst->pDrawable);
1679+ pDstExaPix = ExaGetPixmapPriv(pDstPix);
1680+
1681+ /* Check whether the accelerator can use these pixmaps.
1682+ * FIXME: If it cannot, use temporary pixmaps so that the drawing
1683+ * happens within limits.
1684+ */
1685+ if (pSrcExaPix->accel_blocked ||
1686+ pDstExaPix->accel_blocked)
1687+ {
1688+ return -1;
1689+ }
1690+
1691+ if (pExaScr->info->CheckComposite &&
1692+ !(*pExaScr->info->CheckComposite) (op, pSrc, NULL, pDst))
1693+ {
1694+ return -1;
1695+ }
1696+
1697+ exaGetDrawableDeltas (pDst->pDrawable, pDstPix, &dst_off_x, &dst_off_y);
1698+
1699+ pixmaps[0].as_dst = TRUE;
1700+ pixmaps[0].as_src = exaOpReadsDestination(op);
1701+ pixmaps[0].pPix = pDstPix;
1702+ pixmaps[0].pReg = NULL;
1703+ pixmaps[1].as_dst = FALSE;
1704+ pixmaps[1].as_src = TRUE;
1705+ pixmaps[1].pPix = pSrcPix;
1706+ pixmaps[1].pReg = NULL;
1707+ exaDoMigration(pixmaps, 2, TRUE);
1708+
1709+ pSrcPix = exaGetOffscreenPixmap (pSrc->pDrawable, &src_off_x, &src_off_y);
1710+ if (!exaPixmapIsOffscreen(pDstPix))
1711+ return 0;
1712+
1713+ if (!pSrcPix && pExaScr->info->UploadToScratch)
1714+ {
1715+ pSrcPix = exaGetDrawablePixmap (pSrc->pDrawable);
1716+ if ((*pExaScr->info->UploadToScratch) (pSrcPix, &scratch))
1717+ pSrcPix = &scratch;
1718+ }
1719+
1720+ if (!pSrcPix)
1721+ return 0;
1722+
1723+ if (!(*pExaScr->info->PrepareComposite) (op, pSrc, NULL, pDst, pSrcPix,
1724+ NULL, pDstPix))
1725+ return -1;
1726+
1727+ while (nrect--)
1728+ {
1729+ INT16 xDst = rects->xDst + pDst->pDrawable->x;
1730+ INT16 yDst = rects->yDst + pDst->pDrawable->y;
1731+ INT16 xSrc = rects->xSrc + pSrc->pDrawable->x;
1732+ INT16 ySrc = rects->ySrc + pSrc->pDrawable->y;
1733+
1734+ RegionRec region;
1735+ BoxPtr pbox;
1736+ int nbox;
1737+
1738+ if (!miComputeCompositeRegion (&region, pSrc, NULL, pDst,
1739+ xSrc, ySrc, 0, 0, xDst, yDst,
1740+ rects->width, rects->height))
1741+ goto next_rect;
1742+
1743+ REGION_TRANSLATE(pScreen, &region, dst_off_x, dst_off_y);
1744+
1745+ nbox = REGION_NUM_RECTS(&region);
1746+ pbox = REGION_RECTS(&region);
1747+
1748+ xSrc = xSrc + src_off_x - xDst - dst_off_x;
1749+ ySrc = ySrc + src_off_y - yDst - dst_off_y;
1750+
1751+ while (nbox--)
1752+ {
1753+ (*pExaScr->info->Composite) (pDstPix,
1754+ pbox->x1 + xSrc,
1755+ pbox->y1 + ySrc,
1756+ 0, 0,
1757+ pbox->x1,
1758+ pbox->y1,
1759+ pbox->x2 - pbox->x1,
1760+ pbox->y2 - pbox->y1);
1761+ pbox++;
1762+ }
1763+
1764+ next_rect:
1765+ REGION_UNINIT(pDst->pDrawable->pScreen, &region);
1766+
1767+ rects++;
1768+ }
1769+
1770+ (*pExaScr->info->DoneComposite) (pDstPix);
1771+ exaMarkSync(pDst->pDrawable->pScreen);
1772+
1773+ return 1;
1774+}
1775+
1776+/**
1777+ * Copy a number of rectangles from source to destination in a single
1778+ * operation. This is specialized for building a glyph mask: we don'y
1779+ * have a mask argument because we don't need it for that, and we
1780+ * don't have he special-case fallbacks found in exaComposite() - if the
1781+ * driver can support it, we use the driver functionality, otherwise we
1782+ * fallback straight to software.
1783+ */
1784+void
1785+exaCompositeRects(CARD8 op,
1786+ PicturePtr pSrc,
1787+ PicturePtr pDst,
1788+ int nrect,
1789+ ExaCompositeRectPtr rects)
1790+{
1791+ PixmapPtr pPixmap = exaGetDrawablePixmap(pDst->pDrawable);
1792+ ExaPixmapPriv(pPixmap);
453260b6 1793+ RegionRec region;
453260b6
AM
1794+ int n;
1795+ ExaCompositeRectPtr r;
1796+
33d29f3f
AM
1797+ if (pExaPixmap->pDamage) {
1798+ int x1 = MAXSHORT;
1799+ int y1 = MAXSHORT;
1800+ int x2 = MINSHORT;
1801+ int y2 = MINSHORT;
1802+ BoxRec box;
1803+
1804+ /* We have to manage the damage ourselves, since CompositeRects isn't
1805+ * something in the screen that can be managed by the damage extension,
1806+ * and EXA depends on damage to track what needs to be migrated between
1807+ * offscreen and onscreen.
1808+ */
453260b6 1809+
33d29f3f
AM
1810+ /* Compute the overall extents of the composited region - we're making
1811+ * the assumption here that we are compositing a bunch of glyphs that
1812+ * cluster closely together and damaging each glyph individually would
1813+ * be a loss compared to damaging the bounding box.
1814+ */
1815+ n = nrect;
1816+ r = rects;
1817+ while (n--) {
1818+ int rect_x2 = r->xDst + r->width;
1819+ int rect_y2 = r->yDst + r->width;
453260b6 1820+
33d29f3f
AM
1821+ if (r->xDst < x1) x1 = r->xDst;
1822+ if (r->xDst < y1) y1 = r->xDst;
1823+ if (rect_x2 > x2) x2 = rect_x2;
1824+ if (rect_y2 > y2) y2 = rect_y2;
453260b6 1825+
33d29f3f
AM
1826+ r++;
1827+ }
453260b6 1828+
33d29f3f
AM
1829+ if (x2 <= x1 && y2 <= y1)
1830+ return;
1831+
1832+ box.x1 = x1;
1833+ box.x2 = x2 < MAXSHORT ? x2 : MAXSHORT;
1834+ box.y1 = y1;
1835+ box.y2 = y2 < MAXSHORT ? y2 : MAXSHORT;
1836+
1837+ /* The pixmap migration code relies on pendingDamage indicating
1838+ * the bounds of the current rendering, so we need to force
1839+ * the actual damage into that region before we do anything, and
1840+ * (see use of DamagePendingRegion in exaCopyDirty)
1841+ */
1842+
1843+ REGION_INIT(pScreen, &region, &box, 1);
1844+
1845+ exaDamageDestForMigration(pDst->pDrawable, pPixmap, &region);
1846+ }
453260b6
AM
1847+
1848+ /************************************************************/
1849+
1850+ ValidatePicture (pSrc);
1851+ ValidatePicture (pDst);
1852+
1853+ if (exaTryDriverCompositeRects(op, pSrc, pDst, nrect, rects) != 1) {
1854+ n = nrect;
1855+ r = rects;
1856+ while (n--) {
1857+ ExaCheckComposite (op, pSrc, NULL, pDst,
1858+ r->xSrc, r->ySrc,
1859+ 0, 0,
1860+ r->xDst, r->yDst,
1861+ r->width, r->height);
1862+ r++;
1863+ }
1864+ }
1865+
1866+ /************************************************************/
1867+
33d29f3f
AM
1868+ if (pExaPixmap->pDamage) {
1869+ /* Now we have to flush the damage out from pendingDamage => damage
1870+ * Calling DamageDamageRegion has that effect. (We could pass
1871+ * in an empty region here, but we pass in the same region we
1872+ * use above; the effect is the same.)
1873+ */
453260b6 1874+
33d29f3f
AM
1875+ DamageDamageRegion(pDst->pDrawable, &region);
1876+ REGION_UNINIT(pScreen, &region);
1877+ }
453260b6
AM
1878+}
1879+
1880+static int
1881 exaTryDriverComposite(CARD8 op,
1882 PicturePtr pSrc,
1883 PicturePtr pMask,
33d29f3f
AM
1884@@ -843,22 +1065,16 @@ exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1885 PixmapPtr pixmap = exaGetDrawablePixmap (pDraw);
1886 ExaPixmapPriv (pixmap);
1887 RegionRec migration;
1888- RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
1889- int xoff, yoff;
1890-
1891- exaGetDrawableDeltas(pDraw, pixmap, &xoff, &yoff);
453260b6 1892
33d29f3f
AM
1893- xoff += pDraw->x;
1894- yoff += pDraw->y;
1895+ if (pExaPixmap->pDamage) {
1896+ bounds.x1 += pDraw->x;
1897+ bounds.y1 += pDraw->y;
1898+ bounds.x2 += pDraw->x;
1899+ bounds.y2 += pDraw->y;
453260b6 1900
33d29f3f
AM
1901- bounds.x1 += xoff;
1902- bounds.y1 += yoff;
1903- bounds.x2 += xoff;
1904- bounds.y2 += yoff;
1905-
1906- REGION_INIT(pScreen, &migration, &bounds, 1);
1907- REGION_UNION(pScreen, pending_damage, pending_damage, &migration);
1908- REGION_UNINIT(pScreen, &migration);
1909+ REGION_INIT(pScreen, &migration, &bounds, 1);
1910+ exaDamageDestForMigration(pDraw, pixmap, &migration);
1911+ }
453260b6 1912
33d29f3f 1913 exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
453260b6 1914
33d29f3f
AM
1915@@ -866,6 +1082,13 @@ exaTrapezoids (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1916 (*ps->RasterizeTrapezoid) (pDst, traps, 0, 0);
453260b6 1917
33d29f3f 1918 exaFinishAccess(pDraw, EXA_PREPARE_DEST);
453260b6 1919+
33d29f3f
AM
1920+ /* Damage manually, because Trapezoids expects to hit Composite normally. */
1921+ /* Composite is wrapped by damage, but Trapezoids isn't. */
1922+ if (pExaPixmap->pDamage) {
1923+ DamageDamageRegion(pDraw, &migration);
1924+ REGION_UNINIT(pScreen, &migration);
453260b6 1925+ }
453260b6 1926 }
33d29f3f
AM
1927 else if (maskFormat)
1928 {
1929@@ -946,26 +1169,27 @@ exaTriangles (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1930 PixmapPtr pixmap = exaGetDrawablePixmap (pDraw);
1931 ExaPixmapPriv (pixmap);
1932 RegionRec migration;
1933- RegionPtr pending_damage = DamagePendingRegion(pExaPixmap->pDamage);
1934- int xoff, yoff;
1935-
1936- exaGetDrawableDeltas(pDraw, pixmap, &xoff, &yoff);
1937-
1938- xoff += pDraw->x;
1939- yoff += pDraw->y;
453260b6 1940
33d29f3f
AM
1941- bounds.x1 += xoff;
1942- bounds.y1 += yoff;
1943- bounds.x2 += xoff;
1944- bounds.y2 += yoff;
1945+ if (pExaPixmap->pDamage) {
1946+ bounds.x1 += pDraw->x;
1947+ bounds.y1 += pDraw->y;
1948+ bounds.x2 += pDraw->x;
1949+ bounds.y2 += pDraw->y;
453260b6 1950
33d29f3f
AM
1951- REGION_INIT(pScreen, &migration, &bounds, 1);
1952- REGION_UNION(pScreen, pending_damage, pending_damage, &migration);
1953- REGION_UNINIT(pScreen, &migration);
1954+ REGION_INIT(pScreen, &migration, &bounds, 1);
1955+ exaDamageDestForMigration(pDraw, pixmap, &migration);
453260b6 1956+ }
453260b6 1957
33d29f3f
AM
1958 exaPrepareAccess(pDraw, EXA_PREPARE_DEST);
1959 (*ps->AddTriangles) (pDst, 0, 0, ntri, tris);
1960 exaFinishAccess(pDraw, EXA_PREPARE_DEST);
1961+
1962+ /* Damage manually, because Triangles expects to hit Composite normally. */
1963+ /* Composite is wrapped by damage, but Triangles isn't. */
1964+ if (pExaPixmap->pDamage) {
1965+ DamageDamageRegion(pDraw, &migration);
1966+ REGION_UNINIT(pScreen, &migration);
1967+ }
1968 }
1969 else if (maskFormat)
1970 {
453260b6 1971diff --git a/exa/exa_unaccel.c b/exa/exa_unaccel.c
33d29f3f 1972index d7bd06c..d5d6a30 100644
453260b6
AM
1973--- a/exa/exa_unaccel.c
1974+++ b/exa/exa_unaccel.c
1975@@ -97,12 +97,15 @@ ExaCheckPutImage (DrawablePtr pDrawable, GCPtr pGC, int depth,
1976 int x, int y, int w, int h, int leftPad, int format,
1977 char *bits)
1978 {
1979+ ExaPixmapPriv(exaGetDrawablePixmap(pDrawable));
1980+
1981 EXA_FALLBACK(("to %p (%c)\n", pDrawable, exaDrawableLocation(pDrawable)));
1982 if (exaGCReadsDestination(pDrawable, pGC->planemask, pGC->fillStyle,
1983 pGC->alu))
1984 exaPrepareAccess (pDrawable, EXA_PREPARE_DEST);
1985 else
1986- ExaDoPrepareAccess (pDrawable, EXA_PREPARE_DEST);
33d29f3f
AM
1987+ exaPrepareAccessReg (pDrawable, EXA_PREPARE_DEST, pExaPixmap->pDamage ?
1988+ DamagePendingRegion(pExaPixmap->pDamage) : NULL);
453260b6
AM
1989 fbPutImage (pDrawable, pGC, depth, x, y, w, h, leftPad, format, bits);
1990 exaFinishAccess (pDrawable, EXA_PREPARE_DEST);
1991 }
33d29f3f
AM
1992@@ -350,20 +353,6 @@ ExaCheckComposite (CARD8 op,
1993 REGION_UNINIT(pScreen, &region);
1994 }
1995
1996-void
1997-ExaCheckAddTraps (PicturePtr pPicture,
1998- INT16 x_off,
1999- INT16 y_off,
2000- int ntrap,
2001- xTrap *traps)
2002-{
2003- EXA_FALLBACK(("to pict %p (%c)\n",
2004- exaDrawableLocation(pPicture->pDrawable)));
2005- exaPrepareAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
2006- fbAddTraps (pPicture, x_off, y_off, ntrap, traps);
2007- exaFinishAccess(pPicture->pDrawable, EXA_PREPARE_DEST);
2008-}
2009-
2010 /**
2011 * Gets the 0,0 pixel of a pixmap. Used for doing solid fills of tiled pixmaps
2012 * that happen to be 1x1. Pixmap must be at least 8bpp.
2013@@ -373,23 +362,22 @@ ExaCheckAddTraps (PicturePtr pPicture,
2014 CARD32
2015 exaGetPixmapFirstPixel (PixmapPtr pPixmap)
2016 {
2017- ExaScreenPriv(pPixmap->drawable.pScreen);
2018 CARD32 pixel;
2019 void *fb;
2020 Bool need_finish = FALSE;
2021 BoxRec box;
2022 RegionRec migration;
2023 ExaPixmapPriv (pPixmap);
2024- Bool sys_valid = !miPointInRegion(&pExaPixmap->validSys, 0, 0, &box);
2025- Bool damaged = miPointInRegion(DamageRegion(pExaPixmap->pDamage), 0, 0,
2026- &box);
2027+ Bool sys_valid = pExaPixmap->pDamage &&
2028+ !miPointInRegion(&pExaPixmap->validSys, 0, 0, &box);
2029+ Bool damaged = pExaPixmap->pDamage &&
2030+ miPointInRegion(DamageRegion(pExaPixmap->pDamage), 0, 0, &box);
2031 Bool offscreen = exaPixmapIsOffscreen(pPixmap);
2032
2033 fb = pExaPixmap->sys_ptr;
2034
2035 /* Try to avoid framebuffer readbacks */
2036- if (pExaScr->info->CreatePixmap ||
2037- (!offscreen && !sys_valid && !damaged) ||
2038+ if ((!offscreen && !sys_valid && !damaged) ||
2039 (offscreen && (!sys_valid || damaged)))
2040 {
2041 box.x1 = 0;
453260b6
AM
2042diff --git a/hw/xfree86/exa/exa.man.pre b/hw/xfree86/exa/exa.man.pre
2043index 14859bc..31e1cfe 100644
2044--- a/hw/xfree86/exa/exa.man.pre
2045+++ b/hw/xfree86/exa/exa.man.pre
2046@@ -31,12 +31,6 @@ Disables acceleration of downloading of pixmap data from the framebuffer.
2047 Not usable with drivers which rely on DownloadFromScreen succeeding.
2048 Default: No.
2049 .TP
2050-.BI "Option \*qEXAOptimizeMigration\*q \*q" boolean \*q
2051-Enables an additional optimization for migration of destination pixmaps. This
2052-may improve performance in some cases (e.g. when switching virtual desktops with
2053-no compositing manager) but causes corruption in others (e.g. when starting
2054-compiz). Default: No.
2055-.TP
2056 .BI "Option \*qMigrationHeuristic\*q \*q" anystr \*q
2057 Chooses an alternate pixmap migration heuristic, for debugging purposes. The
2058 default is intended to be the best performing one for general use, though others
2059diff --git a/hw/xfree86/exa/examodule.c b/hw/xfree86/exa/examodule.c
33d29f3f 2060index e18da0a..4a8d8f2 100644
453260b6
AM
2061--- a/hw/xfree86/exa/examodule.c
2062+++ b/hw/xfree86/exa/examodule.c
2063@@ -145,7 +145,7 @@ exaDDXDriverInit(ScreenPtr pScreen)
2064 pExaScr->optimize_migration =
2065 xf86ReturnOptValBool(pScreenPriv->options,
2066 EXAOPT_OPTIMIZE_MIGRATION,
2067- FALSE);
2068+ TRUE);
2069 }
2070
2071 if (xf86ReturnOptValBool(pScreenPriv->options,
33d29f3f
AM
2072@@ -179,13 +179,6 @@ exaDDXDriverInit(ScreenPtr pScreen)
2073
2074 }
2075
2076-/*ARGSUSED*/
2077-static const OptionInfoRec *
2078-EXAAvailableOptions(void *unused)
2079-{
2080- return (EXAOptions);
2081-}
2082-
2083 static XF86ModuleVersionInfo exaVersRec =
2084 {
2085 "exa",
2086From 5ab230373909541945d373252a3f244b68a6f7af Mon Sep 17 00:00:00 2001
2087From: Fedora X Ninjas <x@fedoraproject.org>
2088Date: Mon, 6 Oct 2008 11:43:05 +1000
2089Subject: [PATCH] exa: fix case where glyphs get flushed on last loop of previous cycle.
453260b6 2090
33d29f3f
AM
2091we segfault here in exaCompositeRects as we have no source as already
2092flushed just before the loop finished.
2093---
2094 exa/exa_glyphs.c | 12 +++++++-----
2095 1 files changed, 7 insertions(+), 5 deletions(-)
453260b6
AM
2096
2097diff --git a/exa/exa_glyphs.c b/exa/exa_glyphs.c
33d29f3f 2098index b23e7f6..2efc42d 100644
453260b6
AM
2099--- a/exa/exa_glyphs.c
2100+++ b/exa/exa_glyphs.c
33d29f3f
AM
2101@@ -872,11 +872,13 @@ exaGlyphs (CARD8 op,
2102 list++;
2103 }
453260b6 2104
33d29f3f
AM
2105- if (maskFormat)
2106- exaGlyphsToMask(pMask, &buffer);
2107- else
2108- exaGlyphsToDst(op, pSrc, pDst, &buffer,
2109- xSrc, ySrc, xDst, yDst);
2110+ if (buffer.count && buffer.source) {
2111+ if (maskFormat)
2112+ exaGlyphsToMask(pMask, &buffer);
2113+ else
2114+ exaGlyphsToDst(op, pSrc, pDst, &buffer,
2115+ xSrc, ySrc, xDst, yDst);
2116+ }
2117
2118 if (maskFormat)
2119 {
2120--
21211.5.5.1
2122
This page took 0.318311 seconds and 4 git commands to generate.