1/*
2 *
3 * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Keith Packard not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission.  Keith Packard makes no
12 * representations about the suitability of this software for any purpose.  It
13 * is provided "as is" without express or implied warranty.
14 *
15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#ifdef HAVE_DIX_CONFIG_H
25#include <dix-config.h>
26#endif
27
28#include    <X11/X.h>
29#include    "scrnintstr.h"
30#include    "windowstr.h"
31#include    <X11/fonts/font.h>
32#include    "dixfontstr.h"
33#include    <X11/fonts/fontstruct.h>
34#include    "mi.h"
35#include    "regionstr.h"
36#include    "globals.h"
37#include    "gcstruct.h"
38#include    "shadow.h"
39#include    "fb.h"
40
41/*
42 * These indicate which way the source (shadow) is scanned when
43 * walking the screen in a particular direction
44 */
45
46#define LEFT_TO_RIGHT	1
47#define RIGHT_TO_LEFT	-1
48#define TOP_TO_BOTTOM	2
49#define BOTTOM_TO_TOP	-2
50
51void
52shadowUpdateRotatePacked (ScreenPtr	pScreen,
53			  shadowBufPtr	pBuf)
54{
55    RegionPtr	damage = shadowDamage (pBuf);
56    PixmapPtr	pShadow = pBuf->pPixmap;
57    int		nbox = RegionNumRects (damage);
58    BoxPtr	pbox = RegionRects (damage);
59    FbBits	*shaBits;
60    FbStride	shaStride;
61    int		shaBpp;
62    int		shaXoff, shaYoff;
63    int		box_x1, box_x2, box_y1, box_y2;
64    int		sha_x1 = 0, sha_y1 = 0;
65    int		scr_x1 = 0, scr_x2 = 0, scr_y1 = 0, scr_y2 = 0, scr_w, scr_h;
66    int		scr_x, scr_y;
67    int		w;
68    int		pixelsPerBits;
69    int		pixelsMask;
70    FbStride	shaStepOverY = 0, shaStepDownY = 0;
71    FbStride	shaStepOverX = 0, shaStepDownX = 0;
72    FbBits	*shaLine, *sha;
73    int		shaHeight = pShadow->drawable.height;
74    int		shaWidth = pShadow->drawable.width;
75    FbBits	shaMask;
76    int		shaFirstShift, shaShift;
77    int		o_x_dir;
78    int		o_y_dir;
79    int		x_dir;
80    int		y_dir;
81
82    fbGetDrawable (&pShadow->drawable, shaBits, shaStride, shaBpp, shaXoff, shaYoff);
83    pixelsPerBits = (sizeof (FbBits) * 8) / shaBpp;
84    pixelsMask = ~(pixelsPerBits - 1);
85    shaMask = FbBitsMask (FB_UNIT-shaBpp, shaBpp);
86    /*
87     * Compute rotation related constants to walk the shadow
88     */
89    o_x_dir = LEFT_TO_RIGHT;
90    o_y_dir = TOP_TO_BOTTOM;
91    if (pBuf->randr & SHADOW_REFLECT_X)
92	o_x_dir = -o_x_dir;
93    if (pBuf->randr & SHADOW_REFLECT_Y)
94	o_y_dir = -o_y_dir;
95    switch (pBuf->randr & (SHADOW_ROTATE_ALL)) {
96    case SHADOW_ROTATE_0:	/* upper left shadow -> upper left screen */
97    default:
98	x_dir = o_x_dir;
99	y_dir = o_y_dir;
100	break;
101    case SHADOW_ROTATE_90:    	/* upper right shadow -> upper left screen */
102	x_dir = o_y_dir;
103	y_dir = -o_x_dir;
104	break;
105    case SHADOW_ROTATE_180:	/* lower right shadow -> upper left screen */
106	x_dir = -o_x_dir;
107	y_dir = -o_y_dir;
108	break;
109    case SHADOW_ROTATE_270:	/* lower left shadow -> upper left screen */
110	x_dir = -o_y_dir;
111	y_dir = o_x_dir;
112	break;
113    }
114    switch (x_dir) {
115    case LEFT_TO_RIGHT:
116	shaStepOverX = shaBpp;
117	shaStepOverY = 0;
118	break;
119    case TOP_TO_BOTTOM:
120	shaStepOverX = 0;
121	shaStepOverY = shaStride;
122	break;
123    case RIGHT_TO_LEFT:
124	shaStepOverX = -shaBpp;
125	shaStepOverY = 0;
126	break;
127    case BOTTOM_TO_TOP:
128	shaStepOverX = 0;
129	shaStepOverY = -shaStride;
130	break;
131    }
132    switch (y_dir) {
133    case TOP_TO_BOTTOM:
134	shaStepDownX = 0;
135	shaStepDownY = shaStride;
136	break;
137    case RIGHT_TO_LEFT:
138	shaStepDownX = -shaBpp;
139	shaStepDownY = 0;
140	break;
141    case BOTTOM_TO_TOP:
142	shaStepDownX = 0;
143	shaStepDownY = -shaStride;
144	break;
145    case LEFT_TO_RIGHT:
146	shaStepDownX = shaBpp;
147	shaStepDownY = 0;
148	break;
149    }
150
151    while (nbox--)
152    {
153        box_x1 = pbox->x1;
154        box_y1 = pbox->y1;
155        box_x2 = pbox->x2;
156        box_y2 = pbox->y2;
157        pbox++;
158
159	/*
160	 * Compute screen and shadow locations for this box
161	 */
162	switch (x_dir) {
163	case LEFT_TO_RIGHT:
164	    scr_x1 = box_x1 & pixelsMask;
165	    scr_x2 = (box_x2 + pixelsPerBits - 1) & pixelsMask;
166
167	    sha_x1 = scr_x1;
168	    break;
169	case TOP_TO_BOTTOM:
170	    scr_x1 = box_y1 & pixelsMask;
171	    scr_x2 = (box_y2 + pixelsPerBits - 1) & pixelsMask;
172
173	    sha_y1 = scr_x1;
174	    break;
175	case RIGHT_TO_LEFT:
176	    scr_x1 = (shaWidth - box_x2) & pixelsMask;
177	    scr_x2 = (shaWidth - box_x1 + pixelsPerBits - 1) & pixelsMask;
178
179	    sha_x1 = (shaWidth - scr_x1 - 1);
180	    break;
181	case BOTTOM_TO_TOP:
182	    scr_x1 = (shaHeight - box_y2) & pixelsMask;
183	    scr_x2 = (shaHeight - box_y1 + pixelsPerBits - 1) & pixelsMask;
184
185	    sha_y1 = (shaHeight - scr_x1 - 1);
186	    break;
187	}
188	switch (y_dir) {
189	case TOP_TO_BOTTOM:
190	    scr_y1 = box_y1;
191	    scr_y2 = box_y2;
192
193	    sha_y1 = scr_y1;
194	    break;
195	case RIGHT_TO_LEFT:
196	    scr_y1 = (shaWidth - box_x2);
197	    scr_y2 = (shaWidth - box_x1);
198
199	    sha_x1 = box_x2 - 1;
200	    break;
201	case BOTTOM_TO_TOP:
202	    scr_y1 = shaHeight - box_y2;
203	    scr_y2 = shaHeight - box_y1;
204
205	    sha_y1 = box_y2 - 1;
206	    break;
207	case LEFT_TO_RIGHT:
208	    scr_y1 = box_x1;
209	    scr_y2 = box_x2;
210
211	    sha_x1 = box_x1;
212	    break;
213	}
214	scr_w = ((scr_x2 - scr_x1) * shaBpp) >> FB_SHIFT;
215	scr_h = scr_y2 - scr_y1;
216	scr_y = scr_y1;
217
218	/* shift amount for first pixel on screen */
219	shaFirstShift = FB_UNIT - ((sha_x1 * shaBpp) & FB_MASK) - shaBpp;
220
221	/* pointer to shadow data first placed on screen */
222	shaLine = (shaBits +
223		   sha_y1 * shaStride +
224		   ((sha_x1 * shaBpp) >> FB_SHIFT));
225
226	/*
227	 * Copy the bits, always write across the physical frame buffer
228	 * to take advantage of write combining.
229	 */
230	while (scr_h--)
231	{
232	    int	    p;
233	    FbBits  bits;
234	    FbBits  *win;
235	    int	    i;
236	    CARD32  winSize;
237
238	    sha = shaLine;
239	    shaShift = shaFirstShift;
240	    w = scr_w;
241	    scr_x = scr_x1 * shaBpp >> FB_SHIFT;
242
243	    while (w)
244	    {
245		/*
246		 * Map some of this line
247		 */
248		win = (FbBits *) (*pBuf->window) (pScreen,
249						  scr_y,
250						  scr_x << 2,
251						  SHADOW_WINDOW_WRITE,
252						  &winSize,
253						  pBuf->closure);
254		i = (winSize >> 2);
255		if (i > w)
256		    i = w;
257		w -= i;
258		scr_x += i;
259		/*
260		 * Copy the portion of the line mapped
261		 */
262		while (i--)
263		{
264		    bits = 0;
265		    p = pixelsPerBits;
266		    /*
267		     * Build one word of output from multiple inputs
268		     *
269		     * Note that for 90/270 rotations, this will walk
270		     * down the shadow hitting each scanline once.
271		     * This is probably not very efficient.
272		     */
273		    while (p--)
274		    {
275			bits = FbScrLeft(bits, shaBpp);
276			bits |= FbScrRight (*sha, shaShift) & shaMask;
277
278			shaShift -= shaStepOverX;
279			if (shaShift >= FB_UNIT)
280			{
281			    shaShift -= FB_UNIT;
282			    sha--;
283			}
284			else if (shaShift < 0)
285			{
286			    shaShift += FB_UNIT;
287			    sha++;
288			}
289			sha += shaStepOverY;
290		    }
291		    *win++ = bits;
292		}
293	    }
294	    scr_y++;
295	    shaFirstShift -= shaStepDownX;
296	    if (shaFirstShift >= FB_UNIT)
297	    {
298		shaFirstShift -= FB_UNIT;
299		shaLine--;
300	    }
301	    else if (shaFirstShift < 0)
302	    {
303		shaFirstShift += FB_UNIT;
304		shaLine++;
305	    }
306	    shaLine += shaStepDownY;
307	}
308    }
309}
310
311shadowUpdateProc shadowUpdateRotatePackedWeak(void) {
312    return shadowUpdateRotatePacked;
313}
314