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 */
24 #ifdef HAVE_DIX_CONFIG_H
25 #include <dix-config.h>
26 #endif
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"
41 /*
42 * These indicate which way the source (shadow) is scanned when
43 * walking the screen in a particular direction
44 */
46 #define LEFT_TO_RIGHT 1
47 #define RIGHT_TO_LEFT -1
48 #define TOP_TO_BOTTOM 2
49 #define BOTTOM_TO_TOP -2
51 void
52 shadowUpdateRotatePacked (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 _X_UNUSED 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;
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 }
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++;
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;
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;
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;
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;
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;
193 sha_y1 = scr_y1;
194 break;
195 case RIGHT_TO_LEFT:
196 scr_y1 = (shaWidth - box_x2);
197 scr_y2 = (shaWidth - box_x1);
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;
205 sha_y1 = box_y2 - 1;
206 break;
207 case LEFT_TO_RIGHT:
208 scr_y1 = box_x1;
209 scr_y2 = box_x2;
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;
218 /* shift amount for first pixel on screen */
219 shaFirstShift = FB_UNIT - ((sha_x1 * shaBpp) & FB_MASK) - shaBpp;
221 /* pointer to shadow data first placed on screen */
222 shaLine = (shaBits +
223 sha_y1 * shaStride +
224 ((sha_x1 * shaBpp) >> FB_SHIFT));
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;
238 sha = shaLine;
239 shaShift = shaFirstShift;
240 w = scr_w;
241 scr_x = scr_x1 * shaBpp >> FB_SHIFT;
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;
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 }
311 shadowUpdateProc shadowUpdateRotatePackedWeak(void) {
312 return shadowUpdateRotatePacked;
313 }