First import
[xorg_rtime.git] / xorg-server-1.4 / mi / mibank.c
blob32e963fabcc4b3adcbc323e6830744c56a3e1d7f
1 /*
2 * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of Marc Aurele La France not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. Marc Aurele La France makes no representations
11 * about the suitability of this software for any purpose. It is provided
12 * "as-is" without express or implied warranty.
14 * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
16 * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
24 * Copyright 1990,91,92,93 by Thomas Roell, Germany.
25 * Copyright 1991,92,93 by SGCS (Snitily Graphics Consulting Services), USA.
27 * Permission to use, copy, modify, distribute, and sell this software
28 * and its documentation for any purpose is hereby granted without fee,
29 * provided that the above copyright notice appear in all copies and
30 * that both that copyright notice and this permission notice appear
31 * in supporting documentation, and that the name of Thomas Roell nor
32 * SGCS be used in advertising or publicity pertaining to distribution
33 * of the software without specific, written prior permission.
34 * Thomas Roell nor SGCS makes no representations about the suitability
35 * of this software for any purpose. It is provided "as is" without
36 * express or implied warranty.
38 * THOMAS ROELL AND SGCS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
39 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
40 * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR SGCS BE LIABLE FOR ANY
41 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
42 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
43 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
44 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
49 * This thing originated from an idea of Edwin Goei and his bank switching
50 * code for the DEC TX board.
54 * Heavily modified for the XFree86 Project to turn this into an mi wrapper.
55 * --- Marc Aurele La France (tsi@xfree86.org)
59 * "Heavily modified", indeed! By the time this is finalized, there probably
60 * won't be much left of Roell's code...
62 * Miscellaneous notes:
63 * - Pixels with imbedded bank boundaries are required to be off-screen. There
64 * >might< be a way to fool the underlying framebuffer into dealing with
65 * partial pixels.
66 * - Plans to generalise this to do (hardware) colour plane switching have been
67 * dropped due to colour flashing concerns.
69 * TODO:
70 * - Allow miModifyBanking() to change BankSize and nBankDepth.
71 * - Re-instate shared and double banking for framebuffers whose pixmap formats
72 * don't describe how the server "sees" the screen.
73 * - Remove remaining assumptions that a pixmap's devPrivate field points
74 * directly to its pixel data.
77 /* #define NO_ALLOCA 1 */
79 #ifdef HAVE_DIX_CONFIG_H
80 #include <dix-config.h>
81 #endif
83 #include "servermd.h"
84 #include "gcstruct.h"
85 #include "pixmapstr.h"
86 #include "scrnintstr.h"
87 #include "windowstr.h"
88 #include "mi.h"
89 #include "mibank.h"
91 #define BANK_SINGLE 0
92 #define BANK_SHARED 1
93 #define BANK_DOUBLE 2
94 #define BANK_NOBANK 3
96 typedef struct _miBankScreen
98 miBankInfoRec BankInfo;
99 unsigned int nBankBPP;
100 unsigned int type;
102 unsigned long nBitsPerBank;
103 unsigned long nBitsPerScanline;
104 unsigned long nPixelsPerScanlinePadUnit;
106 PixmapPtr pScreenPixmap;
107 PixmapPtr pBankPixmap;
108 GCPtr pBankGC;
110 int nBanks, maxRects;
111 RegionPtr *pBanks;
113 pointer pbits;
116 * Screen Wrappers
118 CreateScreenResourcesProcPtr CreateScreenResources;
119 ModifyPixmapHeaderProcPtr ModifyPixmapHeader;
120 CloseScreenProcPtr CloseScreen;
121 GetImageProcPtr GetImage;
122 GetSpansProcPtr GetSpans;
123 CreateGCProcPtr CreateGC;
124 PaintWindowBackgroundProcPtr PaintWindowBackground;
125 PaintWindowBorderProcPtr PaintWindowBorder;
126 CopyWindowProcPtr CopyWindow;
127 BSFuncRec BackingStoreFuncs;
128 } miBankScreenRec, *miBankScreenPtr;
130 typedef struct _miBankGC
132 GCOps *wrappedOps, *unwrappedOps;
133 GCFuncs *wrappedFuncs, *unwrappedFuncs;
135 Bool fastCopy, fastPlane;
137 RegionPtr pBankedClips[1];
138 } miBankGCRec, *miBankGCPtr;
140 typedef struct _miBankQueue
142 Bool fastBlit;
143 unsigned short srcBankNo;
144 unsigned short dstBankNo;
145 short x;
146 short y;
147 short w;
148 short h;
149 } miBankQueue;
152 * CAVEAT: This banking scheme requires that the DDX store Pixmap data in the
153 * server's address space.
156 #define ModifyPixmap(_pPix, _width, _devKind, _pbits) \
157 (*pScreen->ModifyPixmapHeader)((_pPix), \
158 (_width), -1, -1, -1, (_devKind), (_pbits))
160 #define SET_SINGLE_BANK(_pPix, _width, _devKind, _no) \
161 ModifyPixmap(_pPix, _width, _devKind, \
162 (char *)pScreenPriv->BankInfo.pBankA + \
163 (*pScreenPriv->BankInfo.SetSourceAndDestinationBanks)(pScreen, (_no)) - \
164 (pScreenPriv->BankInfo.BankSize * (_no)))
166 #define SET_SOURCE_BANK(_pPix, _width, _devKind, _no) \
167 ModifyPixmap(_pPix, _width, _devKind, \
168 (char *)pScreenPriv->BankInfo.pBankA + \
169 (*pScreenPriv->BankInfo.SetSourceBank)(pScreen, (_no)) - \
170 (pScreenPriv->BankInfo.BankSize * (_no)))
172 #define SET_DESTINATION_BANK(_pPix, _width, _devKind, _no) \
173 ModifyPixmap(_pPix, _width, _devKind, \
174 (char *)pScreenPriv->BankInfo.pBankB + \
175 (*pScreenPriv->BankInfo.SetDestinationBank)(pScreen, (_no)) - \
176 (pScreenPriv->BankInfo.BankSize * (_no)))
178 #define ALLOCATE_LOCAL_ARRAY(atype, ntype) \
179 (atype *)ALLOCATE_LOCAL((ntype) * sizeof(atype))
181 static int miBankScreenIndex;
182 static int miBankGCIndex;
183 static unsigned long miBankGeneration = 0;
185 #define BANK_SCRPRIVLVAL pScreen->devPrivates[miBankScreenIndex].ptr
187 #define BANK_SCRPRIVATE ((miBankScreenPtr)(BANK_SCRPRIVLVAL))
189 #define BANK_GCPRIVLVAL(pGC) (pGC)->devPrivates[miBankGCIndex].ptr
191 #define BANK_GCPRIVATE(pGC) ((miBankGCPtr)(BANK_GCPRIVLVAL(pGC)))
193 #define PIXMAP_STATUS(_pPix) \
194 pointer pbits = (_pPix)->devPrivate.ptr
196 #define PIXMAP_SAVE(_pPix) \
197 PIXMAP_STATUS(_pPix); \
198 if (pbits == (pointer)pScreenPriv) \
199 (_pPix)->devPrivate.ptr = pScreenPriv->pbits
201 #define PIXMAP_RESTORE(_pPix) \
202 (_pPix)->devPrivate.ptr = pbits
204 #define BANK_SAVE \
205 int width = pScreenPriv->pBankPixmap->drawable.width; \
206 int devKind = pScreenPriv->pBankPixmap->devKind; \
207 PIXMAP_SAVE(pScreenPriv->pBankPixmap)
209 #define BANK_RESTORE \
210 pScreenPriv->pBankPixmap->drawable.width = width; \
211 pScreenPriv->pBankPixmap->devKind = devKind; \
212 PIXMAP_RESTORE(pScreenPriv->pBankPixmap)
214 #define SCREEN_STATUS \
215 PIXMAP_STATUS(pScreenPriv->pScreenPixmap)
217 #define SCREEN_SAVE \
218 PIXMAP_SAVE(pScreenPriv->pScreenPixmap)
220 #define SCREEN_RESTORE \
221 PIXMAP_RESTORE(pScreenPriv->pScreenPixmap)
223 #define SCREEN_INIT \
224 miBankScreenPtr pScreenPriv = BANK_SCRPRIVATE
226 #define SCREEN_UNWRAP(field) \
227 pScreen->field = pScreenPriv->field
229 #define SCREEN_WRAP(field, wrapper) \
230 pScreenPriv->field = pScreen->field; \
231 pScreen->field = wrapper
233 #define GC_INIT(pGC) \
234 miBankGCPtr pGCPriv = BANK_GCPRIVATE(pGC)
236 #define GC_UNWRAP(pGC) \
237 pGCPriv->unwrappedOps = (pGC)->ops; \
238 pGCPriv->unwrappedFuncs = (pGC)->funcs; \
239 (pGC)->ops = pGCPriv->wrappedOps; \
240 (pGC)->funcs = pGCPriv->wrappedFuncs
242 #define GC_WRAP(pGC) \
243 pGCPriv->wrappedOps = (pGC)->ops; \
244 pGCPriv->wrappedFuncs = (pGC)->funcs; \
245 (pGC)->ops = pGCPriv->unwrappedOps; \
246 (pGC)->funcs = pGCPriv->unwrappedFuncs
248 #define IS_BANKED(pDrawable) \
249 ((pbits == (pointer)pScreenPriv) && \
250 (((DrawablePtr)(pDrawable))->type == DRAWABLE_WINDOW))
252 #define CLIP_SAVE \
253 RegionPtr pOrigCompositeClip = pGC->pCompositeClip
255 #define CLIP_RESTORE \
256 pGC->pCompositeClip = pOrigCompositeClip
258 #define GCOP_INIT \
259 ScreenPtr pScreen = pGC->pScreen; \
260 SCREEN_INIT; \
261 GC_INIT(pGC)
263 #define GCOP_UNWRAP \
264 GC_UNWRAP(pGC)
266 #define GCOP_WRAP \
267 GC_WRAP(pGC)
269 #define GCOP_TOP_PART \
270 for (i = 0; i < pScreenPriv->nBanks; i++) \
272 if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i])) \
273 continue; \
274 GCOP_UNWRAP; \
275 SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i)
277 #define GCOP_BOTTOM_PART \
278 GCOP_WRAP; \
281 #define GCOP_SIMPLE(statement) \
282 if (nArray > 0) \
284 GCOP_INIT; \
285 SCREEN_SAVE; \
286 if (!IS_BANKED(pDrawable)) \
288 GCOP_UNWRAP; \
289 statement; \
290 GCOP_WRAP; \
292 else \
294 int i; \
295 CLIP_SAVE; \
296 GCOP_TOP_PART; \
297 statement; \
298 GCOP_BOTTOM_PART; \
299 CLIP_RESTORE; \
301 SCREEN_RESTORE; \
304 #define GCOP_0D_ARGS mode,
305 #define GCOP_1D_ARGS
306 #define GCOP_2D_ARGS shape, mode,
308 #define GCOP_COMPLEX(aop, atype) \
309 if (nArray > 0) \
311 GCOP_INIT; \
312 SCREEN_SAVE; \
313 if (!IS_BANKED(pDrawable)) \
315 GCOP_UNWRAP; \
316 (*pGC->ops->aop)(pDrawable, pGC, GCOP_ARGS nArray, pArray); \
317 GCOP_WRAP; \
319 else \
321 atype *aarg = pArray, *acopy; \
322 int i; \
323 CLIP_SAVE; \
324 if ((acopy = ALLOCATE_LOCAL_ARRAY(atype, nArray))) \
325 aarg = acopy; \
326 GCOP_TOP_PART; \
327 if (acopy) \
328 memcpy(acopy, pArray, nArray * sizeof(atype)); \
329 (*pGC->ops->aop)(pDrawable, pGC, GCOP_ARGS nArray, aarg); \
330 GCOP_BOTTOM_PART; \
331 DEALLOCATE_LOCAL(acopy); \
332 CLIP_RESTORE; \
334 SCREEN_RESTORE; \
337 /*********************
338 * Utility functions *
339 *********************/
341 static int
342 miBankOf(
343 miBankScreenPtr pScreenPriv,
344 int x,
345 int y
348 int iBank = ((x * (int)pScreenPriv->nBankBPP) +
349 (y * (long)pScreenPriv->nBitsPerScanline)) /
350 (long)pScreenPriv->nBitsPerBank;
352 if (iBank < 0)
353 iBank = 0;
354 else if (iBank >= pScreenPriv->nBanks)
355 iBank = pScreenPriv->nBanks - 1;
357 return iBank;
360 #define FirstBankOf(_x, _y) miBankOf(pScreenPriv, (_x), (_y))
361 #define LastBankOf(_x, _y) miBankOf(pScreenPriv, (_x) - 1, (_y))
363 /* Determine banking type from the BankInfoRec */
364 static unsigned int
365 miBankDeriveType(
366 ScreenPtr pScreen,
367 miBankInfoPtr pBankInfo
370 unsigned int type;
372 if (pBankInfo->pBankA == pBankInfo->pBankB)
374 if (pBankInfo->SetSourceBank == pBankInfo->SetDestinationBank)
376 if (pBankInfo->SetSourceAndDestinationBanks !=
377 pBankInfo->SetSourceBank)
378 return BANK_NOBANK;
380 type = BANK_SINGLE;
382 else
384 if (pBankInfo->SetSourceAndDestinationBanks ==
385 pBankInfo->SetDestinationBank)
386 return BANK_NOBANK;
387 if (pBankInfo->SetSourceAndDestinationBanks ==
388 pBankInfo->SetSourceBank)
389 return BANK_NOBANK;
391 type = BANK_SHARED;
394 else
396 if ((unsigned long)abs((char *)pBankInfo->pBankA -
397 (char *)pBankInfo->pBankB) < pBankInfo->BankSize)
398 return BANK_NOBANK;
400 if (pBankInfo->SetSourceBank == pBankInfo->SetDestinationBank)
402 if (pBankInfo->SetSourceAndDestinationBanks !=
403 pBankInfo->SetSourceBank)
404 return BANK_NOBANK;
406 else
408 if (pBankInfo->SetSourceAndDestinationBanks ==
409 pBankInfo->SetDestinationBank)
410 return BANK_NOBANK;
413 type = BANK_DOUBLE;
417 * Internal limitation: Currently, only single banking is supported when
418 * the pixmap format and the screen's pixel format are different. The
419 * following test is only partially successful at detecting this condition.
421 if (pBankInfo->nBankDepth != pScreen->rootDepth)
422 type = BANK_SINGLE;
424 return type;
427 /* Least common multiple */
428 static unsigned int
429 miLCM(
430 unsigned int x,
431 unsigned int y
434 unsigned int m = x, n = y, o;
436 while ((o = m % n))
438 m = n;
439 n = o;
442 return (x / n) * y;
445 /******************
446 * GCOps wrappers *
447 ******************/
449 static void
450 miBankFillSpans(
451 DrawablePtr pDrawable,
452 GCPtr pGC,
453 int nArray,
454 DDXPointPtr pptInit,
455 int *pwidthInit,
456 int fSorted
459 GCOP_SIMPLE((*pGC->ops->FillSpans)(pDrawable, pGC,
460 nArray, pptInit, pwidthInit, fSorted));
463 static void
464 miBankSetSpans(
465 DrawablePtr pDrawable,
466 GCPtr pGC,
467 char *psrc,
468 DDXPointPtr ppt,
469 int *pwidth,
470 int nArray,
471 int fSorted
474 GCOP_SIMPLE((*pGC->ops->SetSpans)(pDrawable, pGC, psrc,
475 ppt, pwidth, nArray, fSorted));
478 static void
479 miBankPutImage(
480 DrawablePtr pDrawable,
481 GCPtr pGC,
482 int depth,
483 int x,
484 int y,
485 int w,
486 int h,
487 int leftPad,
488 int format,
489 char *pImage
492 if ((w > 0) && (h > 0))
494 GCOP_INIT;
495 SCREEN_SAVE;
497 if (!IS_BANKED(pDrawable))
499 GCOP_UNWRAP;
501 (*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h,
502 leftPad, format, pImage);
504 GCOP_WRAP;
506 else
508 int i, j;
510 CLIP_SAVE;
512 i = FirstBankOf(x + pDrawable->x, y + pDrawable->y);
513 j = LastBankOf(x + pDrawable->x + w, y + pDrawable->y + h);
514 for (; i <= j; i++)
516 if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i]))
517 continue;
519 GCOP_UNWRAP;
521 SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i);
523 (*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h,
524 leftPad, format, pImage);
526 GCOP_WRAP;
529 CLIP_RESTORE;
532 SCREEN_RESTORE;
537 * Here the CopyArea/CopyPlane wrappers. First off, we have to clip against
538 * the source in order to make the minimal number of copies in case of slow
539 * systems. Also the exposure handling is quite tricky. Special attention
540 * is to be given to the way the copies are sequenced. The list of boxes after
541 * the source clip is used to build a workqueue, that contains the atomic
542 * copies (i.e. only from one bank to one bank). Doing so produces a minimal
543 * list of things to do.
545 static RegionPtr
546 miBankCopy(
547 DrawablePtr pSrc,
548 DrawablePtr pDst,
549 GCPtr pGC,
550 int srcx,
551 int srcy,
552 int w,
553 int h,
554 int dstx,
555 int dsty,
556 unsigned long plane,
557 Bool SinglePlane
560 int cx1, cy1, cx2, cy2;
561 int ns, nd, nse, nde, dx, dy, xorg = 0, yorg = 0;
562 int maxWidth = 0, maxHeight = 0, paddedWidth = 0;
563 int nBox, nBoxClipSrc, nBoxClipDst, nQueue;
564 BoxPtr pBox, pBoxClipSrc, pBoxClipDst;
565 BoxRec fastBox, ccBox;
566 RegionPtr ret = NULL, prgnSrcClip = NULL;
567 RegionRec rgnDst;
568 char *pImage = NULL;
569 miBankQueue *pQueue, *pQueueNew, *Queue;
570 miBankQueue *pQueueTmp, *pQueueNext, *pQueueBase;
571 Bool fastBlit, freeSrcClip, fastClip;
572 Bool fExpose = FALSE, fastExpose = FALSE;
574 GCOP_INIT;
575 SCREEN_SAVE;
577 if (!IS_BANKED(pSrc) && !IS_BANKED(pDst))
579 GCOP_UNWRAP;
581 if (SinglePlane)
582 ret = (*pGC->ops->CopyPlane)(pSrc, pDst, pGC,
583 srcx, srcy, w, h, dstx, dsty, plane);
584 else
585 ret = (*pGC->ops->CopyArea)(pSrc, pDst, pGC,
586 srcx, srcy, w, h, dstx, dsty);
588 GCOP_WRAP;
590 else if (!IS_BANKED(pDst))
592 fExpose = pGC->fExpose;
593 pGC->fExpose = FALSE;
595 xorg = pSrc->x;
596 yorg = pSrc->y;
597 dx = dstx - srcx;
598 dy = dsty - srcy;
599 srcx += xorg;
600 srcy += yorg;
602 ns = FirstBankOf(srcx, srcy);
603 nse = LastBankOf(srcx + w, srcy + h);
604 for (; ns <= nse; ns++)
606 if (!pScreenPriv->pBanks[ns])
607 continue;
609 nBox = REGION_NUM_RECTS(pScreenPriv->pBanks[ns]);
610 pBox = REGION_RECTS(pScreenPriv->pBanks[ns]);
612 for (; nBox--; pBox++)
614 cx1 = max(pBox->x1, srcx);
615 cy1 = max(pBox->y1, srcy);
616 cx2 = min(pBox->x2, srcx + w);
617 cy2 = min(pBox->y2, srcy + h);
619 if ((cx1 >= cx2) || (cy1 >= cy2))
620 continue;
622 GCOP_UNWRAP;
624 SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, ns);
626 if (SinglePlane)
627 (*pGC->ops->CopyPlane)(pSrc, pDst, pGC,
628 cx1 - xorg, cy1 - yorg,
629 cx2 - cx1, cy2 - cy1,
630 cx1 + dx - xorg, cy1 + dy - yorg, plane);
631 else
632 (*pGC->ops->CopyArea)(pSrc, pDst, pGC,
633 cx1 - xorg, cy1 - yorg,
634 cx2 - cx1, cy2 - cy1,
635 cx1 + dx - xorg, cy1 + dy - yorg);
637 GCOP_WRAP;
641 pGC->fExpose = fExpose;
642 srcx -= xorg;
643 srcy -= yorg;
645 else if (!IS_BANKED(pSrc))
647 CLIP_SAVE;
649 if (pGC->miTranslate)
651 xorg = pDst->x;
652 yorg = pDst->y;
654 dx = srcx - dstx;
655 dy = srcy - dsty;
656 dstx += xorg;
657 dsty += yorg;
659 nd = FirstBankOf(dstx, dsty);
660 nde = LastBankOf(dstx + w, dsty + h);
661 for (; nd <= nde; nd++)
663 if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[nd]))
664 continue;
667 * It's faster to let the lower-level CopyArea do the clipping
668 * within each bank.
670 nBox = REGION_NUM_RECTS(pScreenPriv->pBanks[nd]);
671 pBox = REGION_RECTS(pScreenPriv->pBanks[nd]);
673 for (; nBox--; pBox++)
675 cx1 = max(pBox->x1, dstx);
676 cy1 = max(pBox->y1, dsty);
677 cx2 = min(pBox->x2, dstx + w);
678 cy2 = min(pBox->y2, dsty + h);
680 if ((cx1 >= cx2) || (cy1 >= cy2))
681 continue;
683 GCOP_UNWRAP;
685 SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, nd);
687 if (SinglePlane)
688 (*pGC->ops->CopyPlane)(pSrc, pDst, pGC,
689 cx1 + dx - xorg, cy1 + dy - yorg,
690 cx2 - cx1, cy2 - cy1,
691 cx1 - xorg, cy1 - yorg, plane);
692 else
693 (*pGC->ops->CopyArea)(pSrc, pDst, pGC,
694 cx1 + dx - xorg, cy1 + dy - yorg,
695 cx2 - cx1, cy2 - cy1,
696 cx1 - xorg, cy1 - yorg);
698 GCOP_WRAP;
702 CLIP_RESTORE;
704 else /* IS_BANKED(pSrc) && IS_BANKED(pDst) */
706 CLIP_SAVE;
708 fExpose = pGC->fExpose;
710 fastBox.x1 = srcx + pSrc->x;
711 fastBox.y1 = srcy + pSrc->y;
712 fastBox.x2 = fastBox.x1 + w;
713 fastBox.y2 = fastBox.y1 + h;
715 dx = dstx - fastBox.x1;
716 dy = dsty - fastBox.y1;
717 if (pGC->miTranslate)
719 xorg = pDst->x;
720 yorg = pDst->y;
724 * Clip against the source. Otherwise we will blit too much for SINGLE
725 * and SHARED banked systems.
727 freeSrcClip = FALSE;
728 fastClip = FALSE;
729 fastExpose = FALSE;
731 if (pGC->subWindowMode != IncludeInferiors)
732 prgnSrcClip = &((WindowPtr)pSrc)->clipList;
733 else if (!((WindowPtr)pSrc)->parent)
734 fastClip = TRUE;
735 else if ((pSrc == pDst) && (pGC->clientClipType == CT_NONE))
736 prgnSrcClip = pGC->pCompositeClip;
737 else
739 prgnSrcClip = NotClippedByChildren((WindowPtr)pSrc);
740 freeSrcClip = TRUE;
743 if (fastClip)
745 fastExpose = TRUE;
748 * Clip the source. If regions extend beyond the source size, make
749 * sure exposure events get sent.
751 if (fastBox.x1 < pSrc->x)
753 fastBox.x1 = pSrc->x;
754 fastExpose = FALSE;
756 if (fastBox.y1 < pSrc->y)
758 fastBox.y1 = pSrc->y;
759 fastExpose = FALSE;
761 if (fastBox.x2 > pSrc->x + (int) pSrc->width)
763 fastBox.x2 = pSrc->x + (int) pSrc->width;
764 fastExpose = FALSE;
766 if (fastBox.y2 > pSrc->y + (int) pSrc->height)
768 fastBox.y2 = pSrc->y + (int) pSrc->height;
769 fastExpose = FALSE;
772 nBox = 1;
773 pBox = &fastBox;
775 else
777 REGION_INIT(pScreen, &rgnDst, &fastBox, 1);
778 REGION_INTERSECT(pScreen, &rgnDst, &rgnDst, prgnSrcClip);
779 pBox = REGION_RECTS(&rgnDst);
780 nBox = REGION_NUM_RECTS(&rgnDst);
784 * fastBlit can only be TRUE if we don't need to worry about attempts
785 * to read partial pixels through the destination bank.
787 if (SinglePlane)
788 fastBlit = pGCPriv->fastPlane;
789 else
790 fastBlit = pGCPriv->fastCopy;
792 nQueue = nBox * pScreenPriv->maxRects * 2;
793 pQueue = Queue = ALLOCATE_LOCAL_ARRAY(miBankQueue, nQueue);
795 if (Queue)
797 for (; nBox--; pBox++)
799 ns = FirstBankOf(pBox->x1, pBox->y1);
800 nse = LastBankOf(pBox->x2, pBox->y2);
801 for (; ns <= nse; ns++)
803 if (!pScreenPriv->pBanks[ns])
804 continue;
806 nBoxClipSrc = REGION_NUM_RECTS(pScreenPriv->pBanks[ns]);
807 pBoxClipSrc = REGION_RECTS(pScreenPriv->pBanks[ns]);
809 for (; nBoxClipSrc--; pBoxClipSrc++)
811 cx1 = max(pBox->x1, pBoxClipSrc->x1);
812 cy1 = max(pBox->y1, pBoxClipSrc->y1);
813 cx2 = min(pBox->x2, pBoxClipSrc->x2);
814 cy2 = min(pBox->y2, pBoxClipSrc->y2);
816 /* Check to see if the region is empty */
817 if ((cx1 >= cx2) || (cy1 >= cy2))
818 continue;
820 /* Translate c[xy]* to destination coordinates */
821 cx1 += dx + xorg;
822 cy1 += dy + yorg;
823 cx2 += dx + xorg;
824 cy2 += dy + yorg;
826 nd = FirstBankOf(cx1, cy1);
827 nde = LastBankOf(cx2, cy2);
828 for (; nd <= nde; nd++)
830 if (!pGCPriv->pBankedClips[nd])
831 continue;
834 * Clients can send quite large clip descriptions,
835 * so use the bank clips here instead.
837 nBoxClipDst =
838 REGION_NUM_RECTS(pScreenPriv->pBanks[nd]);
839 pBoxClipDst =
840 REGION_RECTS(pScreenPriv->pBanks[nd]);
842 for (; nBoxClipDst--; pBoxClipDst++)
844 ccBox.x1 = max(cx1, pBoxClipDst->x1);
845 ccBox.y1 = max(cy1, pBoxClipDst->y1);
846 ccBox.x2 = min(cx2, pBoxClipDst->x2);
847 ccBox.y2 = min(cy2, pBoxClipDst->y2);
849 /* Check to see if the region is empty */
850 if ((ccBox.x1 >= ccBox.x2) ||
851 (ccBox.y1 >= ccBox.y2))
852 continue;
854 pQueue->srcBankNo = ns;
855 pQueue->dstBankNo = nd;
856 pQueue->x = ccBox.x1 - xorg;
857 pQueue->y = ccBox.y1 - yorg;
858 pQueue->w = ccBox.x2 - ccBox.x1;
859 pQueue->h = ccBox.y2 - ccBox.y1;
861 if (maxWidth < pQueue->w)
862 maxWidth = pQueue->w;
863 if (maxHeight < pQueue->h)
864 maxHeight = pQueue->h;
867 * When shared banking is used and the source
868 * and destination banks differ, prevent
869 * attempts to fetch partial scanline pad units
870 * through the destination bank.
872 pQueue->fastBlit = fastBlit;
873 if (fastBlit &&
874 (pScreenPriv->type == BANK_SHARED) &&
875 (ns != nd) &&
876 ((ccBox.x1 %
877 pScreenPriv->nPixelsPerScanlinePadUnit) ||
878 (ccBox.x2 %
879 pScreenPriv->nPixelsPerScanlinePadUnit) ||
880 (RECT_IN_REGION(pScreen,
881 pGCPriv->pBankedClips[nd], &ccBox) !=
882 rgnIN)))
883 pQueue->fastBlit = FALSE;
884 pQueue++;
892 if (!fastClip)
894 REGION_UNINIT(pScreen, &rgnDst);
895 if (freeSrcClip)
896 REGION_DESTROY(pScreen, prgnSrcClip);
899 pQueueNew = pQueue;
900 nQueue = pQueue - Queue;
902 if (nQueue > 0)
904 BANK_SAVE;
906 pQueue = Queue;
908 if ((nQueue > 1) &&
909 ((pSrc == pDst) || (pGC->subWindowMode == IncludeInferiors)))
911 if ((srcy + pSrc->y) < (dsty + yorg))
913 /* Sort from bottom to top */
914 pQueueBase = pQueueNext = pQueue + nQueue - 1;
916 while (pQueueBase >= pQueue)
918 while ((pQueueNext >= pQueue) &&
919 (pQueueBase->y == pQueueNext->y))
920 pQueueNext--;
922 pQueueTmp = pQueueNext + 1;
923 while (pQueueTmp <= pQueueBase)
924 *pQueueNew++ = *pQueueTmp++;
926 pQueueBase = pQueueNext;
929 pQueueNew -= nQueue;
930 pQueue = pQueueNew;
931 pQueueNew = Queue;
934 if ((srcx + pSrc->x) < (dstx + xorg))
936 /* Sort from right to left */
937 pQueueBase = pQueueNext = pQueue;
939 while (pQueueBase < pQueue + nQueue)
941 while ((pQueueNext < pQueue + nQueue) &&
942 (pQueueNext->y == pQueueBase->y))
943 pQueueNext++;
945 pQueueTmp = pQueueNext;
946 while (pQueueTmp != pQueueBase)
947 *pQueueNew++ = *--pQueueTmp;
949 pQueueBase = pQueueNext;
952 pQueueNew -= nQueue;
953 pQueue = pQueueNew;
957 paddedWidth = PixmapBytePad(maxWidth,
958 pScreenPriv->pScreenPixmap->drawable.depth);
959 pImage = (char *)ALLOCATE_LOCAL(paddedWidth * maxHeight);
961 pGC->fExpose = FALSE;
963 while (nQueue--)
965 pGC->pCompositeClip = pGCPriv->pBankedClips[pQueue->dstBankNo];
967 GCOP_UNWRAP;
969 if (pQueue->srcBankNo == pQueue->dstBankNo)
971 SET_SINGLE_BANK(pScreenPriv->pScreenPixmap,
972 -1, -1, pQueue->srcBankNo);
974 if (SinglePlane)
975 (*pGC->ops->CopyPlane)(pSrc, pDst, pGC,
976 pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y,
977 pQueue->w, pQueue->h, pQueue->x, pQueue->y, plane);
978 else
979 (*pGC->ops->CopyArea)(pSrc, pDst, pGC,
980 pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y,
981 pQueue->w, pQueue->h, pQueue->x, pQueue->y);
983 else if (pQueue->fastBlit)
985 SET_SOURCE_BANK (pScreenPriv->pBankPixmap,
986 pScreenPriv->pScreenPixmap->drawable.width,
987 pScreenPriv->pScreenPixmap->devKind,
988 pQueue->srcBankNo);
989 SET_DESTINATION_BANK(pScreenPriv->pScreenPixmap,
990 -1, -1, pQueue->dstBankNo);
992 if (SinglePlane)
993 (*pGC->ops->CopyPlane)(
994 (DrawablePtr)pScreenPriv->pBankPixmap, pDst, pGC,
995 pQueue->x - dx, pQueue->y - dy,
996 pQueue->w, pQueue->h, pQueue->x, pQueue->y, plane);
997 else
998 (*pGC->ops->CopyArea)(
999 (DrawablePtr)pScreenPriv->pBankPixmap, pDst, pGC,
1000 pQueue->x - dx, pQueue->y - dy,
1001 pQueue->w, pQueue->h, pQueue->x, pQueue->y);
1003 else if (pImage)
1005 ModifyPixmap(pScreenPriv->pBankPixmap,
1006 maxWidth, paddedWidth, pImage);
1008 SET_SINGLE_BANK(pScreenPriv->pScreenPixmap,
1009 -1, -1, pQueue->srcBankNo);
1011 (*pScreenPriv->pBankGC->ops->CopyArea)(
1012 pSrc, (DrawablePtr)pScreenPriv->pBankPixmap,
1013 pScreenPriv->pBankGC,
1014 pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y,
1015 pQueue->w, pQueue->h, 0, 0);
1017 SET_SINGLE_BANK(pScreenPriv->pScreenPixmap,
1018 -1, -1, pQueue->dstBankNo);
1020 if (SinglePlane)
1021 (*pGC->ops->CopyPlane)(
1022 (DrawablePtr)pScreenPriv->pBankPixmap,
1023 pDst, pGC, 0, 0, pQueue->w, pQueue->h,
1024 pQueue->x, pQueue->y, plane);
1025 else
1026 (*pGC->ops->CopyArea)(
1027 (DrawablePtr)pScreenPriv->pBankPixmap,
1028 pDst, pGC, 0, 0, pQueue->w, pQueue->h,
1029 pQueue->x, pQueue->y);
1032 GCOP_WRAP;
1034 pQueue++;
1037 DEALLOCATE_LOCAL(pImage);
1039 BANK_RESTORE;
1042 CLIP_RESTORE;
1044 pGC->fExpose = fExpose;
1046 DEALLOCATE_LOCAL(Queue);
1049 SCREEN_RESTORE;
1051 if (!fExpose || fastExpose)
1052 return ret;
1054 return miHandleExposures(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, 0);
1057 static RegionPtr
1058 miBankCopyArea(
1059 DrawablePtr pSrc,
1060 DrawablePtr pDst,
1061 GCPtr pGC,
1062 int srcx,
1063 int srcy,
1064 int w,
1065 int h,
1066 int dstx,
1067 int dsty
1070 return miBankCopy(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, 0, FALSE);
1073 static RegionPtr
1074 miBankCopyPlane(
1075 DrawablePtr pSrc,
1076 DrawablePtr pDst,
1077 GCPtr pGC,
1078 int srcx,
1079 int srcy,
1080 int w,
1081 int h,
1082 int dstx,
1083 int dsty,
1084 unsigned long plane
1087 return
1088 miBankCopy(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane, TRUE);
1091 static void
1092 miBankPolyPoint(
1093 DrawablePtr pDrawable,
1094 GCPtr pGC,
1095 int mode,
1096 int nArray,
1097 xPoint *pArray
1100 # define GCOP_ARGS GCOP_0D_ARGS
1101 GCOP_COMPLEX(PolyPoint, xPoint);
1102 # undef GCOP_ARGS
1105 static void
1106 miBankPolylines(
1107 DrawablePtr pDrawable,
1108 GCPtr pGC,
1109 int mode,
1110 int nArray,
1111 DDXPointPtr pArray
1114 # define GCOP_ARGS GCOP_0D_ARGS
1115 GCOP_COMPLEX(Polylines, DDXPointRec);
1116 # undef GCOP_ARGS
1119 static void
1120 miBankPolySegment(
1121 DrawablePtr pDrawable,
1122 GCPtr pGC,
1123 int nArray,
1124 xSegment *pArray
1127 # define GCOP_ARGS GCOP_1D_ARGS
1128 GCOP_COMPLEX(PolySegment, xSegment);
1129 # undef GCOP_ARGS
1132 static void
1133 miBankPolyRectangle(
1134 DrawablePtr pDrawable,
1135 GCPtr pGC,
1136 int nArray,
1137 xRectangle *pArray
1140 # define GCOP_ARGS GCOP_1D_ARGS
1141 GCOP_COMPLEX(PolyRectangle, xRectangle);
1142 # undef GCOP_ARGS
1145 static void
1146 miBankPolyArc(
1147 DrawablePtr pDrawable,
1148 GCPtr pGC,
1149 int nArray,
1150 xArc *pArray
1153 # define GCOP_ARGS GCOP_1D_ARGS
1154 GCOP_COMPLEX(PolyArc, xArc);
1155 # undef GCOP_ARGS
1158 static void
1159 miBankFillPolygon(
1160 DrawablePtr pDrawable,
1161 GCPtr pGC,
1162 int shape,
1163 int mode,
1164 int nArray,
1165 DDXPointRec *pArray
1168 # define GCOP_ARGS GCOP_2D_ARGS
1169 GCOP_COMPLEX(FillPolygon, DDXPointRec);
1170 # undef GCOP_ARGS
1173 static void
1174 miBankPolyFillRect(
1175 DrawablePtr pDrawable,
1176 GCPtr pGC,
1177 int nArray,
1178 xRectangle *pArray
1181 # define GCOP_ARGS GCOP_1D_ARGS
1182 GCOP_COMPLEX(PolyFillRect, xRectangle);
1183 # undef GCOP_ARGS
1186 static void
1187 miBankPolyFillArc(
1188 DrawablePtr pDrawable,
1189 GCPtr pGC,
1190 int nArray,
1191 xArc *pArray
1194 # define GCOP_ARGS GCOP_1D_ARGS
1195 GCOP_COMPLEX(PolyFillArc, xArc);
1196 # undef GCOP_ARGS
1199 static int
1200 miBankPolyText8(
1201 DrawablePtr pDrawable,
1202 GCPtr pGC,
1203 int x,
1204 int y,
1205 int nArray,
1206 char *pchar
1209 int retval = x;
1211 GCOP_SIMPLE(retval =
1212 (*pGC->ops->PolyText8)(pDrawable, pGC, x, y, nArray, pchar));
1214 return retval;
1217 static int
1218 miBankPolyText16(
1219 DrawablePtr pDrawable,
1220 GCPtr pGC,
1221 int x,
1222 int y,
1223 int nArray,
1224 unsigned short *pchar
1227 int retval = x;
1229 GCOP_SIMPLE(retval =
1230 (*pGC->ops->PolyText16)(pDrawable, pGC, x, y, nArray, pchar));
1232 return retval;
1235 static void
1236 miBankImageText8(
1237 DrawablePtr pDrawable,
1238 GCPtr pGC,
1239 int x,
1240 int y,
1241 int nArray,
1242 char *pchar
1245 GCOP_SIMPLE((*pGC->ops->ImageText8)(pDrawable, pGC, x, y, nArray, pchar));
1248 static void
1249 miBankImageText16(
1250 DrawablePtr pDrawable,
1251 GCPtr pGC,
1252 int x,
1253 int y,
1254 int nArray,
1255 unsigned short *pchar
1258 GCOP_SIMPLE((*pGC->ops->ImageText16)(pDrawable, pGC, x, y, nArray, pchar));
1261 static void
1262 miBankImageGlyphBlt(
1263 DrawablePtr pDrawable,
1264 GCPtr pGC,
1265 int x,
1266 int y,
1267 unsigned int nArray,
1268 CharInfoPtr *ppci,
1269 pointer pglyphBase
1272 GCOP_SIMPLE((*pGC->ops->ImageGlyphBlt)(pDrawable, pGC,
1273 x, y, nArray, ppci, pglyphBase));
1276 static void
1277 miBankPolyGlyphBlt(
1278 DrawablePtr pDrawable,
1279 GCPtr pGC,
1280 int x,
1281 int y,
1282 unsigned int nArray,
1283 CharInfoPtr *ppci,
1284 pointer pglyphBase
1287 GCOP_SIMPLE((*pGC->ops->PolyGlyphBlt)(pDrawable, pGC,
1288 x, y, nArray, ppci, pglyphBase));
1291 static void
1292 miBankPushPixels(
1293 GCPtr pGC,
1294 PixmapPtr pBitmap,
1295 DrawablePtr pDrawable,
1296 int w,
1297 int h,
1298 int x,
1299 int y
1302 if ((w > 0) && (h > 0))
1304 GCOP_INIT;
1305 SCREEN_SAVE;
1307 if (!IS_BANKED(pDrawable))
1309 GCOP_UNWRAP;
1311 (*pGC->ops->PushPixels)(pGC, pBitmap, pDrawable, w, h, x, y);
1313 GCOP_WRAP;
1315 else
1317 int i, j;
1319 CLIP_SAVE;
1321 i = FirstBankOf(x, y);
1322 j = LastBankOf(x + w, y + h);
1323 for (; i <= j; i++)
1325 if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i]))
1326 continue;
1328 GCOP_UNWRAP;
1330 SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i);
1332 (*pGC->ops->PushPixels)(pGC, pBitmap, pDrawable, w, h, x, y);
1334 GCOP_WRAP;
1337 CLIP_RESTORE;
1340 SCREEN_RESTORE;
1344 static GCOps miBankGCOps =
1346 miBankFillSpans,
1347 miBankSetSpans,
1348 miBankPutImage,
1349 miBankCopyArea,
1350 miBankCopyPlane,
1351 miBankPolyPoint,
1352 miBankPolylines,
1353 miBankPolySegment,
1354 miBankPolyRectangle,
1355 miBankPolyArc,
1356 miBankFillPolygon,
1357 miBankPolyFillRect,
1358 miBankPolyFillArc,
1359 miBankPolyText8,
1360 miBankPolyText16,
1361 miBankImageText8,
1362 miBankImageText16,
1363 miBankImageGlyphBlt,
1364 miBankPolyGlyphBlt,
1365 miBankPushPixels,
1366 {NULL} /* devPrivate */
1369 /********************
1370 * GCFuncs wrappers *
1371 ********************/
1373 static void
1374 miBankValidateGC(
1375 GCPtr pGC,
1376 unsigned long changes,
1377 DrawablePtr pDrawable
1380 GC_INIT(pGC);
1381 GC_UNWRAP(pGC);
1383 (*pGC->funcs->ValidateGC)(pGC, changes, pDrawable);
1385 if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)) ||
1386 (pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS)))
1388 ScreenPtr pScreen = pGC->pScreen;
1389 RegionPtr prgnClip;
1390 unsigned long planemask;
1391 int i;
1393 SCREEN_INIT;
1394 SCREEN_SAVE;
1396 if (IS_BANKED(pDrawable))
1398 for (i = 0; i < pScreenPriv->nBanks; i++)
1400 if (!pScreenPriv->pBanks[i])
1401 continue;
1403 if (!(prgnClip = pGCPriv->pBankedClips[i]))
1404 prgnClip = REGION_CREATE(pScreen, NULL, 1);
1406 REGION_INTERSECT(pScreen, prgnClip,
1407 pScreenPriv->pBanks[i], pGC->pCompositeClip);
1409 if ((REGION_NUM_RECTS(prgnClip) <= 1) &&
1410 ((prgnClip->extents.x1 == prgnClip->extents.x2) ||
1411 (prgnClip->extents.y1 == prgnClip->extents.y2)))
1413 REGION_DESTROY(pScreen, prgnClip);
1414 pGCPriv->pBankedClips[i] = NULL;
1416 else
1417 pGCPriv->pBankedClips[i] = prgnClip;
1421 * fastCopy and fastPlane can only be TRUE if we don't need to
1422 * worry about attempts to read partial pixels through the
1423 * destination bank.
1425 switch (pScreenPriv->type)
1427 case BANK_SHARED:
1428 pGCPriv->fastCopy = pGCPriv->fastPlane = FALSE;
1430 if ((pGC->alu != GXclear) && (pGC->alu != GXcopy) &&
1431 (pGC->alu != GXcopyInverted) && (pGC->alu != GXset))
1432 break;
1434 if (pScreen->rootDepth == 1)
1435 pGCPriv->fastPlane = TRUE;
1437 /* This is probably paranoia */
1438 if ((pDrawable->depth != pScreen->rootDepth) ||
1439 (pDrawable->depth != pGC->depth))
1440 break;
1442 planemask = (1 << pGC->depth) - 1;
1443 if ((pGC->planemask & planemask) == planemask)
1444 pGCPriv->fastCopy = TRUE;
1446 break;
1448 case BANK_DOUBLE:
1449 pGCPriv->fastCopy = pGCPriv->fastPlane = TRUE;
1450 break;
1452 default:
1453 pGCPriv->fastCopy = pGCPriv->fastPlane = FALSE;
1454 break;
1457 else
1460 * Here we are on a pixmap and don't need all that special clipping
1461 * stuff, hence free it.
1463 for (i = 0; i < pScreenPriv->nBanks; i++)
1465 if (!pGCPriv->pBankedClips[i])
1466 continue;
1468 REGION_DESTROY(pScreen, pGCPriv->pBankedClips[i]);
1469 pGCPriv->pBankedClips[i] = NULL;
1473 SCREEN_RESTORE;
1476 GC_WRAP(pGC);
1479 static void
1480 miBankChangeGC(
1481 GCPtr pGC,
1482 unsigned long mask
1485 GC_INIT(pGC);
1486 GC_UNWRAP(pGC);
1488 (*pGC->funcs->ChangeGC)(pGC, mask);
1490 GC_WRAP(pGC);
1493 static void
1494 miBankCopyGC(
1495 GCPtr pGCSrc,
1496 unsigned long mask,
1497 GCPtr pGCDst
1500 GC_INIT(pGCDst);
1501 GC_UNWRAP(pGCDst);
1503 (*pGCDst->funcs->CopyGC)(pGCSrc, mask, pGCDst);
1505 GC_WRAP(pGCDst);
1508 static void
1509 miBankDestroyGC(
1510 GCPtr pGC
1513 ScreenPtr pScreen = pGC->pScreen;
1514 int i;
1516 SCREEN_INIT;
1517 GC_INIT(pGC);
1518 GC_UNWRAP(pGC);
1520 (*pGC->funcs->DestroyGC)(pGC);
1522 for (i = 0; i < pScreenPriv->nBanks; i++)
1524 if (!pGCPriv->pBankedClips[i])
1525 continue;
1527 REGION_DESTROY(pScreen, pGCPriv->pBankedClips[i]);
1528 pGCPriv->pBankedClips[i] = NULL;
1531 GC_WRAP(pGC);
1534 static void
1535 miBankChangeClip(
1536 GCPtr pGC,
1537 int type,
1538 pointer pvalue,
1539 int nrects
1542 GC_INIT(pGC);
1543 GC_UNWRAP(pGC);
1545 (*pGC->funcs->ChangeClip)(pGC, type, pvalue, nrects);
1547 GC_WRAP(pGC);
1550 static void
1551 miBankDestroyClip(
1552 GCPtr pGC
1555 GC_INIT(pGC);
1556 GC_UNWRAP(pGC);
1558 (*pGC->funcs->DestroyClip)(pGC);
1560 GC_WRAP(pGC);
1563 static void
1564 miBankCopyClip(
1565 GCPtr pGCDst,
1566 GCPtr pGCSrc
1569 GC_INIT(pGCDst);
1570 GC_UNWRAP(pGCDst);
1572 (*pGCDst->funcs->CopyClip)(pGCDst, pGCSrc);
1574 GC_WRAP(pGCDst);
1577 static GCFuncs miBankGCFuncs =
1579 miBankValidateGC,
1580 miBankChangeGC,
1581 miBankCopyGC,
1582 miBankDestroyGC,
1583 miBankChangeClip,
1584 miBankDestroyClip,
1585 miBankCopyClip
1588 /*******************
1589 * Screen Wrappers *
1590 *******************/
1592 static Bool
1593 miBankCreateScreenResources(
1594 ScreenPtr pScreen
1597 Bool retval;
1599 SCREEN_INIT;
1600 SCREEN_UNWRAP(CreateScreenResources);
1602 if ((retval = (*pScreen->CreateScreenResources)(pScreen)))
1604 /* Set screen buffer address to something recognizable */
1605 pScreenPriv->pScreenPixmap = (*pScreen->GetScreenPixmap)(pScreen);
1606 pScreenPriv->pbits = pScreenPriv->pScreenPixmap->devPrivate.ptr;
1607 pScreenPriv->pScreenPixmap->devPrivate.ptr = (pointer)pScreenPriv;
1609 /* Get shadow pixmap; width & height of 0 means no pixmap data */
1610 pScreenPriv->pBankPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0,
1611 pScreenPriv->pScreenPixmap->drawable.depth);
1612 if (!pScreenPriv->pBankPixmap)
1613 retval = FALSE;
1616 /* Shadow the screen */
1617 if (retval)
1618 retval = (*pScreen->ModifyPixmapHeader)(pScreenPriv->pBankPixmap,
1619 pScreenPriv->pScreenPixmap->drawable.width,
1620 pScreenPriv->pScreenPixmap->drawable.height,
1621 pScreenPriv->pScreenPixmap->drawable.depth,
1622 pScreenPriv->pScreenPixmap->drawable.bitsPerPixel,
1623 pScreenPriv->pScreenPixmap->devKind, NULL);
1625 /* Create shadow GC */
1626 if (retval)
1628 pScreenPriv->pBankGC = CreateScratchGC(pScreen,
1629 pScreenPriv->pBankPixmap->drawable.depth);
1630 if (!pScreenPriv->pBankGC)
1631 retval = FALSE;
1634 /* Validate shadow GC */
1635 if (retval)
1637 pScreenPriv->pBankGC->graphicsExposures = FALSE;
1638 pScreenPriv->pBankGC->subWindowMode = IncludeInferiors;
1639 ValidateGC((DrawablePtr)pScreenPriv->pBankPixmap,
1640 pScreenPriv->pBankGC);
1643 SCREEN_WRAP(CreateScreenResources, miBankCreateScreenResources);
1645 return retval;
1648 static Bool
1649 miBankModifyPixmapHeader(
1650 PixmapPtr pPixmap,
1651 int width,
1652 int height,
1653 int depth,
1654 int bitsPerPixel,
1655 int devKind,
1656 pointer pPixData
1659 Bool retval = FALSE;
1661 if (pPixmap)
1663 ScreenPtr pScreen = pPixmap->drawable.pScreen;
1665 SCREEN_INIT;
1666 PIXMAP_SAVE(pPixmap);
1667 SCREEN_UNWRAP(ModifyPixmapHeader);
1669 retval = (*pScreen->ModifyPixmapHeader)(pPixmap, width, height,
1670 depth, bitsPerPixel, devKind, pPixData);
1672 SCREEN_WRAP(ModifyPixmapHeader, miBankModifyPixmapHeader);
1674 if (pbits == (pointer)pScreenPriv)
1676 pScreenPriv->pbits = pPixmap->devPrivate.ptr;
1677 pPixmap->devPrivate.ptr = pbits;
1681 return retval;
1684 static Bool
1685 miBankCloseScreen(
1686 int nIndex,
1687 ScreenPtr pScreen
1690 int i;
1692 SCREEN_INIT;
1694 /* Free shadow GC */
1695 FreeScratchGC(pScreenPriv->pBankGC);
1697 /* Free shadow pixmap */
1698 (*pScreen->DestroyPixmap)(pScreenPriv->pBankPixmap);
1700 /* Restore screen pixmap devPrivate pointer */
1701 pScreenPriv->pScreenPixmap->devPrivate.ptr = pScreenPriv->pbits;
1703 /* Delete bank clips */
1704 for (i = 0; i < pScreenPriv->nBanks; i++)
1705 if (pScreenPriv->pBanks[i])
1706 REGION_DESTROY(pScreen, pScreenPriv->pBanks[i]);
1708 Xfree(pScreenPriv->pBanks);
1710 SCREEN_UNWRAP(CreateScreenResources);
1711 SCREEN_UNWRAP(ModifyPixmapHeader);
1712 SCREEN_UNWRAP(CloseScreen);
1713 SCREEN_UNWRAP(GetImage);
1714 SCREEN_UNWRAP(GetSpans);
1715 SCREEN_UNWRAP(CreateGC);
1716 SCREEN_UNWRAP(PaintWindowBackground);
1717 SCREEN_UNWRAP(PaintWindowBorder);
1718 SCREEN_UNWRAP(CopyWindow);
1719 SCREEN_UNWRAP(BackingStoreFuncs);
1721 Xfree(pScreenPriv);
1722 return (*pScreen->CloseScreen)(nIndex, pScreen);
1725 static void
1726 miBankGetImage(
1727 DrawablePtr pDrawable,
1728 int sx,
1729 int sy,
1730 int w,
1731 int h,
1732 unsigned int format,
1733 unsigned long planemask,
1734 char *pImage
1737 if ((w > 0) && (h > 0))
1739 ScreenPtr pScreen = pDrawable->pScreen;
1741 SCREEN_INIT;
1742 SCREEN_STATUS;
1743 SCREEN_UNWRAP(GetImage);
1745 if (!IS_BANKED(pDrawable))
1747 (*pScreen->GetImage)(pDrawable, sx, sy, w, h,
1748 format, planemask, pImage);
1750 else
1752 int paddedWidth;
1753 char *pBankImage;
1755 paddedWidth = PixmapBytePad(w,
1756 pScreenPriv->pScreenPixmap->drawable.depth);
1757 pBankImage = (char *)ALLOCATE_LOCAL(paddedWidth * h);
1759 if (pBankImage)
1761 BANK_SAVE;
1763 ModifyPixmap(pScreenPriv->pBankPixmap, w, paddedWidth,
1764 pBankImage);
1766 (*pScreenPriv->pBankGC->ops->CopyArea)(
1767 (DrawablePtr)WindowTable[pScreen->myNum],
1768 (DrawablePtr)pScreenPriv->pBankPixmap,
1769 pScreenPriv->pBankGC,
1770 sx + pDrawable->x, sy + pDrawable->y, w, h, 0, 0);
1772 (*pScreen->GetImage)((DrawablePtr)pScreenPriv->pBankPixmap,
1773 0, 0, w, h, format, planemask, pImage);
1775 BANK_RESTORE;
1777 DEALLOCATE_LOCAL(pBankImage);
1781 SCREEN_WRAP(GetImage, miBankGetImage);
1785 static void
1786 miBankGetSpans(
1787 DrawablePtr pDrawable,
1788 int wMax,
1789 DDXPointPtr ppt,
1790 int *pwidth,
1791 int nspans,
1792 char *pImage
1795 if (nspans > 0)
1797 ScreenPtr pScreen = pDrawable->pScreen;
1799 SCREEN_INIT;
1800 SCREEN_STATUS;
1801 SCREEN_UNWRAP(GetSpans);
1803 if (!IS_BANKED(pDrawable))
1805 (*pScreen->GetSpans)(pDrawable, wMax, ppt, pwidth, nspans, pImage);
1807 else
1809 char *pBankImage;
1810 int paddedWidth;
1811 DDXPointRec pt;
1813 pt.x = pt.y = 0;
1815 paddedWidth =
1816 PixmapBytePad(pScreenPriv->pScreenPixmap->drawable.width,
1817 pScreenPriv->pScreenPixmap->drawable.depth);
1818 pBankImage = (char *)ALLOCATE_LOCAL(paddedWidth);
1820 if (pBankImage)
1822 BANK_SAVE;
1824 ModifyPixmap(pScreenPriv->pBankPixmap,
1825 pScreenPriv->pScreenPixmap->drawable.width,
1826 paddedWidth, pBankImage);
1828 for (; nspans--; ppt++, pwidth++)
1830 if (*pwidth <= 0)
1831 continue;
1833 (*pScreenPriv->pBankGC->ops->CopyArea)(
1834 (DrawablePtr)WindowTable[pScreen->myNum],
1835 (DrawablePtr)pScreenPriv->pBankPixmap,
1836 pScreenPriv->pBankGC,
1837 ppt->x, ppt->y, *pwidth, 1, 0, 0);
1839 (*pScreen->GetSpans)((DrawablePtr)pScreenPriv->pBankPixmap,
1840 wMax, &pt, pwidth, 1, pImage);
1842 pImage = pImage + PixmapBytePad(*pwidth, pDrawable->depth);
1845 BANK_RESTORE;
1847 DEALLOCATE_LOCAL(pBankImage);
1851 SCREEN_WRAP(GetSpans, miBankGetSpans);
1855 static Bool
1856 miBankCreateGC(
1857 GCPtr pGC
1860 ScreenPtr pScreen = pGC->pScreen;
1861 miBankGCPtr pGCPriv = BANK_GCPRIVATE(pGC);
1862 Bool ret;
1864 SCREEN_INIT;
1865 SCREEN_UNWRAP(CreateGC);
1867 if ((ret = (*pScreen->CreateGC)(pGC)))
1869 pGCPriv->unwrappedOps = &miBankGCOps;
1870 pGCPriv->unwrappedFuncs = &miBankGCFuncs;
1871 GC_WRAP(pGC);
1873 memset(&pGCPriv->pBankedClips, 0,
1874 pScreenPriv->nBanks * sizeof(pGCPriv->pBankedClips));
1877 SCREEN_WRAP(CreateGC, miBankCreateGC);
1879 return ret;
1882 static void
1883 miBankPaintWindow(
1884 WindowPtr pWin,
1885 RegionPtr pRegion,
1886 int what
1889 ScreenPtr pScreen = pWin->drawable.pScreen;
1890 RegionRec tmpReg;
1891 int i;
1892 PaintWindowProcPtr PaintWindow;
1894 SCREEN_INIT;
1895 SCREEN_SAVE;
1897 if (what == PW_BORDER)
1899 SCREEN_UNWRAP(PaintWindowBorder);
1900 PaintWindow = pScreen->PaintWindowBorder;
1902 else
1904 SCREEN_UNWRAP(PaintWindowBackground);
1905 PaintWindow = pScreen->PaintWindowBackground;
1908 if (!IS_BANKED(pWin))
1910 (*PaintWindow)(pWin, pRegion, what);
1912 else
1914 REGION_NULL(pScreen, &tmpReg);
1916 for (i = 0; i < pScreenPriv->nBanks; i++)
1918 if (!pScreenPriv->pBanks[i])
1919 continue;
1921 REGION_INTERSECT(pScreen, &tmpReg, pRegion,
1922 pScreenPriv->pBanks[i]);
1924 if (REGION_NIL(&tmpReg))
1925 continue;
1927 SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i);
1929 (*PaintWindow)(pWin, &tmpReg, what);
1932 REGION_UNINIT(pScreen, &tmpReg);
1935 if (what == PW_BORDER)
1937 SCREEN_WRAP(PaintWindowBorder, miBankPaintWindow);
1939 else
1941 SCREEN_WRAP(PaintWindowBackground, miBankPaintWindow);
1944 SCREEN_RESTORE;
1947 static void
1948 miBankCopyWindow(
1949 WindowPtr pWindow,
1950 DDXPointRec ptOldOrg,
1951 RegionPtr pRgnSrc
1954 ScreenPtr pScreen = pWindow->drawable.pScreen;
1955 GCPtr pGC;
1956 int dx, dy, nBox;
1957 DrawablePtr pDrawable = (DrawablePtr)WindowTable[pScreen->myNum];
1958 RegionPtr pRgnDst;
1959 BoxPtr pBox, pBoxTmp, pBoxNext, pBoxBase, pBoxNew1, pBoxNew2;
1960 XID subWindowMode = IncludeInferiors;
1962 pGC = GetScratchGC(pDrawable->depth, pScreen);
1964 ChangeGC(pGC, GCSubwindowMode, &subWindowMode);
1965 ValidateGC(pDrawable, pGC);
1967 pRgnDst = REGION_CREATE(pScreen, NULL, 1);
1969 dx = ptOldOrg.x - pWindow->drawable.x;
1970 dy = ptOldOrg.y - pWindow->drawable.y;
1971 REGION_TRANSLATE(pScreen, pRgnSrc, -dx, -dy);
1972 REGION_INTERSECT(pScreen, pRgnDst, &pWindow->borderClip, pRgnSrc);
1974 pBox = REGION_RECTS(pRgnDst);
1975 nBox = REGION_NUM_RECTS(pRgnDst);
1977 pBoxNew1 = NULL;
1978 pBoxNew2 = NULL;
1980 if (nBox > 1)
1982 if (dy < 0)
1984 /* Sort boxes from bottom to top */
1985 pBoxNew1 = ALLOCATE_LOCAL_ARRAY(BoxRec, nBox);
1987 if (pBoxNew1)
1989 pBoxBase = pBoxNext = pBox + nBox - 1;
1991 while (pBoxBase >= pBox)
1993 while ((pBoxNext >= pBox) &&
1994 (pBoxBase->y1 == pBoxNext->y1))
1995 pBoxNext--;
1997 pBoxTmp = pBoxNext + 1;
1999 while (pBoxTmp <= pBoxBase)
2000 *pBoxNew1++ = *pBoxTmp++;
2002 pBoxBase = pBoxNext;
2005 pBoxNew1 -= nBox;
2006 pBox = pBoxNew1;
2010 if (dx < 0)
2012 /* Sort boxes from right to left */
2013 pBoxNew2 = ALLOCATE_LOCAL_ARRAY(BoxRec, nBox);
2015 if (pBoxNew2)
2017 pBoxBase = pBoxNext = pBox;
2019 while (pBoxBase < pBox + nBox)
2021 while ((pBoxNext < pBox + nBox) &&
2022 (pBoxNext->y1 == pBoxBase->y1))
2023 pBoxNext++;
2025 pBoxTmp = pBoxNext;
2027 while (pBoxTmp != pBoxBase)
2028 *pBoxNew2++ = *--pBoxTmp;
2030 pBoxBase = pBoxNext;
2033 pBoxNew2 -= nBox;
2034 pBox = pBoxNew2;
2039 while (nBox--)
2041 (*pGC->ops->CopyArea)(pDrawable, pDrawable, pGC,
2042 pBox->x1 + dx, pBox->y1 + dy,
2043 pBox->x2 - pBox->x1, pBox->y2 - pBox->y1,
2044 pBox->x1, pBox->y1);
2046 pBox++;
2049 FreeScratchGC(pGC);
2051 REGION_DESTROY(pScreen, pRgnDst);
2053 DEALLOCATE_LOCAL(pBoxNew2);
2054 DEALLOCATE_LOCAL(pBoxNew1);
2057 /**************************
2058 * Backing store wrappers *
2059 **************************/
2061 static void
2062 miBankSaveAreas(
2063 PixmapPtr pPixmap,
2064 RegionPtr prgnSave,
2065 int xorg,
2066 int yorg,
2067 WindowPtr pWin
2070 ScreenPtr pScreen = pPixmap->drawable.pScreen;
2071 RegionRec rgnClipped;
2072 int i;
2074 SCREEN_INIT;
2075 SCREEN_SAVE;
2076 SCREEN_UNWRAP(BackingStoreFuncs.SaveAreas);
2078 if (!IS_BANKED(pWin))
2080 (*pScreen->BackingStoreFuncs.SaveAreas)(pPixmap, prgnSave, xorg, yorg,
2081 pWin);
2083 else
2085 REGION_NULL(pScreen, &rgnClipped);
2086 REGION_TRANSLATE(pScreen, prgnSave, xorg, yorg);
2088 for (i = 0; i < pScreenPriv->nBanks; i++)
2090 if (!pScreenPriv->pBanks[i])
2091 continue;
2093 REGION_INTERSECT(pScreen, &rgnClipped,
2094 prgnSave, pScreenPriv->pBanks[i]);
2096 if (REGION_NIL(&rgnClipped))
2097 continue;
2099 SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i);
2101 REGION_TRANSLATE(pScreen, &rgnClipped, -xorg, -yorg);
2103 (*pScreen->BackingStoreFuncs.SaveAreas)(pPixmap, &rgnClipped,
2104 xorg, yorg, pWin);
2107 REGION_TRANSLATE(pScreen, prgnSave, -xorg, -yorg);
2108 REGION_UNINIT(pScreen, &rgnClipped);
2111 SCREEN_WRAP(BackingStoreFuncs.SaveAreas, miBankSaveAreas);
2112 SCREEN_RESTORE;
2115 static void
2116 miBankRestoreAreas(
2117 PixmapPtr pPixmap,
2118 RegionPtr prgnRestore,
2119 int xorg,
2120 int yorg,
2121 WindowPtr pWin
2124 ScreenPtr pScreen = pPixmap->drawable.pScreen;
2125 RegionRec rgnClipped;
2126 int i;
2128 SCREEN_INIT;
2129 SCREEN_SAVE;
2130 SCREEN_UNWRAP(BackingStoreFuncs.RestoreAreas);
2132 if (!IS_BANKED(pWin))
2134 (*pScreen->BackingStoreFuncs.RestoreAreas)(pPixmap, prgnRestore,
2135 xorg, yorg, pWin);
2137 else
2139 REGION_NULL(pScreen, &rgnClipped);
2141 for (i = 0; i < pScreenPriv->nBanks; i++)
2143 if (!pScreenPriv->pBanks[i])
2144 continue;
2146 REGION_INTERSECT(pScreen, &rgnClipped,
2147 prgnRestore, pScreenPriv->pBanks[i]);
2149 if (REGION_NIL(&rgnClipped))
2150 continue;
2152 SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i);
2154 (*pScreen->BackingStoreFuncs.RestoreAreas)(pPixmap, &rgnClipped,
2155 xorg, yorg, pWin);
2158 REGION_UNINIT(pScreen, &rgnClipped);
2161 SCREEN_WRAP(BackingStoreFuncs.RestoreAreas, miBankRestoreAreas);
2162 SCREEN_RESTORE;
2165 _X_EXPORT Bool
2166 miInitializeBanking(
2167 ScreenPtr pScreen,
2168 unsigned int xsize,
2169 unsigned int ysize,
2170 unsigned int width,
2171 miBankInfoPtr pBankInfo
2174 miBankScreenPtr pScreenPriv;
2175 unsigned long nBitsPerBank, nBitsPerScanline, nPixelsPerScanlinePadUnit;
2176 unsigned long BankBase, ServerPad;
2177 unsigned int type, iBank, nBanks, maxRects, we, nBankBPP;
2178 int i;
2180 if (!pBankInfo || !pBankInfo->BankSize)
2181 return TRUE; /* No banking required */
2183 /* Sanity checks */
2185 if (!pScreen || !xsize || !ysize || (xsize > width) ||
2186 !pBankInfo->SetSourceBank || !pBankInfo->SetDestinationBank ||
2187 !pBankInfo->SetSourceAndDestinationBanks ||
2188 !pBankInfo->pBankA || !pBankInfo->pBankB ||
2189 !pBankInfo->nBankDepth)
2190 return FALSE;
2193 * DDX *must* have registered a pixmap format whose depth is
2194 * pBankInfo->nBankDepth. This is not necessarily the rootDepth
2195 * pixmap format.
2197 i = 0;
2198 while (screenInfo.formats[i].depth != pBankInfo->nBankDepth)
2199 if (++i >= screenInfo.numPixmapFormats)
2200 return FALSE;
2201 nBankBPP = screenInfo.formats[i].bitsPerPixel;
2203 i = 0;
2204 while (screenInfo.formats[i].depth != pScreen->rootDepth)
2205 if (++i >= screenInfo.numPixmapFormats)
2206 return FALSE;
2208 if (nBankBPP > screenInfo.formats[i].bitsPerPixel)
2209 return FALSE;
2211 /* Determine banking type */
2212 if ((type = miBankDeriveType(pScreen, pBankInfo)) == BANK_NOBANK)
2213 return FALSE;
2215 /* Internal data */
2217 nBitsPerBank = pBankInfo->BankSize * 8;
2218 ServerPad = PixmapBytePad(1, pBankInfo->nBankDepth) * 8;
2219 if (nBitsPerBank % ServerPad)
2220 return FALSE;
2221 nBitsPerScanline = PixmapBytePad(width, pBankInfo->nBankDepth) * 8;
2222 nBanks = ((nBitsPerScanline * (ysize - 1)) +
2223 (nBankBPP * xsize) + nBitsPerBank - 1) / nBitsPerBank;
2224 nPixelsPerScanlinePadUnit = miLCM(ServerPad, nBankBPP) / nBankBPP;
2226 /* Private areas */
2228 if (miBankGeneration != serverGeneration)
2230 if (((miBankScreenIndex = AllocateScreenPrivateIndex()) < 0) ||
2231 ((miBankGCIndex = AllocateGCPrivateIndex()) < 0))
2232 return FALSE;
2234 miBankGeneration = serverGeneration;
2237 if (!AllocateGCPrivate(pScreen, miBankGCIndex,
2238 (nBanks * sizeof(RegionPtr)) +
2239 (sizeof(miBankGCRec) - sizeof(RegionPtr))))
2240 return FALSE;
2242 if (!(pScreenPriv = (miBankScreenPtr)Xcalloc(sizeof(miBankScreenRec))))
2243 return FALSE;
2245 if (!(pScreenPriv->pBanks = /* Allocate and clear */
2246 (RegionPtr *)Xcalloc(nBanks * sizeof(RegionPtr))))
2248 Xfree(pScreenPriv);
2249 return FALSE;
2253 * Translate banks into clipping regions which are themselves clipped
2254 * against the screen. This also ensures that pixels with imbedded bank
2255 * boundaries are off-screen.
2258 BankBase = 0;
2259 maxRects = 0;
2260 we = 0;
2261 for (iBank = 0; iBank < nBanks; iBank++)
2263 xRectangle pRects[3], *pRect = pRects;
2264 unsigned int xb, yb, xe, ye;
2266 xb = ((BankBase + nBankBPP - 1) % nBitsPerScanline) / nBankBPP;
2267 yb = (BankBase + nBankBPP - 1) / nBitsPerScanline;
2268 if (xb >= xsize)
2270 xb = we = 0;
2271 yb++;
2273 if (yb >= ysize)
2275 we = 0;
2276 break;
2279 if (we)
2280 break;
2282 BankBase += nBitsPerBank;
2284 we = (BankBase % nBitsPerScanline) % nBankBPP;
2285 xe = (BankBase % nBitsPerScanline) / nBankBPP;
2286 ye = BankBase / nBitsPerScanline;
2287 if (xe >= xsize)
2289 we = xe = 0;
2290 ye++;
2292 if (ye >= ysize)
2294 we = xe = 0;
2295 ye = ysize;
2298 if (yb == ye)
2300 if (xb >= xe)
2301 continue;
2303 pRect->x = xb;
2304 pRect->y = yb;
2305 pRect->width = xe - xb;
2306 pRect->height = 1;
2307 maxRects += 2;
2308 pRect++;
2310 else
2312 if (xb)
2314 pRect->x = xb;
2315 pRect->y = yb++;
2316 pRect->width = xsize - xb;
2317 pRect->height = 1;
2318 maxRects += 2;
2319 pRect++;
2322 if (yb < ye)
2324 pRect->x = 0;
2325 pRect->y = yb;
2326 pRect->width = xsize;
2327 pRect->height = ye - yb;
2328 maxRects += min(pRect->height, 3) + 1;
2329 pRect++;
2332 if (xe)
2334 pRect->x = 0;
2335 pRect->y = ye;
2336 pRect->width = xe;
2337 pRect->height = 1;
2338 maxRects += 2;
2339 pRect++;
2343 pScreenPriv->pBanks[iBank] =
2344 RECTS_TO_REGION(pScreen, pRect - pRects, pRects, 0);
2345 if (!pScreenPriv->pBanks[iBank] ||
2346 REGION_NAR(pScreenPriv->pBanks[iBank]))
2348 we = 1;
2349 break;
2353 if (we && (iBank < nBanks))
2355 for (i = iBank; i >= 0; i--)
2356 if (pScreenPriv->pBanks[i])
2357 REGION_DESTROY(pScreen, pScreenPriv->pBanks[i]);
2359 Xfree(pScreenPriv->pBanks);
2360 Xfree(pScreenPriv);
2362 return FALSE;
2365 /* Open for business */
2367 pScreenPriv->type = type;
2368 pScreenPriv->nBanks = nBanks;
2369 pScreenPriv->maxRects = maxRects;
2370 pScreenPriv->nBankBPP = nBankBPP;
2371 pScreenPriv->BankInfo = *pBankInfo;
2372 pScreenPriv->nBitsPerBank = nBitsPerBank;
2373 pScreenPriv->nBitsPerScanline = nBitsPerScanline;
2374 pScreenPriv->nPixelsPerScanlinePadUnit = nPixelsPerScanlinePadUnit;
2376 SCREEN_WRAP(CreateScreenResources, miBankCreateScreenResources);
2377 SCREEN_WRAP(ModifyPixmapHeader, miBankModifyPixmapHeader);
2378 SCREEN_WRAP(CloseScreen, miBankCloseScreen);
2379 SCREEN_WRAP(GetImage, miBankGetImage);
2380 SCREEN_WRAP(GetSpans, miBankGetSpans);
2381 SCREEN_WRAP(CreateGC, miBankCreateGC);
2382 SCREEN_WRAP(PaintWindowBackground, miBankPaintWindow);
2383 SCREEN_WRAP(PaintWindowBorder, miBankPaintWindow);
2384 SCREEN_WRAP(CopyWindow, miBankCopyWindow);
2386 pScreenPriv->BackingStoreFuncs = pScreen->BackingStoreFuncs;
2388 pScreen->BackingStoreFuncs.SaveAreas = miBankSaveAreas;
2389 pScreen->BackingStoreFuncs.RestoreAreas = miBankRestoreAreas;
2390 /* ??????????????????????????????????????????????????????????????
2391 pScreen->BackingStoreFuncs.SetClipmaskRgn = miBankSetClipmaskRgn;
2392 ?????????????????????????????????????????????????????????????? */
2394 BANK_SCRPRIVLVAL = (pointer)pScreenPriv;
2396 return TRUE;
2399 /* This is used to force GC revalidation when the banking type is changed */
2400 /*ARGSUSED*/
2401 static int
2402 miBankNewSerialNumber(
2403 WindowPtr pWin,
2404 pointer unused
2407 pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
2408 return WT_WALKCHILDREN;
2411 /* This entry modifies the banking interface */
2412 _X_EXPORT Bool
2413 miModifyBanking(
2414 ScreenPtr pScreen,
2415 miBankInfoPtr pBankInfo
2418 unsigned int type;
2420 if (!pScreen)
2421 return FALSE;
2423 if (miBankGeneration == serverGeneration)
2425 SCREEN_INIT;
2427 if (pScreenPriv)
2429 if (!pBankInfo || !pBankInfo->BankSize ||
2430 !pBankInfo->pBankA || !pBankInfo->pBankB ||
2431 !pBankInfo->SetSourceBank || !pBankInfo->SetDestinationBank ||
2432 !pBankInfo->SetSourceAndDestinationBanks)
2433 return FALSE;
2435 /* BankSize and nBankDepth cannot, as yet, be changed */
2436 if ((pScreenPriv->BankInfo.BankSize != pBankInfo->BankSize) ||
2437 (pScreenPriv->BankInfo.nBankDepth != pBankInfo->nBankDepth))
2438 return FALSE;
2440 if ((type = miBankDeriveType(pScreen, pBankInfo)) == BANK_NOBANK)
2441 return FALSE;
2443 /* Reset banking info */
2444 pScreenPriv->BankInfo = *pBankInfo;
2445 if (type != pScreenPriv->type)
2448 * Banking type is changing. Revalidate all window GC's.
2450 pScreenPriv->type = type;
2451 WalkTree(pScreen, miBankNewSerialNumber, 0);
2454 return TRUE;
2458 if (!pBankInfo || !pBankInfo->BankSize)
2459 return TRUE; /* No change requested */
2461 return FALSE;
2465 * Given various screen attributes, determine the minimum scanline width such
2466 * that each scanline is server and DDX padded and any pixels with imbedded
2467 * bank boundaries are off-screen. This function returns -1 if such a width
2468 * cannot exist. This function exists because the DDX needs to be able to
2469 * determine this width before initializing a frame buffer.
2472 miScanLineWidth(
2473 unsigned int xsize, /* pixels */
2474 unsigned int ysize, /* pixels */
2475 unsigned int width, /* pixels */
2476 unsigned long BankSize, /* char's */
2477 PixmapFormatRec *pBankFormat,
2478 unsigned int nWidthUnit /* bits */
2481 unsigned long nBitsPerBank, nBitsPerScanline, nBitsPerScanlinePadUnit;
2482 unsigned long minBitsPerScanline, maxBitsPerScanline;
2484 /* Sanity checks */
2486 if (!nWidthUnit || !pBankFormat)
2487 return -1;
2489 nBitsPerBank = BankSize * 8;
2490 if (nBitsPerBank % pBankFormat->scanlinePad)
2491 return -1;
2493 if (xsize > width)
2494 width = xsize;
2495 nBitsPerScanlinePadUnit = miLCM(pBankFormat->scanlinePad, nWidthUnit);
2496 nBitsPerScanline =
2497 (((width * pBankFormat->bitsPerPixel) + nBitsPerScanlinePadUnit - 1) /
2498 nBitsPerScanlinePadUnit) * nBitsPerScanlinePadUnit;
2499 width = nBitsPerScanline / pBankFormat->bitsPerPixel;
2501 if (!xsize || !(nBitsPerBank % pBankFormat->bitsPerPixel))
2502 return (int)width;
2505 * Scanlines will be server-pad aligned at this point. They will also be
2506 * a multiple of nWidthUnit bits long. Ensure that pixels with imbedded
2507 * bank boundaries are off-screen.
2509 * It seems reasonable to limit total frame buffer size to 1/16 of the
2510 * theoretical maximum address space size. On a machine with 32-bit
2511 * addresses (to 8-bit quantities) this turns out to be 256MB. Not only
2512 * does this provide a simple limiting condition for the loops below, but
2513 * it also prevents unsigned long wraparounds.
2515 if (!ysize)
2516 return -1;
2518 minBitsPerScanline = xsize * pBankFormat->bitsPerPixel;
2519 if (minBitsPerScanline > nBitsPerBank)
2520 return -1;
2522 if (ysize == 1)
2523 return (int)width;
2525 maxBitsPerScanline =
2526 (((unsigned long)(-1) >> 1) - minBitsPerScanline) / (ysize - 1);
2527 while (nBitsPerScanline <= maxBitsPerScanline)
2529 unsigned long BankBase, BankUnit;
2531 BankUnit = ((nBitsPerBank + nBitsPerScanline - 1) / nBitsPerBank) *
2532 nBitsPerBank;
2533 if (!(BankUnit % nBitsPerScanline))
2534 return (int)width;
2536 for (BankBase = BankUnit; ; BankBase += nBitsPerBank)
2538 unsigned long x, y;
2540 y = BankBase / nBitsPerScanline;
2541 if (y >= ysize)
2542 return (int)width;
2544 x = BankBase % nBitsPerScanline;
2545 if (!(x % pBankFormat->bitsPerPixel))
2546 continue;
2548 if (x < minBitsPerScanline)
2551 * Skip ahead certain widths by dividing the excess scanline
2552 * amongst the y's.
2554 y *= nBitsPerScanlinePadUnit;
2555 nBitsPerScanline +=
2556 ((x + y - 1) / y) * nBitsPerScanlinePadUnit;
2557 width = nBitsPerScanline / pBankFormat->bitsPerPixel;
2558 break;
2561 if (BankBase != BankUnit)
2562 continue;
2564 if (!(nBitsPerScanline % x))
2565 return (int)width;
2567 BankBase = ((nBitsPerScanline - minBitsPerScanline) /
2568 (nBitsPerScanline - x)) * BankUnit;
2572 return -1;