1/*
2 * Copyright © 1998 Keith Packard
3 * Copyright © 2012 Intel Corporation
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#include "fb.h"
25#include <gcstruct.h>
26#include <scrnintstr.h>
27
28/*
29 * Pad pixmap to FB_UNIT bits wide
30 */
31void
32fbPadPixmap(PixmapPtr pPixmap)
33{
34	int width;
35	FbBits *bits;
36	FbBits b;
37	FbBits mask;
38	int height;
39	int w;
40	int stride;
41	int bpp;
42	_X_UNUSED int xOff, yOff;
43
44	fbGetDrawable(&pPixmap->drawable, bits, stride, bpp, xOff, yOff);
45
46	width = pPixmap->drawable.width * pPixmap->drawable.bitsPerPixel;
47	height = pPixmap->drawable.height;
48	mask = FbBitsMask(0, width);
49	while (height--) {
50		b = READ(bits) & mask;
51		w = width;
52		while (w < FB_UNIT) {
53			b = b | FbScrRight(b, w);
54			w <<= 1;
55		}
56		WRITE(bits, b);
57		bits += stride;
58	}
59}
60
61/*
62 * Verify that 'bits' repeats every 'len' bits
63 */
64static Bool
65fbBitsRepeat(FbBits bits, int len, int width)
66{
67	FbBits mask = FbBitsMask(0, len);
68	FbBits orig = bits & mask;
69	int i;
70
71	if (width > FB_UNIT)
72		width = FB_UNIT;
73	for (i = 0; i < width / len; i++) {
74		if ((bits & mask) != orig)
75			return FALSE;
76		bits = FbScrLeft(bits, len);
77	}
78	return TRUE;
79}
80
81/*
82 * Check whether an entire bitmap line is a repetition of
83 * the first 'len' bits
84 */
85static Bool
86fbLineRepeat(FbBits * bits, int len, int width)
87{
88	FbBits first = bits[0];
89
90	if (!fbBitsRepeat(first, len, width))
91		return FALSE;
92	width = (width + FB_UNIT - 1) >> FB_SHIFT;
93	bits++;
94	while (--width)
95		if (READ(bits) != first)
96			return FALSE;
97	return TRUE;
98}
99
100/*
101 * The even stipple code wants the first FB_UNIT/bpp bits on
102 * each scanline to represent the entire stipple
103 */
104static Bool
105fbCanEvenStipple(PixmapPtr pStipple, int bpp)
106{
107	int len = FB_UNIT / bpp;
108	FbBits *bits;
109	int stride;
110	int stip_bpp;
111	_X_UNUSED int stipXoff, stipYoff;
112	int h;
113
114	/* make sure the stipple width is a multiple of the even stipple width */
115	if (pStipple->drawable.width % len != 0)
116		return FALSE;
117
118	fbGetDrawable(&pStipple->drawable, bits, stride, stip_bpp, stipXoff,
119		      stipYoff);
120	h = pStipple->drawable.height;
121	/* check to see that the stipple repeats horizontally */
122	while (h--) {
123		if (!fbLineRepeat(bits, len, pStipple->drawable.width))
124			return FALSE;
125
126		bits += stride;
127	}
128	return TRUE;
129}
130
131void
132fbValidateGC(GCPtr gc, unsigned long changes, DrawablePtr drawable)
133{
134	FbGCPrivPtr pgc = fb_gc(gc);
135	FbBits mask;
136
137	DBG(("%s changes=%lx\n", __FUNCTION__, changes));
138
139	if (changes & GCStipple) {
140		pgc->evenStipple = FALSE;
141
142		if (gc->stipple) {
143			/* can we do an even stipple ?? */
144			if (FbEvenStip(gc->stipple->drawable.width,
145				       drawable->bitsPerPixel) &&
146			    (fbCanEvenStipple(gc->stipple, drawable->bitsPerPixel)))
147				pgc->evenStipple = TRUE;
148		}
149	}
150
151	/*
152	 * Recompute reduced rop values
153	 */
154	if (changes & (GCForeground | GCBackground | GCPlaneMask | GCFunction)) {
155		int s;
156		FbBits depthMask;
157
158		mask = FbFullMask(drawable->bitsPerPixel);
159		depthMask = FbFullMask(drawable->depth);
160
161		DBG(("%s: computing rrop mask=%08x, depthMask=%08x, fg=%08x, bg=%08x, planemask=%08x\n",
162		     __FUNCTION__, mask, depthMask, (int)gc->fgPixel, (int)gc->bgPixel, (int)gc->planemask));
163
164		pgc->fg = gc->fgPixel & mask;
165		pgc->bg = gc->bgPixel & mask;
166
167		if ((gc->planemask & depthMask) == depthMask)
168			pgc->pm = mask;
169		else
170			pgc->pm = gc->planemask & mask;
171
172		s = drawable->bitsPerPixel;
173		while (s < FB_UNIT) {
174			pgc->fg |= pgc->fg << s;
175			pgc->bg |= pgc->bg << s;
176			pgc->pm |= pgc->pm << s;
177			s <<= 1;
178		}
179		pgc->and = fbAnd(gc->alu, pgc->fg, pgc->pm);
180		pgc->xor = fbXor(gc->alu, pgc->fg, pgc->pm);
181		pgc->bgand = fbAnd(gc->alu, pgc->bg, pgc->pm);
182		pgc->bgxor = fbXor(gc->alu, pgc->bg, pgc->pm);
183
184		DBG(("%s: rrop fg=%08x, bg=%08x, pm=%08x, and=%08x, xor=%08x, bgand=%08x, bgxor=%08x\n",
185		     __FUNCTION__, pgc->fg, pgc->bg, pgc->pm, pgc->and, pgc->xor, pgc->bgand, pgc->bgxor));
186	}
187
188	if (changes & GCDashList) {
189		unsigned short n = gc->numInDashList;
190		unsigned char *dash = gc->dash;
191		unsigned int dashLength = 0;
192
193		while (n--)
194			dashLength += (unsigned int) *dash++;
195		pgc->dashLength = dashLength;
196	}
197}
198