105b261ecSmrg/*
205b261ecSmrg *
305b261ecSmrg * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
405b261ecSmrg *
505b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that
705b261ecSmrg * the above copyright notice appear in all copies and that both that
805b261ecSmrg * copyright notice and this permission notice appear in supporting
905b261ecSmrg * documentation, and that the name of Keith Packard not be used in
1005b261ecSmrg * advertising or publicity pertaining to distribution of the software without
1105b261ecSmrg * specific, written prior permission.  Keith Packard makes no
1205b261ecSmrg * representations about the suitability of this software for any purpose.  It
1305b261ecSmrg * is provided "as is" without express or implied warranty.
1405b261ecSmrg *
1505b261ecSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1605b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1705b261ecSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1805b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1905b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
2005b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2105b261ecSmrg * PERFORMANCE OF THIS SOFTWARE.
2205b261ecSmrg */
2305b261ecSmrg
2405b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
2505b261ecSmrg#include <dix-config.h>
2605b261ecSmrg#endif
2705b261ecSmrg
2805b261ecSmrg#include    <X11/X.h>
2905b261ecSmrg#include    "scrnintstr.h"
3005b261ecSmrg#include    "windowstr.h"
3105b261ecSmrg#include    <X11/fonts/font.h>
3205b261ecSmrg#include    "dixfontstr.h"
3305b261ecSmrg#include    <X11/fonts/fontstruct.h>
3405b261ecSmrg#include    "mi.h"
3505b261ecSmrg#include    "regionstr.h"
3605b261ecSmrg#include    "globals.h"
3705b261ecSmrg#include    "gcstruct.h"
3805b261ecSmrg#include    "shadow.h"
3905b261ecSmrg#include    "fb.h"
4005b261ecSmrg
4105b261ecSmrg/*
4205b261ecSmrg * These indicate which way the source (shadow) is scanned when
4305b261ecSmrg * walking the screen in a particular direction
4405b261ecSmrg */
4505b261ecSmrg
4605b261ecSmrg#define LEFT_TO_RIGHT	1
4705b261ecSmrg#define RIGHT_TO_LEFT	-1
4805b261ecSmrg#define TOP_TO_BOTTOM	2
4905b261ecSmrg#define BOTTOM_TO_TOP	-2
5005b261ecSmrg
5105b261ecSmrgvoid
5235c4bbdfSmrgshadowUpdateRotatePacked(ScreenPtr pScreen, shadowBufPtr pBuf)
5305b261ecSmrg{
541b5d61b8Smrg    RegionPtr damage = DamageRegion(pBuf->pDamage);
5535c4bbdfSmrg    PixmapPtr pShadow = pBuf->pPixmap;
5635c4bbdfSmrg    int nbox = RegionNumRects(damage);
5735c4bbdfSmrg    BoxPtr pbox = RegionRects(damage);
5835c4bbdfSmrg    FbBits *shaBits;
5935c4bbdfSmrg    FbStride shaStride;
6035c4bbdfSmrg    int shaBpp;
6135c4bbdfSmrg    _X_UNUSED int shaXoff, shaYoff;
6235c4bbdfSmrg    int box_x1, box_x2, box_y1, box_y2;
6335c4bbdfSmrg    int sha_x1 = 0, sha_y1 = 0;
6435c4bbdfSmrg    int scr_x1 = 0, scr_x2 = 0, scr_y1 = 0, scr_y2 = 0, scr_w, scr_h;
6535c4bbdfSmrg    int scr_x, scr_y;
6635c4bbdfSmrg    int w;
6735c4bbdfSmrg    int pixelsPerBits;
6835c4bbdfSmrg    int pixelsMask;
6935c4bbdfSmrg    FbStride shaStepOverY = 0, shaStepDownY = 0;
7035c4bbdfSmrg    FbStride shaStepOverX = 0, shaStepDownX = 0;
7135c4bbdfSmrg    FbBits *shaLine, *sha;
7235c4bbdfSmrg    int shaHeight = pShadow->drawable.height;
7335c4bbdfSmrg    int shaWidth = pShadow->drawable.width;
7435c4bbdfSmrg    FbBits shaMask;
7535c4bbdfSmrg    int shaFirstShift, shaShift;
7635c4bbdfSmrg    int o_x_dir;
7735c4bbdfSmrg    int o_y_dir;
7835c4bbdfSmrg    int x_dir;
7935c4bbdfSmrg    int y_dir;
8005b261ecSmrg
8135c4bbdfSmrg    fbGetDrawable(&pShadow->drawable, shaBits, shaStride, shaBpp, shaXoff,
8235c4bbdfSmrg                  shaYoff);
8335c4bbdfSmrg    pixelsPerBits = (sizeof(FbBits) * 8) / shaBpp;
8405b261ecSmrg    pixelsMask = ~(pixelsPerBits - 1);
8535c4bbdfSmrg    shaMask = FbBitsMask(FB_UNIT - shaBpp, shaBpp);
8605b261ecSmrg    /*
8705b261ecSmrg     * Compute rotation related constants to walk the shadow
8805b261ecSmrg     */
8905b261ecSmrg    o_x_dir = LEFT_TO_RIGHT;
9005b261ecSmrg    o_y_dir = TOP_TO_BOTTOM;
9105b261ecSmrg    if (pBuf->randr & SHADOW_REFLECT_X)
9235c4bbdfSmrg        o_x_dir = -o_x_dir;
9305b261ecSmrg    if (pBuf->randr & SHADOW_REFLECT_Y)
9435c4bbdfSmrg        o_y_dir = -o_y_dir;
9505b261ecSmrg    switch (pBuf->randr & (SHADOW_ROTATE_ALL)) {
9635c4bbdfSmrg    case SHADOW_ROTATE_0:      /* upper left shadow -> upper left screen */
9705b261ecSmrg    default:
9835c4bbdfSmrg        x_dir = o_x_dir;
9935c4bbdfSmrg        y_dir = o_y_dir;
10035c4bbdfSmrg        break;
10135c4bbdfSmrg    case SHADOW_ROTATE_90:     /* upper right shadow -> upper left screen */
10235c4bbdfSmrg        x_dir = o_y_dir;
10335c4bbdfSmrg        y_dir = -o_x_dir;
10435c4bbdfSmrg        break;
10535c4bbdfSmrg    case SHADOW_ROTATE_180:    /* lower right shadow -> upper left screen */
10635c4bbdfSmrg        x_dir = -o_x_dir;
10735c4bbdfSmrg        y_dir = -o_y_dir;
10835c4bbdfSmrg        break;
10935c4bbdfSmrg    case SHADOW_ROTATE_270:    /* lower left shadow -> upper left screen */
11035c4bbdfSmrg        x_dir = -o_y_dir;
11135c4bbdfSmrg        y_dir = o_x_dir;
11235c4bbdfSmrg        break;
11305b261ecSmrg    }
11405b261ecSmrg    switch (x_dir) {
11505b261ecSmrg    case LEFT_TO_RIGHT:
11635c4bbdfSmrg        shaStepOverX = shaBpp;
11735c4bbdfSmrg        shaStepOverY = 0;
11835c4bbdfSmrg        break;
11905b261ecSmrg    case TOP_TO_BOTTOM:
12035c4bbdfSmrg        shaStepOverX = 0;
12135c4bbdfSmrg        shaStepOverY = shaStride;
12235c4bbdfSmrg        break;
12305b261ecSmrg    case RIGHT_TO_LEFT:
12435c4bbdfSmrg        shaStepOverX = -shaBpp;
12535c4bbdfSmrg        shaStepOverY = 0;
12635c4bbdfSmrg        break;
12705b261ecSmrg    case BOTTOM_TO_TOP:
12835c4bbdfSmrg        shaStepOverX = 0;
12935c4bbdfSmrg        shaStepOverY = -shaStride;
13035c4bbdfSmrg        break;
13105b261ecSmrg    }
13205b261ecSmrg    switch (y_dir) {
13305b261ecSmrg    case TOP_TO_BOTTOM:
13435c4bbdfSmrg        shaStepDownX = 0;
13535c4bbdfSmrg        shaStepDownY = shaStride;
13635c4bbdfSmrg        break;
13705b261ecSmrg    case RIGHT_TO_LEFT:
13835c4bbdfSmrg        shaStepDownX = -shaBpp;
13935c4bbdfSmrg        shaStepDownY = 0;
14035c4bbdfSmrg        break;
14105b261ecSmrg    case BOTTOM_TO_TOP:
14235c4bbdfSmrg        shaStepDownX = 0;
14335c4bbdfSmrg        shaStepDownY = -shaStride;
14435c4bbdfSmrg        break;
14505b261ecSmrg    case LEFT_TO_RIGHT:
14635c4bbdfSmrg        shaStepDownX = shaBpp;
14735c4bbdfSmrg        shaStepDownY = 0;
14835c4bbdfSmrg        break;
14905b261ecSmrg    }
15035c4bbdfSmrg
15135c4bbdfSmrg    while (nbox--) {
15205b261ecSmrg        box_x1 = pbox->x1;
15305b261ecSmrg        box_y1 = pbox->y1;
15405b261ecSmrg        box_x2 = pbox->x2;
15505b261ecSmrg        box_y2 = pbox->y2;
15605b261ecSmrg        pbox++;
15705b261ecSmrg
15835c4bbdfSmrg        /*
15935c4bbdfSmrg         * Compute screen and shadow locations for this box
16035c4bbdfSmrg         */
16135c4bbdfSmrg        switch (x_dir) {
16235c4bbdfSmrg        case LEFT_TO_RIGHT:
16335c4bbdfSmrg            scr_x1 = box_x1 & pixelsMask;
16435c4bbdfSmrg            scr_x2 = (box_x2 + pixelsPerBits - 1) & pixelsMask;
16535c4bbdfSmrg
16635c4bbdfSmrg            sha_x1 = scr_x1;
16735c4bbdfSmrg            break;
16835c4bbdfSmrg        case TOP_TO_BOTTOM:
16935c4bbdfSmrg            scr_x1 = box_y1 & pixelsMask;
17035c4bbdfSmrg            scr_x2 = (box_y2 + pixelsPerBits - 1) & pixelsMask;
17135c4bbdfSmrg
17235c4bbdfSmrg            sha_y1 = scr_x1;
17335c4bbdfSmrg            break;
17435c4bbdfSmrg        case RIGHT_TO_LEFT:
17535c4bbdfSmrg            scr_x1 = (shaWidth - box_x2) & pixelsMask;
17635c4bbdfSmrg            scr_x2 = (shaWidth - box_x1 + pixelsPerBits - 1) & pixelsMask;
17735c4bbdfSmrg
17835c4bbdfSmrg            sha_x1 = (shaWidth - scr_x1 - 1);
17935c4bbdfSmrg            break;
18035c4bbdfSmrg        case BOTTOM_TO_TOP:
18135c4bbdfSmrg            scr_x1 = (shaHeight - box_y2) & pixelsMask;
18235c4bbdfSmrg            scr_x2 = (shaHeight - box_y1 + pixelsPerBits - 1) & pixelsMask;
18305b261ecSmrg
18435c4bbdfSmrg            sha_y1 = (shaHeight - scr_x1 - 1);
18535c4bbdfSmrg            break;
18635c4bbdfSmrg        }
18735c4bbdfSmrg        switch (y_dir) {
18835c4bbdfSmrg        case TOP_TO_BOTTOM:
18935c4bbdfSmrg            scr_y1 = box_y1;
19035c4bbdfSmrg            scr_y2 = box_y2;
19105b261ecSmrg
19235c4bbdfSmrg            sha_y1 = scr_y1;
19335c4bbdfSmrg            break;
19435c4bbdfSmrg        case RIGHT_TO_LEFT:
19535c4bbdfSmrg            scr_y1 = (shaWidth - box_x2);
19635c4bbdfSmrg            scr_y2 = (shaWidth - box_x1);
19705b261ecSmrg
19835c4bbdfSmrg            sha_x1 = box_x2 - 1;
19935c4bbdfSmrg            break;
20035c4bbdfSmrg        case BOTTOM_TO_TOP:
20135c4bbdfSmrg            scr_y1 = shaHeight - box_y2;
20235c4bbdfSmrg            scr_y2 = shaHeight - box_y1;
20305b261ecSmrg
20435c4bbdfSmrg            sha_y1 = box_y2 - 1;
20535c4bbdfSmrg            break;
20635c4bbdfSmrg        case LEFT_TO_RIGHT:
20735c4bbdfSmrg            scr_y1 = box_x1;
20835c4bbdfSmrg            scr_y2 = box_x2;
20905b261ecSmrg
21035c4bbdfSmrg            sha_x1 = box_x1;
21135c4bbdfSmrg            break;
21235c4bbdfSmrg        }
21335c4bbdfSmrg        scr_w = ((scr_x2 - scr_x1) * shaBpp) >> FB_SHIFT;
21435c4bbdfSmrg        scr_h = scr_y2 - scr_y1;
21535c4bbdfSmrg        scr_y = scr_y1;
21605b261ecSmrg
21735c4bbdfSmrg        /* shift amount for first pixel on screen */
21835c4bbdfSmrg        shaFirstShift = FB_UNIT - ((sha_x1 * shaBpp) & FB_MASK) - shaBpp;
21905b261ecSmrg
22035c4bbdfSmrg        /* pointer to shadow data first placed on screen */
22135c4bbdfSmrg        shaLine = (shaBits +
22235c4bbdfSmrg                   sha_y1 * shaStride + ((sha_x1 * shaBpp) >> FB_SHIFT));
22305b261ecSmrg
22435c4bbdfSmrg        /*
22535c4bbdfSmrg         * Copy the bits, always write across the physical frame buffer
22635c4bbdfSmrg         * to take advantage of write combining.
22735c4bbdfSmrg         */
22835c4bbdfSmrg        while (scr_h--) {
22935c4bbdfSmrg            int p;
23035c4bbdfSmrg            FbBits bits;
23135c4bbdfSmrg            FbBits *win;
23235c4bbdfSmrg            int i;
23335c4bbdfSmrg            CARD32 winSize;
23405b261ecSmrg
23535c4bbdfSmrg            sha = shaLine;
23635c4bbdfSmrg            shaShift = shaFirstShift;
23735c4bbdfSmrg            w = scr_w;
23835c4bbdfSmrg            scr_x = scr_x1 * shaBpp >> FB_SHIFT;
23935c4bbdfSmrg
24035c4bbdfSmrg            while (w) {
24135c4bbdfSmrg                /*
24235c4bbdfSmrg                 * Map some of this line
24335c4bbdfSmrg                 */
24435c4bbdfSmrg                win = (FbBits *) (*pBuf->window) (pScreen,
24535c4bbdfSmrg                                                  scr_y,
24635c4bbdfSmrg                                                  scr_x << 2,
24735c4bbdfSmrg                                                  SHADOW_WINDOW_WRITE,
24835c4bbdfSmrg                                                  &winSize, pBuf->closure);
24935c4bbdfSmrg                i = (winSize >> 2);
25035c4bbdfSmrg                if (i > w)
25135c4bbdfSmrg                    i = w;
25235c4bbdfSmrg                w -= i;
25335c4bbdfSmrg                scr_x += i;
25435c4bbdfSmrg                /*
25535c4bbdfSmrg                 * Copy the portion of the line mapped
25635c4bbdfSmrg                 */
25735c4bbdfSmrg                while (i--) {
25835c4bbdfSmrg                    bits = 0;
25935c4bbdfSmrg                    p = pixelsPerBits;
26035c4bbdfSmrg                    /*
26135c4bbdfSmrg                     * Build one word of output from multiple inputs
26235c4bbdfSmrg                     *
26335c4bbdfSmrg                     * Note that for 90/270 rotations, this will walk
26435c4bbdfSmrg                     * down the shadow hitting each scanline once.
26535c4bbdfSmrg                     * This is probably not very efficient.
26635c4bbdfSmrg                     */
26735c4bbdfSmrg                    while (p--) {
26835c4bbdfSmrg                        bits = FbScrLeft(bits, shaBpp);
26935c4bbdfSmrg                        bits |= FbScrRight(*sha, shaShift) & shaMask;
27035c4bbdfSmrg
27135c4bbdfSmrg                        shaShift -= shaStepOverX;
27235c4bbdfSmrg                        if (shaShift >= FB_UNIT) {
27335c4bbdfSmrg                            shaShift -= FB_UNIT;
27435c4bbdfSmrg                            sha--;
27535c4bbdfSmrg                        }
27635c4bbdfSmrg                        else if (shaShift < 0) {
27735c4bbdfSmrg                            shaShift += FB_UNIT;
27835c4bbdfSmrg                            sha++;
27935c4bbdfSmrg                        }
28035c4bbdfSmrg                        sha += shaStepOverY;
28135c4bbdfSmrg                    }
28235c4bbdfSmrg                    *win++ = bits;
28335c4bbdfSmrg                }
28435c4bbdfSmrg            }
28535c4bbdfSmrg            scr_y++;
28635c4bbdfSmrg            shaFirstShift -= shaStepDownX;
28735c4bbdfSmrg            if (shaFirstShift >= FB_UNIT) {
28835c4bbdfSmrg                shaFirstShift -= FB_UNIT;
28935c4bbdfSmrg                shaLine--;
29035c4bbdfSmrg            }
29135c4bbdfSmrg            else if (shaFirstShift < 0) {
29235c4bbdfSmrg                shaFirstShift += FB_UNIT;
29335c4bbdfSmrg                shaLine++;
29435c4bbdfSmrg            }
29535c4bbdfSmrg            shaLine += shaStepDownY;
29635c4bbdfSmrg        }
29705b261ecSmrg    }
29805b261ecSmrg}
299