lx_exa.c revision 170d5fdc
1f29dbc25Smrg/*
2f29dbc25Smrg * Copyright (c) 2007-2008 Advanced Micro Devices, Inc.
3f29dbc25Smrg *
4f29dbc25Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5f29dbc25Smrg * copy of this software and associated documentation files (the "Software"),
6f29dbc25Smrg * to deal in the Software without restriction, including without limitation
7f29dbc25Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8f29dbc25Smrg * and/or sell copies of the Software, and to permit persons to whom the
9f29dbc25Smrg * Software is furnished to do so, subject to the following conditions:
10f29dbc25Smrg *
11f29dbc25Smrg * The above copyright notice and this permission notice shall be included in
12f29dbc25Smrg * all copies or substantial portions of the Software.
13f29dbc25Smrg *
14f29dbc25Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15f29dbc25Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16f29dbc25Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17f29dbc25Smrg * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18f29dbc25Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19f29dbc25Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20f29dbc25Smrg * DEALINGS IN THE SOFTWARE.
21f29dbc25Smrg *
22f29dbc25Smrg * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
23f29dbc25Smrg * contributors may be used to endorse or promote products derived from this
24f29dbc25Smrg * software without specific prior written permission.
25f29dbc25Smrg */
26f29dbc25Smrg
27f29dbc25Smrg/* TODO:
28f29dbc25Smrg   Support a8 as a source or destination?
29f29dbc25Smrg   convert !a8 or !a4 masks?
30f29dbc25Smrg   support multiple pass operations?
31f29dbc25Smrg*/
32f29dbc25Smrg
33f29dbc25Smrg/* To support PictOptAdd with a mask */
34f29dbc25Smrg
35f29dbc25Smrg#ifdef HAVE_CONFIG_H
36f29dbc25Smrg#include "config.h"
37f29dbc25Smrg#endif
38f29dbc25Smrg
39f29dbc25Smrg#include "xf86.h"
40f29dbc25Smrg#include "exa.h"
41f29dbc25Smrg
42f29dbc25Smrg#include "geode.h"
43f29dbc25Smrg#include "cim_defs.h"
44f29dbc25Smrg#include "cim_regs.h"
45f29dbc25Smrg
46f29dbc25Smrg#include "geode_blend.h"
47f29dbc25Smrg
48f29dbc25Smrg#define F(x)    IntToxFixed(x)
49f29dbc25Smrg#define I(x)    xFixedToInt(x)
50f29dbc25Smrg
51f29dbc25Smrgstatic const struct exa_format_t
52f29dbc25Smrg{
53f29dbc25Smrg    int exa;
54f29dbc25Smrg    int bpp;
55f29dbc25Smrg    int fmt;
56f29dbc25Smrg    int alphabits;
57f29dbc25Smrg} lx_exa_formats[] = {
58f29dbc25Smrg    {
59f29dbc25Smrg    PICT_a8r8g8b8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 8}, {
60f29dbc25Smrg    PICT_x8r8g8b8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 0}, {
61f29dbc25Smrg    PICT_x8b8g8r8, 32, CIMGP_SOURCE_FMT_32BPP_BGR, 0}, {
62f29dbc25Smrg    PICT_a4r4g4b4, 16, CIMGP_SOURCE_FMT_4_4_4_4, 4}, {
63f29dbc25Smrg    PICT_a1r5g5b5, 16, CIMGP_SOURCE_FMT_1_5_5_5, 1}, {
64f29dbc25Smrg    PICT_r5g6b5, 16, CIMGP_SOURCE_FMT_0_5_6_5, 0}, {
65f29dbc25Smrg    PICT_b5g6r5, 16, CIMGP_SOURCE_FMT_16BPP_BGR, 0}, {
66f29dbc25Smrg    PICT_x1r5g5b5, 16, CIMGP_SOURCE_FMT_1_5_5_5, 0}, {
67f29dbc25Smrg    PICT_x1b5g5r5, 16, CIMGP_SOURCE_FMT_15BPP_BGR, 0}, {
68170d5fdcSmrg    PICT_r3g3b2, 8, CIMGP_SOURCE_FMT_3_3_2, 0}, {
69170d5fdcSmrg    PICT_a8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 8}
70f29dbc25Smrg};
71f29dbc25Smrg
72f29dbc25Smrg/* This is a chunk of memory we use for scratch space */
73f29dbc25Smrg
74f29dbc25Smrg#define COMP_TYPE_MASK 0
75f29dbc25Smrg#define COMP_TYPE_ONEPASS 1
76f29dbc25Smrg#define COMP_TYPE_TWOPASS 3
77f29dbc25Smrg#define COMP_TYPE_ROTATE  5
78f29dbc25Smrg
79f29dbc25Smrgstatic struct
80f29dbc25Smrg{
81f29dbc25Smrg    int type;
82f29dbc25Smrg
83f29dbc25Smrg    unsigned int srcOffset;
84f29dbc25Smrg    unsigned int srcPitch;
85f29dbc25Smrg    unsigned int srcBpp;
86f29dbc25Smrg    unsigned int srcWidth, srcHeight;
87f29dbc25Smrg    PixmapPtr srcPixmap;
88f29dbc25Smrg
89f29dbc25Smrg    unsigned int srcColor;
90f29dbc25Smrg    int op;
91f29dbc25Smrg    int repeat;
92170d5fdcSmrg    int maskrepeat;
93f29dbc25Smrg    unsigned int fourBpp;
94f29dbc25Smrg    unsigned int bufferOffset;
95f29dbc25Smrg    struct exa_format_t *srcFormat;
96f29dbc25Smrg    struct exa_format_t *dstFormat;
97f29dbc25Smrg
98f29dbc25Smrg    int rotate;
99f29dbc25Smrg    PictTransform *transform;
100f29dbc25Smrg
101f29dbc25Smrg} exaScratch;
102f29dbc25Smrg
103f29dbc25Smrgstatic const int SDfn[16] = {
104f29dbc25Smrg    0x00, 0x88, 0x44, 0xCC, 0x22, 0xAA, 0x66, 0xEE,
105f29dbc25Smrg    0x11, 0x99, 0x55, 0xDD, 0x33, 0xBB, 0x77, 0xFF
106f29dbc25Smrg};
107f29dbc25Smrg
108f29dbc25Smrgstatic const int SDfn_PM[16] = {
109f29dbc25Smrg    0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
110f29dbc25Smrg    0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA
111f29dbc25Smrg};
112f29dbc25Smrg
113f29dbc25Smrg/* These functions check to see if we can safely prefetch the memory
114f29dbc25Smrg * for the blt, or if we have to wait the previous blt to complete.
115f29dbc25Smrg * One function is for the fill, and the other is for the copy because
116f29dbc25Smrg * they have different requirements based on ROP
117f29dbc25Smrg */
118f29dbc25Smrg
119f29dbc25Smrgstatic int lx0 = -1, ly0 = -1, lx1 = -1, ly1 = -1;
120f29dbc25Smrg
121f29dbc25Smrgstatic int
122f29dbc25Smrglx_fill_flags(int x0, int y0, int w, int h, int rop)
123f29dbc25Smrg{
124f29dbc25Smrg    int x1 = x0 + w, y1 = y0 + h;
125f29dbc25Smrg    int n = ((rop ^ (rop >> 1)) & 0x55) == 0 ||	/* no dst */
126f29dbc25Smrg	x0 >= lx1 || y0 >= ly1 ||      /* rght/below */
127f29dbc25Smrg	x1 <= lx0 || y1 <= ly0 ?       /* left/above */
128f29dbc25Smrg	0 : CIMGP_BLTFLAGS_HAZARD;
129f29dbc25Smrg
130f29dbc25Smrg    lx0 = x0;
131f29dbc25Smrg    ly0 = y0;
132f29dbc25Smrg    lx1 = x1;
133f29dbc25Smrg    ly1 = y1;
134f29dbc25Smrg
135f29dbc25Smrg    return n;
136f29dbc25Smrg}
137f29dbc25Smrg
138f29dbc25Smrgstatic int
139f29dbc25Smrglx_copy_flags(int x0, int y0, int x1, int y1, int w, int h, int rop)
140f29dbc25Smrg{
141f29dbc25Smrg    int x2 = x1 + w, y2 = y1 + h;
142f29dbc25Smrg
143f29dbc25Smrg    /* dst not hazzard and src not hazzard */
144f29dbc25Smrg    int n = (((rop ^ (rop >> 1)) & 0x55) == 0 ||
145f29dbc25Smrg	x1 >= lx1 || y1 >= ly1 ||
146f29dbc25Smrg	x2 <= lx0 || y2 <= ly0) &&
147f29dbc25Smrg	(((rop ^ (rop >> 2)) & 0x33) == 0 ||
148f29dbc25Smrg	x0 >= lx1 || y0 >= ly1 ||
149f29dbc25Smrg	x0 + w <= lx0 || y0 + h <= ly0) ? 0 : CIMGP_BLTFLAGS_HAZARD;
150f29dbc25Smrg
151f29dbc25Smrg    lx0 = x1;
152f29dbc25Smrg    ly0 = y1;
153f29dbc25Smrg    lx1 = x2;
154f29dbc25Smrg    ly1 = y2;
155f29dbc25Smrg
156f29dbc25Smrg    return n;
157f29dbc25Smrg}
158f29dbc25Smrg
159f29dbc25Smrg/* These are borrowed from the exa engine - they should be made global
160f29dbc25Smrg   and available to drivers, but until then....
161f29dbc25Smrg*/
162f29dbc25Smrg
163f29dbc25Smrg/* exaGetPixelFromRGBA (exa_render.c) */
164f29dbc25Smrg
165f29dbc25Smrgstatic Bool
166f29dbc25Smrg_GetPixelFromRGBA(CARD32 * pixel,
167f29dbc25Smrg    CARD16 red, CARD16 green, CARD16 blue, CARD16 alpha, CARD32 format)
168f29dbc25Smrg{
169f29dbc25Smrg    int rbits, bbits, gbits, abits;
170f29dbc25Smrg    int rshift, bshift, gshift, ashift;
171f29dbc25Smrg
172f29dbc25Smrg    *pixel = 0;
173f29dbc25Smrg
174f29dbc25Smrg    if (!PICT_FORMAT_COLOR(format))
175f29dbc25Smrg	return FALSE;
176f29dbc25Smrg
177f29dbc25Smrg    rbits = PICT_FORMAT_R(format);
178f29dbc25Smrg    gbits = PICT_FORMAT_G(format);
179f29dbc25Smrg    bbits = PICT_FORMAT_B(format);
180f29dbc25Smrg    abits = PICT_FORMAT_A(format);
181f29dbc25Smrg
182f29dbc25Smrg    if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
183f29dbc25Smrg	bshift = 0;
184f29dbc25Smrg	gshift = bbits;
185f29dbc25Smrg	rshift = gshift + gbits;
186f29dbc25Smrg	ashift = rshift + rbits;
187f29dbc25Smrg    } else {			       /* PICT_TYPE_ABGR */
188f29dbc25Smrg	rshift = 0;
189f29dbc25Smrg	gshift = rbits;
190f29dbc25Smrg	bshift = gshift + gbits;
191f29dbc25Smrg	ashift = bshift + bbits;
192f29dbc25Smrg    }
193f29dbc25Smrg
194f29dbc25Smrg    *pixel |= (blue >> (16 - bbits)) << bshift;
195f29dbc25Smrg    *pixel |= (red >> (16 - rbits)) << rshift;
196f29dbc25Smrg    *pixel |= (green >> (16 - gbits)) << gshift;
197f29dbc25Smrg    *pixel |= (alpha >> (16 - abits)) << ashift;
198f29dbc25Smrg
199f29dbc25Smrg    return TRUE;
200f29dbc25Smrg}
201f29dbc25Smrg
202f29dbc25Smrg/* exaGetRGBAFromPixel (exa_render.c) */
203f29dbc25Smrg
204f29dbc25Smrgstatic Bool
205f29dbc25Smrg_GetRGBAFromPixel(CARD32 pixel,
206f29dbc25Smrg    CARD16 * red,
207f29dbc25Smrg    CARD16 * green, CARD16 * blue, CARD16 * alpha, CARD32 format)
208f29dbc25Smrg{
209f29dbc25Smrg    int rbits, bbits, gbits, abits;
210f29dbc25Smrg    int rshift, bshift, gshift, ashift;
211f29dbc25Smrg
212f29dbc25Smrg    if (!PICT_FORMAT_COLOR(format))
213f29dbc25Smrg	return FALSE;
214f29dbc25Smrg
215f29dbc25Smrg    rbits = PICT_FORMAT_R(format);
216f29dbc25Smrg    gbits = PICT_FORMAT_G(format);
217f29dbc25Smrg    bbits = PICT_FORMAT_B(format);
218f29dbc25Smrg    abits = PICT_FORMAT_A(format);
219f29dbc25Smrg
220f29dbc25Smrg    if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
221f29dbc25Smrg	bshift = 0;
222f29dbc25Smrg	gshift = bbits;
223f29dbc25Smrg	rshift = gshift + gbits;
224f29dbc25Smrg	ashift = rshift + rbits;
225f29dbc25Smrg    } else {			       /* PICT_TYPE_ABGR */
226f29dbc25Smrg	rshift = 0;
227f29dbc25Smrg	gshift = rbits;
228f29dbc25Smrg	bshift = gshift + gbits;
229f29dbc25Smrg	ashift = bshift + bbits;
230f29dbc25Smrg    }
231f29dbc25Smrg
232f29dbc25Smrg    *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits);
233f29dbc25Smrg    while (rbits < 16) {
234f29dbc25Smrg	*red |= *red >> rbits;
235f29dbc25Smrg	rbits <<= 1;
236f29dbc25Smrg    }
237f29dbc25Smrg
238f29dbc25Smrg    *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits);
239f29dbc25Smrg    while (gbits < 16) {
240f29dbc25Smrg	*green |= *green >> gbits;
241f29dbc25Smrg	gbits <<= 1;
242f29dbc25Smrg    }
243f29dbc25Smrg
244f29dbc25Smrg    *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits);
245f29dbc25Smrg    while (bbits < 16) {
246f29dbc25Smrg	*blue |= *blue >> bbits;
247f29dbc25Smrg	bbits <<= 1;
248f29dbc25Smrg    }
249f29dbc25Smrg
250f29dbc25Smrg    if (abits) {
251f29dbc25Smrg	*alpha = ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits);
252f29dbc25Smrg	while (abits < 16) {
253f29dbc25Smrg	    *alpha |= *alpha >> abits;
254f29dbc25Smrg	    abits <<= 1;
255f29dbc25Smrg	}
256f29dbc25Smrg    } else
257f29dbc25Smrg	*alpha = 0xffff;
258f29dbc25Smrg
259f29dbc25Smrg    return TRUE;
260f29dbc25Smrg}
261f29dbc25Smrg
262f29dbc25Smrgstatic unsigned int
263f29dbc25Smrglx_get_source_color(PixmapPtr pSrc, int srcFormat, int dstFormat)
264f29dbc25Smrg{
265f29dbc25Smrg    CARD32 in, out;
266f29dbc25Smrg    CARD16 red = 0, green = 0, blue = 0, alpha = 0;
267f29dbc25Smrg
268f29dbc25Smrg    /* Stall to avoid a race with the upload function */
269f29dbc25Smrg    /* for 1.4 and newer, the problem will be resolved within
270f29dbc25Smrg     * exaGetPixmapFirstPixel, so this should be adjusted so
271f29dbc25Smrg     * the stall isn't run needlessly
272f29dbc25Smrg     */
273f29dbc25Smrg
274f29dbc25Smrg    gp_wait_until_idle();
275f29dbc25Smrg    in = exaGetPixmapFirstPixel(pSrc);
276f29dbc25Smrg
277f29dbc25Smrg    _GetRGBAFromPixel(in, &red, &blue, &green, &alpha, srcFormat);
278f29dbc25Smrg    _GetPixelFromRGBA(&out, red, blue, green, alpha, dstFormat);
279f29dbc25Smrg
280f29dbc25Smrg    return out;
281f29dbc25Smrg}
282f29dbc25Smrg
283f29dbc25Smrgstatic Bool
284f29dbc25Smrglx_prepare_solid(PixmapPtr pxMap, int alu, Pixel planemask, Pixel fg)
285f29dbc25Smrg{
286f29dbc25Smrg    int pitch = exaGetPixmapPitch(pxMap);
287f29dbc25Smrg    int op = (planemask == ~0U) ? SDfn[alu] : SDfn_PM[alu];
288f29dbc25Smrg
289f29dbc25Smrg    gp_declare_blt(0);
290f29dbc25Smrg    gp_set_bpp(pxMap->drawable.bitsPerPixel);
291f29dbc25Smrg
292f29dbc25Smrg    gp_set_raster_operation(op);
293f29dbc25Smrg
294f29dbc25Smrg    if (planemask != ~0U)
295f29dbc25Smrg	gp_set_solid_pattern(planemask);
296f29dbc25Smrg
297f29dbc25Smrg    exaScratch.op = op;
298f29dbc25Smrg
299f29dbc25Smrg    gp_set_solid_source(fg);
300f29dbc25Smrg
301f29dbc25Smrg    gp_set_strides(pitch, pitch);
302f29dbc25Smrg    gp_write_parameters();
303f29dbc25Smrg    return TRUE;
304f29dbc25Smrg}
305f29dbc25Smrg
306f29dbc25Smrgstatic void
307f29dbc25Smrglx_do_solid(PixmapPtr pxMap, int x1, int y1, int x2, int y2)
308f29dbc25Smrg{
309f29dbc25Smrg    int bpp = (pxMap->drawable.bitsPerPixel + 7) / 8;
310f29dbc25Smrg    int pitch = exaGetPixmapPitch(pxMap);
311f29dbc25Smrg    unsigned int offset =
312f29dbc25Smrg	exaGetPixmapOffset(pxMap) + (pitch * y1) + (bpp * x1);
313f29dbc25Smrg
314f29dbc25Smrg    gp_declare_blt(lx_fill_flags(x1, y1, x2 - x1, y2 - y1, exaScratch.op));
315f29dbc25Smrg    gp_pattern_fill(offset, x2 - x1, y2 - y1);
316f29dbc25Smrg}
317f29dbc25Smrg
318f29dbc25Smrgstatic Bool
319f29dbc25Smrglx_prepare_copy(PixmapPtr pxSrc, PixmapPtr pxDst, int dx, int dy,
320f29dbc25Smrg    int alu, Pixel planemask)
321f29dbc25Smrg{
322f29dbc25Smrg    int dpitch = exaGetPixmapPitch(pxDst);
323f29dbc25Smrg    int op = (planemask == ~0U) ? SDfn[alu] : SDfn_PM[alu];
324f29dbc25Smrg
325f29dbc25Smrg    gp_declare_blt(0);
326f29dbc25Smrg    gp_set_bpp(pxDst->drawable.bitsPerPixel);
327f29dbc25Smrg
328f29dbc25Smrg    gp_set_raster_operation(op);
329f29dbc25Smrg
330f29dbc25Smrg    if (planemask != ~0U)
331f29dbc25Smrg	gp_set_solid_pattern(planemask);
332f29dbc25Smrg
333f29dbc25Smrg    exaScratch.srcOffset = exaGetPixmapOffset(pxSrc);
334f29dbc25Smrg    exaScratch.srcPitch = exaGetPixmapPitch(pxSrc);
335f29dbc25Smrg    exaScratch.srcBpp = (pxSrc->drawable.bitsPerPixel + 7) / 8;
336f29dbc25Smrg
337f29dbc25Smrg    exaScratch.op = op;
338f29dbc25Smrg
339f29dbc25Smrg    gp_set_strides(dpitch, exaScratch.srcPitch);
340f29dbc25Smrg    gp_write_parameters();
341f29dbc25Smrg    return TRUE;
342f29dbc25Smrg}
343f29dbc25Smrg
344f29dbc25Smrgstatic void
345f29dbc25Smrglx_do_copy(PixmapPtr pxDst, int srcX, int srcY,
346f29dbc25Smrg    int dstX, int dstY, int w, int h)
347f29dbc25Smrg{
348f29dbc25Smrg    int dstBpp = (pxDst->drawable.bitsPerPixel + 7) / 8;
349f29dbc25Smrg    int dstPitch = exaGetPixmapPitch(pxDst);
350f29dbc25Smrg    unsigned int srcOffset, dstOffset;
351f29dbc25Smrg    int flags = 0;
352f29dbc25Smrg
353f29dbc25Smrg    gp_declare_blt(lx_copy_flags(srcX, srcY, dstX, dstY, w, h,
354f29dbc25Smrg	    exaScratch.op));
355f29dbc25Smrg
356f29dbc25Smrg    srcOffset = exaScratch.srcOffset + (exaScratch.srcPitch * srcY) +
357f29dbc25Smrg	(exaScratch.srcBpp) * srcX;
358f29dbc25Smrg
359f29dbc25Smrg    dstOffset = exaGetPixmapOffset(pxDst) +
360f29dbc25Smrg	(dstPitch * dstY) + (dstBpp * dstX);
361f29dbc25Smrg
362f29dbc25Smrg    if (dstX > srcX)
363f29dbc25Smrg	flags |= CIMGP_NEGXDIR;
364f29dbc25Smrg
365f29dbc25Smrg    if (dstY > srcY)
366f29dbc25Smrg	flags |= CIMGP_NEGYDIR;
367f29dbc25Smrg
368f29dbc25Smrg    gp_screen_to_screen_blt(dstOffset, srcOffset, w, h, flags);
369f29dbc25Smrg}
370f29dbc25Smrg
371f29dbc25Smrg/* Composite operations
372f29dbc25Smrg
373f29dbc25SmrgThese are the simplest - one pass operations - if there is no format or
374f29dbc25Smrgmask, the we can make these happen pretty fast
375f29dbc25Smrg
376f29dbc25Smrg                       Operation  Type  Channel   Alpha
377f29dbc25SmrgPictOpClear            0          2     0         3
378f29dbc25SmrgPictOpSrc              0          3     0         3
379f29dbc25SmrgPictOpDst              0          3     1         3
380f29dbc25SmrgPictOpOver             2          0     0         3
381f29dbc25SmrgPictOpOverReverse      2          0     1         3
382f29dbc25SmrgPictOpIn               0          1     0         3
383f29dbc25SmrgPictOpInReverse        0          1     1         3
384f29dbc25SmrgPictOpOut              1          0     0         3
385f29dbc25SmrgPictOpOutReverse       1          0     1         3
386f29dbc25SmrgPictOpAdd              2          2     0         3
387f29dbc25Smrg
388f29dbc25SmrgThe following require multiple passes
389f29dbc25SmrgPictOpAtop
390f29dbc25SmrgPictOpXor
391f29dbc25Smrg*/
392f29dbc25Smrg
393f29dbc25Smrgstruct blend_ops_t
394f29dbc25Smrg{
395f29dbc25Smrg    int operation;
396f29dbc25Smrg    int type;
397f29dbc25Smrg    int channel;
398f29dbc25Smrg} lx_alpha_ops[] = {
399f29dbc25Smrg    /* PictOpClear */
400f29dbc25Smrg    {
401f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONSTANT_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
402f29dbc25Smrg    },
403f29dbc25Smrg	/* PictOpSrc */
404f29dbc25Smrg    {
405f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_ALPHA_EQUALS_ONE, CIMGP_CHANNEL_A_SOURCE}, {
406f29dbc25Smrg    },
407f29dbc25Smrg	/* PictOpDst */
408f29dbc25Smrg    {
409f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_ALPHA_EQUALS_ONE, CIMGP_CHANNEL_A_DEST}, {
410f29dbc25Smrg    },
411f29dbc25Smrg	/* PictOpOver */
412f29dbc25Smrg    {
413170d5fdcSmrg    CIMGP_A_PLUS_BETA_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
414170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
415f29dbc25Smrg	/* PictOpOverReverse */
416f29dbc25Smrg    {
417170d5fdcSmrg    CIMGP_A_PLUS_BETA_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST}, {
418170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
419f29dbc25Smrg	/* PictOpIn */
420f29dbc25Smrg    {
421f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
422170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
423f29dbc25Smrg	/* PictOpInReverse */
424f29dbc25Smrg    {
425f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_DEST}, {
426170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
427f29dbc25Smrg	/* PictOpOut */
428f29dbc25Smrg    {
429170d5fdcSmrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST}, {
430170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
431f29dbc25Smrg	/* PictOpOutReverse */
432f29dbc25Smrg    {
433170d5fdcSmrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
434170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
435f29dbc25Smrg	/* SrcAtop */
436f29dbc25Smrg    {
437f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_DEST}, {
438f29dbc25Smrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE},
439f29dbc25Smrg	/* SrcAtopReverse */
440f29dbc25Smrg    {
441f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
442f29dbc25Smrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST},
443f29dbc25Smrg	/* Xor */
444f29dbc25Smrg    {
445f29dbc25Smrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
446f29dbc25Smrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE},
447f29dbc25Smrg	/* PictOpAdd */
448f29dbc25Smrg    {
449f29dbc25Smrg    CIMGP_A_PLUS_BETA_B, CIMGP_CONSTANT_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
450f29dbc25Smrg    }
451f29dbc25Smrg};
452f29dbc25Smrg
453f29dbc25Smrg#define ARRAY_SIZE(a) (sizeof((a)) / (sizeof(*(a))))
454f29dbc25Smrg
455f29dbc25Smrgstatic const struct exa_format_t *
456f29dbc25Smrglx_get_format(PicturePtr p)
457f29dbc25Smrg{
458f29dbc25Smrg    int i;
459f29dbc25Smrg    unsigned int format = p->format;
460f29dbc25Smrg
461170d5fdcSmrg    for (i = 0; i < ARRAY_SIZE(lx_exa_formats); i++)
462f29dbc25Smrg	if (lx_exa_formats[i].exa == format)
463f29dbc25Smrg	    return (&lx_exa_formats[i]);
464f29dbc25Smrg
465f29dbc25Smrg    return NULL;
466f29dbc25Smrg}
467f29dbc25Smrg
468f29dbc25Smrgstatic Bool
469f29dbc25Smrglx_process_transform(PicturePtr pSrc)
470f29dbc25Smrg{
471f29dbc25Smrg    PictTransformPtr t = pSrc->transform;
472f29dbc25Smrg    xFixed c0 = t->matrix[0][0];
473f29dbc25Smrg    xFixed s0 = t->matrix[0][1];
474f29dbc25Smrg    xFixed s1 = t->matrix[1][0];
475f29dbc25Smrg    xFixed c1 = t->matrix[1][1];
476f29dbc25Smrg
477f29dbc25Smrg    /* If the transform doesn't have any rotation
478f29dbc25Smrg     * or scaling components, then just grab the
479f29dbc25Smrg     * translate coordinates */
480f29dbc25Smrg
481f29dbc25Smrg    if (t->matrix[0][0] == 0 &&
482f29dbc25Smrg	t->matrix[0][1] == 0 &&
483f29dbc25Smrg	t->matrix[1][0] == 0 && t->matrix[1][1] == 0) {
484f29dbc25Smrg	exaScratch.transform = pSrc->transform;
485f29dbc25Smrg	return TRUE;
486f29dbc25Smrg    }
487f29dbc25Smrg
488f29dbc25Smrg    /* Otherwise, see if this is a simple
489f29dbc25Smrg     * rotate transform - if it isn't, then
490f29dbc25Smrg     * we have to punt back to software */
491f29dbc25Smrg
492f29dbc25Smrg    if (t->matrix[2][2] != F(1))
493f29dbc25Smrg	return FALSE;
494f29dbc25Smrg
495f29dbc25Smrg    /* The rotate matrix looks like this:
496f29dbc25Smrg     * [ cos X   -sin x
497f29dbc25Smrg     * sin X   cos X ]
498f29dbc25Smrg     *
499f29dbc25Smrg     * Where X is the angle.  We do a simple
500f29dbc25Smrg     * check first - if [0,0] != [1,1], then
501f29dbc25Smrg     * scaling was specified too, and we can
502f29dbc25Smrg     * bail, and if [0,1] != -[1,1] then this
503f29dbc25Smrg     * isn't scaling that we can handle.
504f29dbc25Smrg     */
505f29dbc25Smrg
506f29dbc25Smrg    if ((c0 != c1) || (s0 != -s1))
507f29dbc25Smrg	return FALSE;
508f29dbc25Smrg
509f29dbc25Smrg    /* Now, figure out what angle we want - we
510f29dbc25Smrg     * can only accelerate right angle rotations,
511f29dbc25Smrg     * so this turns into an easy set of if statements */
512f29dbc25Smrg
513f29dbc25Smrg    if (c0 == F(1) && s1 == F(0))
514f29dbc25Smrg	exaScratch.rotate = RR_Rotate_0;
515f29dbc25Smrg    else if (c0 == F(0) && s1 == F(1))
516f29dbc25Smrg	exaScratch.rotate = RR_Rotate_90;
517f29dbc25Smrg    else if (c0 == F(-1) && s1 == F(0))
518f29dbc25Smrg	exaScratch.rotate = RR_Rotate_180;
519f29dbc25Smrg    else if (c0 == F(0) && s1 == F(-1))
520f29dbc25Smrg	exaScratch.rotate = RR_Rotate_270;
521f29dbc25Smrg    else
522f29dbc25Smrg	return FALSE;
523f29dbc25Smrg
524f29dbc25Smrg    exaScratch.transform = pSrc->transform;
525f29dbc25Smrg
526f29dbc25Smrg    return TRUE;
527f29dbc25Smrg}
528f29dbc25Smrg
529f29dbc25Smrgstatic Bool
530f29dbc25Smrglx_check_composite(int op, PicturePtr pSrc, PicturePtr pMsk, PicturePtr pDst)
531f29dbc25Smrg{
532f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR_FROM_PICTURE(pDst);
533170d5fdcSmrg    const struct exa_format_t *srcFmt, *dstFmt;
534f29dbc25Smrg
535f29dbc25Smrg    /* Check that the operation is supported */
536f29dbc25Smrg
537f29dbc25Smrg    if (op > PictOpAdd)
538f29dbc25Smrg	return FALSE;
539f29dbc25Smrg
540170d5fdcSmrg    /* FIXME: Meet this conditions from the debug for PictOpAdd.
541170d5fdcSmrg     * Any Other possibilities? Add a judge for the future supplement */
542170d5fdcSmrg    if (op == PictOpAdd && pSrc->format == PICT_a8r8g8b8 &&
543170d5fdcSmrg	pDst->format == PICT_a8 && !pMsk)
544170d5fdcSmrg	return TRUE;
545170d5fdcSmrg
546170d5fdcSmrg    if (op == PictOpAdd && pSrc->format == PICT_x8r8g8b8 &&
547170d5fdcSmrg	pDst->format == PICT_a8 && !pMsk)
548170d5fdcSmrg	return TRUE;
549170d5fdcSmrg
550170d5fdcSmrg    if (op == PictOpAdd && pSrc->format == PICT_r5g6b5 &&
551170d5fdcSmrg	pDst->format == PICT_a8 && !pMsk)
552170d5fdcSmrg	return TRUE;
553170d5fdcSmrg
554170d5fdcSmrg    /* We need the off-screen buffer to do the multipass work */
555170d5fdcSmrg
556f29dbc25Smrg    if (usesPasses(op)) {
557f29dbc25Smrg	if (pGeode->exaBfrOffset == 0 || !pMsk)
558f29dbc25Smrg	    return FALSE;
559f29dbc25Smrg    }
560f29dbc25Smrg
561f29dbc25Smrg    if (pMsk && op == PictOpAdd)
562f29dbc25Smrg	return FALSE;
563f29dbc25Smrg
564f29dbc25Smrg    /* Check that the filter matches what we support */
565f29dbc25Smrg
566f29dbc25Smrg    switch (pSrc->filter) {
567f29dbc25Smrg    case PictFilterNearest:
568f29dbc25Smrg    case PictFilterFast:
569f29dbc25Smrg    case PictFilterGood:
570f29dbc25Smrg    case PictFilterBest:
571f29dbc25Smrg	break;
572f29dbc25Smrg
573f29dbc25Smrg    default:
574f29dbc25Smrg	/* WE don't support bilinear or convolution filters */
575f29dbc25Smrg	return FALSE;
576f29dbc25Smrg    }
577f29dbc25Smrg
578f29dbc25Smrg    /* We don't support any mask transforms */
579f29dbc25Smrg    if (pMsk && pMsk->transform)
580f29dbc25Smrg	return FALSE;
581f29dbc25Smrg
582170d5fdcSmrg    /* XXX - don't know if we can do any hwaccel on solid fills or gradient types */
583170d5fdcSmrg    if (pSrc->pSourcePict || (pMsk && pMsk->pSourcePict))
584170d5fdcSmrg	return FALSE;
585170d5fdcSmrg
586f29dbc25Smrg    /* Keep an eye out for source rotation transforms - those we can
587f29dbc25Smrg     * do something about */
588f29dbc25Smrg
589f29dbc25Smrg    exaScratch.rotate = RR_Rotate_0;
590f29dbc25Smrg    exaScratch.transform = NULL;
591f29dbc25Smrg
592f29dbc25Smrg    if (pSrc->transform && !lx_process_transform(pSrc))
593f29dbc25Smrg	return FALSE;
594f29dbc25Smrg
595f29dbc25Smrg    /* XXX - I don't understand PICT_a8 enough - so I'm punting */
596f29dbc25Smrg
597170d5fdcSmrg    if ((op != PictOpAdd) && (pSrc->format == PICT_a8 ||
598170d5fdcSmrg	pDst->format == PICT_a8))
599f29dbc25Smrg	return FALSE;
600f29dbc25Smrg
601f29dbc25Smrg    if (pMsk && op != PictOpClear) {
602170d5fdcSmrg	struct blend_ops_t *opPtr = &lx_alpha_ops[op * 2];
603170d5fdcSmrg	int direction = (opPtr->channel == CIMGP_CHANNEL_A_SOURCE) ? 0 : 1;
604170d5fdcSmrg
605170d5fdcSmrg	/* Direction 0 indicates src->dst, 1 indiates dst->src */
606170d5fdcSmrg	if (((direction == 0) && (pSrc->pDrawable->bitsPerPixel < 16)) ||
607170d5fdcSmrg	    ((direction == 1) && (pDst->pDrawable->bitsPerPixel < 16))) {
608170d5fdcSmrg	    ErrorF("Can't do mask blending with less then 16bpp\n");
609170d5fdcSmrg	    return FALSE;
610170d5fdcSmrg	}
611f29dbc25Smrg	/* We can only do masks with a 8bpp or a 4bpp mask */
612f29dbc25Smrg	if (pMsk->format != PICT_a8 && pMsk->format != PICT_a4)
613f29dbc25Smrg	    return FALSE;
614170d5fdcSmrg	/* The pSrc should be 1x1 pixel if the pMsk is not zero */
615170d5fdcSmrg	if (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1)
616170d5fdcSmrg	    return FALSE;
617170d5fdcSmrg	/* FIXME: In lx_prepare_composite, there are no variables to record the
618170d5fdcSmrg	 * one pixel source's width and height when the mask is not zero.
619170d5fdcSmrg	 * That will lead to bigger region to render instead of one pixel in lx
620170d5fdcSmrg	 * _do_composite, so we should fallback currently to avoid this */
621170d5fdcSmrg	if (!pSrc->repeat)
622170d5fdcSmrg	    return FALSE;
623f29dbc25Smrg    }
624f29dbc25Smrg
625f29dbc25Smrg    /* Get the formats for the source and destination */
626f29dbc25Smrg
627f29dbc25Smrg    if ((srcFmt = lx_get_format(pSrc)) == NULL) {
628f29dbc25Smrg	ErrorF("EXA: Invalid source format %x\n", pSrc->format);
629f29dbc25Smrg	return FALSE;
630f29dbc25Smrg    }
631f29dbc25Smrg
632f29dbc25Smrg    if ((dstFmt = lx_get_format(pDst)) == NULL) {
633f29dbc25Smrg	ErrorF("EXA:  Invalid destination format %x\n", pDst->format);
634f29dbc25Smrg	return FALSE;
635f29dbc25Smrg    }
636f29dbc25Smrg
637f29dbc25Smrg    /* Make sure operations that need alpha bits have them */
638f29dbc25Smrg    /* If a mask is enabled, the alpha will come from there */
639f29dbc25Smrg
640f29dbc25Smrg    if (!pMsk && (!srcFmt->alphabits && usesSrcAlpha(op)))
641f29dbc25Smrg	return FALSE;
642f29dbc25Smrg
643f29dbc25Smrg    if (!pMsk && (!dstFmt->alphabits && usesDstAlpha(op)))
644f29dbc25Smrg	return FALSE;
645f29dbc25Smrg
646f29dbc25Smrg    /* FIXME:  See a way around this! */
647f29dbc25Smrg
648f29dbc25Smrg    if (srcFmt->alphabits == 0 && dstFmt->alphabits != 0)
649f29dbc25Smrg	return FALSE;
650f29dbc25Smrg
651f29dbc25Smrg    /* If this is a rotate operation, then make sure the src and dst
652f29dbc25Smrg     * formats are the same */
653f29dbc25Smrg
654f29dbc25Smrg    if (exaScratch.rotate != RR_Rotate_0 && srcFmt != dstFmt) {
655f29dbc25Smrg	ErrorF("EXA: Can't rotate and convert formats at the same time\n");
656f29dbc25Smrg	return FALSE;
657f29dbc25Smrg    }
658170d5fdcSmrg    return TRUE;
659170d5fdcSmrg}
660170d5fdcSmrg
661170d5fdcSmrgstatic Bool
662170d5fdcSmrglx_prepare_composite(int op, PicturePtr pSrc, PicturePtr pMsk,
663170d5fdcSmrg    PicturePtr pDst, PixmapPtr pxSrc, PixmapPtr pxMsk, PixmapPtr pxDst)
664170d5fdcSmrg{
665170d5fdcSmrg    GeodeRec *pGeode = GEODEPTR_FROM_PIXMAP(pxDst);
666170d5fdcSmrg    const struct exa_format_t *srcFmt, *dstFmt;
667170d5fdcSmrg
668170d5fdcSmrg    /* Get the formats for the source and destination */
669170d5fdcSmrg
670170d5fdcSmrg    srcFmt = lx_get_format(pSrc);
671170d5fdcSmrg    dstFmt = lx_get_format(pDst);
672f29dbc25Smrg
673f29dbc25Smrg    /* Set up the scratch buffer with the information we need */
674f29dbc25Smrg
675f29dbc25Smrg    exaScratch.srcFormat = (struct exa_format_t *)srcFmt;
676f29dbc25Smrg    exaScratch.dstFormat = (struct exa_format_t *)dstFmt;
677f29dbc25Smrg    exaScratch.op = op;
678f29dbc25Smrg    exaScratch.repeat = pSrc->repeat;
679f29dbc25Smrg    exaScratch.bufferOffset = pGeode->exaBfrOffset;
680f29dbc25Smrg
681f29dbc25Smrg    if (pMsk && op != PictOpClear) {
682f29dbc25Smrg	/* Get the source color */
683170d5fdcSmrg	/* If the op is PictOpOver(or PictOpOutReverse, PictOpInReverse,
684170d5fdcSmrg	 * PictOpIn, PictOpOut, PictOpOverReverse), we should get the
685170d5fdcSmrg	 * ARGB32 source format */
686170d5fdcSmrg
687170d5fdcSmrg	if ((op == PictOpOver || op == PictOpOutReverse || op ==
688170d5fdcSmrg	    PictOpInReverse || op == PictOpIn || op == PictOpOut ||
689170d5fdcSmrg	    op == PictOpOverReverse) && (srcFmt->alphabits != 0))
690170d5fdcSmrg	    exaScratch.srcColor = exaGetPixmapFirstPixel(pxSrc);
691170d5fdcSmrg	else if ((op == PictOpOver || op == PictOpOutReverse || op ==
692170d5fdcSmrg	    PictOpInReverse || op == PictOpIn || op == PictOpOut ||
693170d5fdcSmrg	    op == PictOpOverReverse) &&
694170d5fdcSmrg	    (srcFmt->alphabits == 0))
695f29dbc25Smrg	    exaScratch.srcColor = lx_get_source_color(pxSrc, pSrc->format,
696170d5fdcSmrg		PICT_a8r8g8b8);
697f29dbc25Smrg	else
698170d5fdcSmrg	    exaScratch.srcColor = lx_get_source_color(pxSrc, pSrc->format,
699170d5fdcSmrg		pDst->format);
700f29dbc25Smrg
701f29dbc25Smrg	/* Save off the info we need (reuse the source values to save space) */
702f29dbc25Smrg
703f29dbc25Smrg	exaScratch.type = COMP_TYPE_MASK;
704170d5fdcSmrg	exaScratch.maskrepeat = pMsk->repeat;
705f29dbc25Smrg
706f29dbc25Smrg	exaScratch.srcOffset = exaGetPixmapOffset(pxMsk);
707f29dbc25Smrg	exaScratch.srcPitch = exaGetPixmapPitch(pxMsk);
708f29dbc25Smrg	exaScratch.srcBpp = (pxMsk->drawable.bitsPerPixel + 7) / 8;
709f29dbc25Smrg
710f29dbc25Smrg	exaScratch.srcWidth = pMsk->pDrawable->width;
711f29dbc25Smrg	exaScratch.srcHeight = pMsk->pDrawable->height;
712f29dbc25Smrg
713f29dbc25Smrg	/* Flag to indicate if this a 8BPP or a 4BPP mask */
714f29dbc25Smrg	exaScratch.fourBpp = (pxMsk->drawable.bitsPerPixel == 4) ? 1 : 0;
715f29dbc25Smrg    } else {
716f29dbc25Smrg	if (usesPasses(op))
717f29dbc25Smrg	    exaScratch.type = COMP_TYPE_TWOPASS;
718f29dbc25Smrg	else if (exaScratch.rotate != RR_Rotate_0)
719f29dbc25Smrg	    exaScratch.type = COMP_TYPE_ROTATE;
720f29dbc25Smrg	else
721f29dbc25Smrg	    exaScratch.type = COMP_TYPE_ONEPASS;
722f29dbc25Smrg
723f29dbc25Smrg	exaScratch.srcOffset = exaGetPixmapOffset(pxSrc);
724f29dbc25Smrg	exaScratch.srcPitch = exaGetPixmapPitch(pxSrc);
725f29dbc25Smrg	exaScratch.srcBpp = (pxSrc->drawable.bitsPerPixel + 7) / 8;
726f29dbc25Smrg
727f29dbc25Smrg	exaScratch.srcWidth = pSrc->pDrawable->width;
728f29dbc25Smrg	exaScratch.srcHeight = pSrc->pDrawable->height;
729f29dbc25Smrg    }
730f29dbc25Smrg
731f29dbc25Smrg    return TRUE;
732f29dbc25Smrg}
733f29dbc25Smrg
734f29dbc25Smrgstatic int
735f29dbc25Smrglx_get_bpp_from_format(int format)
736f29dbc25Smrg{
737f29dbc25Smrg
738f29dbc25Smrg    switch (format) {
739f29dbc25Smrg    case CIMGP_SOURCE_FMT_8_8_8_8:
740f29dbc25Smrg    case CIMGP_SOURCE_FMT_32BPP_BGR:
741f29dbc25Smrg	return 32;
742f29dbc25Smrg
743f29dbc25Smrg    case CIMGP_SOURCE_FMT_4_4_4_4:
744f29dbc25Smrg	return 12;
745f29dbc25Smrg
746f29dbc25Smrg    case CIMGP_SOURCE_FMT_0_5_6_5:
747f29dbc25Smrg    case CIMGP_SOURCE_FMT_16BPP_BGR:
748f29dbc25Smrg	return 16;
749f29dbc25Smrg
750f29dbc25Smrg    case CIMGP_SOURCE_FMT_1_5_5_5:
751f29dbc25Smrg    case CIMGP_SOURCE_FMT_15BPP_BGR:
752f29dbc25Smrg	return 15;
753f29dbc25Smrg
754f29dbc25Smrg    case CIMGP_SOURCE_FMT_3_3_2:
755f29dbc25Smrg	return 8;
756f29dbc25Smrg    }
757f29dbc25Smrg
758f29dbc25Smrg    return 0;
759f29dbc25Smrg}
760f29dbc25Smrg
761f29dbc25Smrg/* BGR needs to be set in the source for it to take - so adjust the source
762f29dbc25Smrg * to enable BGR if the two formats are different, and disable it if they
763f29dbc25Smrg * are the same
764f29dbc25Smrg */
765f29dbc25Smrg
766f29dbc25Smrgstatic void
767f29dbc25Smrglx_set_source_format(int srcFormat, int dstFormat)
768f29dbc25Smrg{
769f29dbc25Smrg    if (!(srcFormat & 0x10) && (dstFormat & 0x10))
770f29dbc25Smrg	gp_set_source_format(srcFormat | 0x10);
771f29dbc25Smrg    else if ((srcFormat & 0x10) && (dstFormat & 0x10))
772f29dbc25Smrg	gp_set_source_format(srcFormat & ~0x10);
773f29dbc25Smrg    else
774f29dbc25Smrg	gp_set_source_format(srcFormat);
775f29dbc25Smrg}
776f29dbc25Smrg
777f29dbc25Smrg/* If we are converting colors and we need the channel A alpha,
778f29dbc25Smrg * then use a special alpha type that preserves the alpha before
779f29dbc25Smrg * converting the format
780f29dbc25Smrg */
781f29dbc25Smrg
782f29dbc25Smrgstatic inline int
783f29dbc25Smrgget_op_type(struct exa_format_t *src, struct exa_format_t *dst, int type)
784f29dbc25Smrg{
785f29dbc25Smrg    return (type == CIMGP_CHANNEL_A_ALPHA &&
786f29dbc25Smrg	src->alphabits != dst->alphabits) ? CIMGP_CONVERTED_ALPHA : type;
787f29dbc25Smrg}
788f29dbc25Smrg
789f29dbc25Smrg/* Note - this is the preferred onepass method.  The other will remain
790f29dbc25Smrg * ifdefed out until such time that we are sure its not needed
791f29dbc25Smrg */
792f29dbc25Smrg
793170d5fdcSmrg#define GetPixmapOffset(px, x, y) ( exaGetPixmapOffset((px)) + \
794170d5fdcSmrg  (exaGetPixmapPitch((px)) * (y)) + \
795170d5fdcSmrg  ((((px)->drawable.bitsPerPixel + 7) / 8) * (x)) )
796170d5fdcSmrg
797170d5fdcSmrg#define GetSrcOffset(_x, _y) (exaScratch.srcOffset + ((_y) * exaScratch.srcPitch) + \
798170d5fdcSmrg			      ((_x) * exaScratch.srcBpp))
799170d5fdcSmrg
800170d5fdcSmrgstatic void
801170d5fdcSmrglx_composite_onepass_add_a8(PixmapPtr pxDst, unsigned long dstOffset,
802170d5fdcSmrg    unsigned long srcOffset, int width, int height, int opX, int opY,
803170d5fdcSmrg    int srcX, int srcY)
804170d5fdcSmrg{
805170d5fdcSmrg    struct blend_ops_t *opPtr;
806170d5fdcSmrg    int apply, type;
807170d5fdcSmrg    int optempX, optempY;
808170d5fdcSmrg    int i, j;
809170d5fdcSmrg    unsigned long pixmapOffset, pixmapPitch, calBitsPixel;
810170d5fdcSmrg
811170d5fdcSmrg    pixmapOffset = exaGetPixmapOffset(pxDst);
812170d5fdcSmrg    pixmapPitch = exaGetPixmapPitch(pxDst);
813170d5fdcSmrg    calBitsPixel = (pxDst->drawable.bitsPerPixel + 7) / 8;
814170d5fdcSmrg
815170d5fdcSmrg    /* Keep this GP idle judge here. Otherwise the SW method has chance to
816170d5fdcSmrg     * conflict with the HW rendering method */
817170d5fdcSmrg    gp_wait_until_idle();
818170d5fdcSmrg
819170d5fdcSmrg    if (opX % 4 == 0 && srcX % 4 == 0) {
820170d5fdcSmrg	/* HW acceleration */
821170d5fdcSmrg	opPtr = &lx_alpha_ops[exaScratch.op * 2];
822170d5fdcSmrg	apply = CIMGP_APPLY_BLEND_TO_ALL;
823170d5fdcSmrg	gp_declare_blt(0);
824170d5fdcSmrg	gp_set_bpp(32);
825170d5fdcSmrg	gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
826170d5fdcSmrg	gp_set_source_format(8);
827170d5fdcSmrg	type = opPtr->type;
828170d5fdcSmrg	gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0);
829170d5fdcSmrg	gp_screen_to_screen_convert(dstOffset, srcOffset, width / 4, height, 0);
830170d5fdcSmrg	/* Calculate the pixels in the tail of each line */
831170d5fdcSmrg	for (j = srcY; j < srcY + height; j++)
832170d5fdcSmrg	    for (i = srcX + (width / 4) * 4; i < srcX + width; i++) {
833170d5fdcSmrg		srcOffset = GetSrcOffset(i, j);
834170d5fdcSmrg		optempX = opX + i - srcX;
835170d5fdcSmrg		optempY = opY + j - srcY;
836170d5fdcSmrg		dstOffset = pixmapOffset + pixmapPitch * optempY +
837170d5fdcSmrg		    calBitsPixel * optempX;
838170d5fdcSmrg		*(cim_fb_ptr + dstOffset) = (*(cim_fb_ptr + srcOffset)
839170d5fdcSmrg		    + *(cim_fb_ptr + dstOffset) <= 0xff) ?
840170d5fdcSmrg		    *(cim_fb_ptr + srcOffset) + *(cim_fb_ptr + dstOffset) : 0xff;
841170d5fdcSmrg	}
842170d5fdcSmrg    } else {
843170d5fdcSmrg	for (j = srcY; j < srcY + height; j++)
844170d5fdcSmrg	    for (i = srcX; i < srcX + width; i++) {
845170d5fdcSmrg		srcOffset = GetSrcOffset(i, j);
846170d5fdcSmrg		optempX = opX + i - srcX;
847170d5fdcSmrg		optempY = opY + j - srcY;
848170d5fdcSmrg		dstOffset = pixmapOffset + pixmapPitch * optempY +
849170d5fdcSmrg		    calBitsPixel * optempX;
850170d5fdcSmrg		*(cim_fb_ptr + dstOffset) = (*(cim_fb_ptr + srcOffset) +
851170d5fdcSmrg		    *(cim_fb_ptr + dstOffset) <= 0xff) ?
852170d5fdcSmrg		    *(cim_fb_ptr + srcOffset) + *(cim_fb_ptr + dstOffset) : 0xff;
853170d5fdcSmrg	}
854170d5fdcSmrg    }
855170d5fdcSmrg}
856170d5fdcSmrg
857f29dbc25Smrgstatic void
858f29dbc25Smrglx_composite_onepass(PixmapPtr pxDst, unsigned long dstOffset,
859f29dbc25Smrg    unsigned long srcOffset, int width, int height)
860f29dbc25Smrg{
861f29dbc25Smrg    struct blend_ops_t *opPtr;
862f29dbc25Smrg    int apply, type;
863f29dbc25Smrg
864f29dbc25Smrg    opPtr = &lx_alpha_ops[exaScratch.op * 2];
865f29dbc25Smrg
866f29dbc25Smrg    apply = (exaScratch.dstFormat->alphabits != 0 &&
867f29dbc25Smrg	exaScratch.srcFormat->alphabits != 0) ?
868f29dbc25Smrg	CIMGP_APPLY_BLEND_TO_ALL : CIMGP_APPLY_BLEND_TO_RGB;
869f29dbc25Smrg
870f29dbc25Smrg    gp_declare_blt(0);
871f29dbc25Smrg    gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
872f29dbc25Smrg    gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
873f29dbc25Smrg
874f29dbc25Smrg    lx_set_source_format(exaScratch.srcFormat->fmt,
875f29dbc25Smrg	exaScratch.dstFormat->fmt);
876f29dbc25Smrg
877f29dbc25Smrg    type =
878f29dbc25Smrg	get_op_type(exaScratch.srcFormat, exaScratch.dstFormat, opPtr->type);
879f29dbc25Smrg
880f29dbc25Smrg    gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0);
881f29dbc25Smrg
882f29dbc25Smrg    gp_screen_to_screen_convert(dstOffset, srcOffset, width, height, 0);
883f29dbc25Smrg}
884f29dbc25Smrg
885170d5fdcSmrgstatic void
886170d5fdcSmrglx_composite_all_black(unsigned long srcOffset, int width, int height)
887170d5fdcSmrg{
888170d5fdcSmrg    struct blend_ops_t *opPtr;
889170d5fdcSmrg    int apply, type;
890170d5fdcSmrg
891170d5fdcSmrg    opPtr = &lx_alpha_ops[0];
892170d5fdcSmrg    apply = (exaScratch.srcFormat->alphabits != 0) ?
893170d5fdcSmrg	CIMGP_APPLY_BLEND_TO_ALL : CIMGP_APPLY_BLEND_TO_RGB;
894170d5fdcSmrg    gp_declare_blt(0);
895170d5fdcSmrg    gp_set_bpp(lx_get_bpp_from_format(exaScratch.srcFormat->fmt));
896170d5fdcSmrg    gp_set_strides(exaScratch.srcPitch, exaScratch.srcPitch);
897170d5fdcSmrg    lx_set_source_format(exaScratch.srcFormat->fmt,
898170d5fdcSmrg	exaScratch.srcFormat->fmt);
899170d5fdcSmrg    type =
900170d5fdcSmrg	get_op_type(exaScratch.srcFormat, exaScratch.srcFormat, opPtr->type);
901170d5fdcSmrg    gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0);
902170d5fdcSmrg    gp_screen_to_screen_convert(srcOffset, srcOffset, width, height, 0);
903170d5fdcSmrg
904170d5fdcSmrg}
905170d5fdcSmrg
906170d5fdcSmrgstatic void
907170d5fdcSmrglx_composite_onepass_special(PixmapPtr pxDst, int width, int height, int opX,
908170d5fdcSmrg    int opY, int srcX, int srcY)
909170d5fdcSmrg{
910170d5fdcSmrg    struct blend_ops_t *opPtr;
911170d5fdcSmrg    int apply, type;
912170d5fdcSmrg    int opWidth, opHeight;
913170d5fdcSmrg    int optempX, optempY;
914170d5fdcSmrg    unsigned int dstOffset, srcOffset = 0;
915170d5fdcSmrg
916170d5fdcSmrg    optempX = opX;
917170d5fdcSmrg    optempY = opY;
918170d5fdcSmrg
919170d5fdcSmrg    /* Make sure srcX and srcY are in source region */
920170d5fdcSmrg    srcX = ((srcX % (int)exaScratch.srcWidth) + (int)exaScratch.srcWidth)
921170d5fdcSmrg	% (int)exaScratch.srcWidth;
922170d5fdcSmrg    srcY = ((srcY % (int)exaScratch.srcHeight) + (int)exaScratch.srcHeight)
923170d5fdcSmrg	% (int)exaScratch.srcHeight;
924170d5fdcSmrg
925170d5fdcSmrg    opWidth = exaScratch.srcWidth - srcX;
926170d5fdcSmrg    opHeight = exaScratch.srcHeight -  srcY;
927170d5fdcSmrg
928170d5fdcSmrg    srcOffset = GetSrcOffset(srcX, srcY);
929170d5fdcSmrg
930170d5fdcSmrg    if (width < opWidth)
931170d5fdcSmrg	opWidth = width;
932170d5fdcSmrg    if (height < opHeight)
933170d5fdcSmrg	opHeight = height;
934170d5fdcSmrg
935170d5fdcSmrg    while (1) {
936170d5fdcSmrg	gp_wait_until_idle();
937170d5fdcSmrg	dstOffset = GetPixmapOffset(pxDst, optempX, optempY);
938170d5fdcSmrg	opPtr = &lx_alpha_ops[exaScratch.op * 2];
939170d5fdcSmrg	apply = (exaScratch.dstFormat->alphabits != 0 &&
940170d5fdcSmrg	    exaScratch.srcFormat->alphabits != 0) ?
941170d5fdcSmrg	    CIMGP_APPLY_BLEND_TO_ALL : CIMGP_APPLY_BLEND_TO_RGB;
942170d5fdcSmrg	gp_declare_blt(0);
943170d5fdcSmrg	gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
944170d5fdcSmrg	gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
945170d5fdcSmrg	lx_set_source_format(exaScratch.srcFormat->fmt,
946170d5fdcSmrg	    exaScratch.dstFormat->fmt);
947170d5fdcSmrg	type = get_op_type(exaScratch.srcFormat, exaScratch.dstFormat,
948170d5fdcSmrg	    opPtr->type);
949170d5fdcSmrg	gp_set_alpha_operation(opPtr->operation, type, opPtr->channel,
950170d5fdcSmrg	    apply, 0);
951170d5fdcSmrg	gp_screen_to_screen_convert(dstOffset, srcOffset, opWidth, opHeight, 0);
952170d5fdcSmrg
953170d5fdcSmrg	optempX += opWidth;
954170d5fdcSmrg	if (optempX >= opX + width) {
955170d5fdcSmrg	    optempX = opX;
956170d5fdcSmrg	    optempY += opHeight;
957170d5fdcSmrg	    if (optempY >= opY + height)
958170d5fdcSmrg		break;
959170d5fdcSmrg	}
960170d5fdcSmrg	if (optempX == opX) {
961170d5fdcSmrg	    srcOffset = GetSrcOffset(srcX, 0);
962170d5fdcSmrg	    opWidth = ((opX + width) - optempX) > (exaScratch.srcWidth - srcX)
963170d5fdcSmrg		? (exaScratch.srcWidth - srcX) : ((opX + width) - optempX);
964170d5fdcSmrg	    opHeight = ((opY + height) - optempY) > exaScratch.srcHeight
965170d5fdcSmrg		? exaScratch.srcHeight : ((opY + height) - optempY);
966170d5fdcSmrg	} else if (optempY == opY) {
967170d5fdcSmrg	    srcOffset = GetSrcOffset(0, srcY);
968170d5fdcSmrg	    opWidth = ((opX + width) - optempX) > exaScratch.srcWidth
969170d5fdcSmrg		? exaScratch.srcWidth : ((opX + width) - optempX);
970170d5fdcSmrg	    opHeight = ((opY + height) - optempY) > (exaScratch.srcHeight -
971170d5fdcSmrg		srcY) ? (exaScratch.srcHeight - srcY) : ((opY + height) - optempY);
972170d5fdcSmrg	} else {
973170d5fdcSmrg	    srcOffset = GetSrcOffset(0, 0);
974170d5fdcSmrg	    opWidth = ((opX + width) - optempX) > exaScratch.srcWidth
975170d5fdcSmrg		? exaScratch.srcWidth : ((opX + width) - optempX);
976170d5fdcSmrg	    opHeight = ((opY + height) - optempY) > exaScratch.srcHeight
977170d5fdcSmrg		? exaScratch.srcHeight : ((opY + height) - optempY);
978170d5fdcSmrg	}
979170d5fdcSmrg    }
980170d5fdcSmrg}
981170d5fdcSmrg
982f29dbc25Smrg/* This function handles the multipass blend functions */
983f29dbc25Smrg
984f29dbc25Smrgstatic void
985f29dbc25Smrglx_composite_multipass(PixmapPtr pxDst, unsigned long dstOffset,
986f29dbc25Smrg    unsigned long srcOffset, int width, int height)
987f29dbc25Smrg{
988f29dbc25Smrg    struct blend_ops_t *opPtr;
989f29dbc25Smrg    int sbpp = lx_get_bpp_from_format(exaScratch.srcFormat->fmt);
990f29dbc25Smrg    int apply, type;
991f29dbc25Smrg
992f29dbc25Smrg    /* Wait until the GP is idle - this will ensure that the scratch buffer
993f29dbc25Smrg     * isn't occupied */
994f29dbc25Smrg
995f29dbc25Smrg    gp_wait_until_idle();
996f29dbc25Smrg
997f29dbc25Smrg    /* Copy the destination to the scratch buffer, and convert it to the
998f29dbc25Smrg     * source format */
999f29dbc25Smrg
1000f29dbc25Smrg    gp_declare_blt(0);
1001f29dbc25Smrg
1002f29dbc25Smrg    gp_set_bpp(sbpp);
1003f29dbc25Smrg    gp_set_source_format(exaScratch.dstFormat->fmt);
1004f29dbc25Smrg    gp_set_raster_operation(0xCC);
1005f29dbc25Smrg    gp_set_strides(exaScratch.srcPitch, exaGetPixmapPitch(pxDst));
1006f29dbc25Smrg    gp_screen_to_screen_convert(exaScratch.bufferOffset, dstOffset,
1007f29dbc25Smrg	width, height, 0);
1008f29dbc25Smrg
1009f29dbc25Smrg    /* Do the first blend from the source to the scratch buffer */
1010f29dbc25Smrg
1011f29dbc25Smrg    gp_declare_blt(CIMGP_BLTFLAGS_HAZARD);
1012f29dbc25Smrg    gp_set_bpp(sbpp);
1013f29dbc25Smrg    gp_set_source_format(exaScratch.srcFormat->fmt);
1014f29dbc25Smrg    gp_set_strides(exaScratch.srcPitch, exaScratch.srcPitch);
1015f29dbc25Smrg
1016f29dbc25Smrg    opPtr = &lx_alpha_ops[exaScratch.op * 2];
1017f29dbc25Smrg
1018f29dbc25Smrg    apply = (exaScratch.srcFormat->alphabits == 0) ?
1019f29dbc25Smrg	CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL;
1020f29dbc25Smrg
1021f29dbc25Smrg    /* If we're destroying the source alpha bits, then make sure we
1022f29dbc25Smrg     * use the alpha before the color conversion
1023f29dbc25Smrg     */
1024f29dbc25Smrg
1025f29dbc25Smrg    gp_screen_to_screen_blt(exaScratch.bufferOffset, srcOffset, width, height,
1026f29dbc25Smrg	0);
1027f29dbc25Smrg
1028f29dbc25Smrg    /* Finally, do the second blend back to the destination */
1029f29dbc25Smrg
1030f29dbc25Smrg    opPtr = &lx_alpha_ops[(exaScratch.op * 2) + 1];
1031f29dbc25Smrg
1032f29dbc25Smrg    apply = (exaScratch.dstFormat->alphabits == 0) ?
1033f29dbc25Smrg	CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL;
1034f29dbc25Smrg
1035f29dbc25Smrg    gp_declare_blt(CIMGP_BLTFLAGS_HAZARD);
1036f29dbc25Smrg    gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
1037f29dbc25Smrg
1038f29dbc25Smrg    lx_set_source_format(exaScratch.srcFormat->fmt,
1039f29dbc25Smrg	exaScratch.dstFormat->fmt);
1040f29dbc25Smrg
1041f29dbc25Smrg    type =
1042f29dbc25Smrg	get_op_type(exaScratch.srcFormat, exaScratch.dstFormat, opPtr->type);
1043f29dbc25Smrg
1044f29dbc25Smrg    gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0);
1045f29dbc25Smrg
1046f29dbc25Smrg    gp_screen_to_screen_convert(dstOffset, exaScratch.bufferOffset,
1047f29dbc25Smrg	width, height, 0);
1048f29dbc25Smrg}
1049f29dbc25Smrg
1050f29dbc25Smrgstatic void
1051f29dbc25Smrglx_composite_rotate(PixmapPtr pxDst, unsigned long dstOffset,
1052f29dbc25Smrg    unsigned int srcOffset, int width, int height)
1053f29dbc25Smrg{
1054f29dbc25Smrg    int degrees = 0;
1055f29dbc25Smrg
1056f29dbc25Smrg    gp_declare_blt(0);
1057f29dbc25Smrg    gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
1058f29dbc25Smrg    gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
1059f29dbc25Smrg
1060f29dbc25Smrg    lx_set_source_format(exaScratch.srcFormat->fmt,
1061f29dbc25Smrg	exaScratch.dstFormat->fmt);
1062f29dbc25Smrg
1063f29dbc25Smrg    gp_set_raster_operation(0xCC);
1064f29dbc25Smrg
1065f29dbc25Smrg    /* RandR rotation is counter-clockwise, our rotation
1066f29dbc25Smrg     * is clockwise, so adjust the numbers accordingly */
1067f29dbc25Smrg
1068f29dbc25Smrg    switch (exaScratch.rotate) {
1069f29dbc25Smrg    case RR_Rotate_90:
1070f29dbc25Smrg	degrees = 270;
1071f29dbc25Smrg	break;
1072f29dbc25Smrg    case RR_Rotate_180:
1073f29dbc25Smrg	degrees = 180;
1074f29dbc25Smrg	break;
1075f29dbc25Smrg    case RR_Rotate_270:
1076f29dbc25Smrg	degrees = 90;
1077f29dbc25Smrg	break;
1078f29dbc25Smrg    }
1079f29dbc25Smrg
1080f29dbc25Smrg    gp_rotate_blt(dstOffset, srcOffset, width, height, degrees);
1081f29dbc25Smrg}
1082f29dbc25Smrg
1083f29dbc25Smrgstatic void
1084f29dbc25Smrglx_do_composite_mask(PixmapPtr pxDst, unsigned long dstOffset,
1085f29dbc25Smrg    unsigned int maskOffset, int width, int height)
1086f29dbc25Smrg{
1087f29dbc25Smrg    struct blend_ops_t *opPtr = &lx_alpha_ops[exaScratch.op * 2];
1088f29dbc25Smrg
1089f29dbc25Smrg    gp_declare_blt(0);
1090f29dbc25Smrg
1091f29dbc25Smrg    gp_set_source_format(exaScratch.srcFormat->fmt);
1092f29dbc25Smrg    gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
1093f29dbc25Smrg    gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
1094f29dbc25Smrg    gp_set_solid_source(exaScratch.srcColor);
1095f29dbc25Smrg
1096f29dbc25Smrg    gp_blend_mask_blt(dstOffset, 0, width, height, maskOffset,
1097f29dbc25Smrg	exaScratch.srcPitch, opPtr->operation, exaScratch.fourBpp);
1098f29dbc25Smrg}
1099f29dbc25Smrg
1100170d5fdcSmrgstatic void
1101170d5fdcSmrglx_do_composite_mask_two_pass(PixmapPtr pxDst, unsigned long dstOffset,
1102170d5fdcSmrg    unsigned int maskOffset, int width, int height, int opX, int opY,
1103170d5fdcSmrg    xPointFixed srcPoint)
1104170d5fdcSmrg{
1105170d5fdcSmrg    int apply, type;
1106170d5fdcSmrg    struct blend_ops_t *opPtr;
1107170d5fdcSmrg    int opWidth, opHeight;
1108170d5fdcSmrg    int opoverX, opoverY;
1109170d5fdcSmrg
1110170d5fdcSmrg    opoverX = opX;
1111170d5fdcSmrg    opoverY = opY;
1112170d5fdcSmrg
1113170d5fdcSmrg    /* The rendering region should not be bigger than off-screen memory size
1114170d5fdcSmrg     * which equals to DEFAULT_EXA_SCRATCH_BFRSZ. If that happens, we split
1115170d5fdcSmrg     * the PictOpOver rendering region into several 256KB chunks. And because
1116170d5fdcSmrg     * of the Pitch(stride) parameter, so we use maximun width of mask picture.
1117170d5fdcSmrg     * that is to say it is a scanline rendering process */
1118170d5fdcSmrg    if (width * height * 4 > DEFAULT_EXA_SCRATCH_BFRSZ) {
1119170d5fdcSmrg	opWidth = width;
1120170d5fdcSmrg	opHeight = DEFAULT_EXA_SCRATCH_BFRSZ / (width * 4);
1121170d5fdcSmrg    } else {
1122170d5fdcSmrg	opWidth = width;
1123170d5fdcSmrg	opHeight = height;
1124170d5fdcSmrg    }
1125f29dbc25Smrg
1126170d5fdcSmrg    while (1) {
1127170d5fdcSmrg
1128170d5fdcSmrg	/* Wait until the GP is idle - this will ensure that the scratch buffer
1129170d5fdcSmrg	 * isn't occupied */
1130170d5fdcSmrg
1131170d5fdcSmrg	gp_wait_until_idle();
1132170d5fdcSmrg
1133170d5fdcSmrg	/* Copy the source to the scratch buffer, and do a src * mask raster
1134170d5fdcSmrg	 * operation */
1135170d5fdcSmrg
1136170d5fdcSmrg	gp_declare_blt(0);
1137170d5fdcSmrg	opPtr = &lx_alpha_ops[(exaScratch.op * 2) + 1];
1138170d5fdcSmrg	gp_set_source_format(CIMGP_SOURCE_FMT_8_8_8_8);
1139170d5fdcSmrg	gp_set_strides(opWidth * 4, exaScratch.srcPitch);
1140170d5fdcSmrg	gp_set_bpp(lx_get_bpp_from_format(CIMGP_SOURCE_FMT_8_8_8_8));
1141170d5fdcSmrg	gp_set_solid_source(exaScratch.srcColor);
1142170d5fdcSmrg	gp_blend_mask_blt(exaScratch.bufferOffset, 0, opWidth, opHeight,
1143170d5fdcSmrg	    maskOffset, exaScratch.srcPitch, opPtr->operation,
1144170d5fdcSmrg	    exaScratch.fourBpp);
1145170d5fdcSmrg
1146170d5fdcSmrg	/* Do a relative operation(refer rendercheck ops.c), and copy the
1147170d5fdcSmrg	 * operation result to destination */
1148170d5fdcSmrg
1149170d5fdcSmrg	gp_declare_blt(CIMGP_BLTFLAGS_HAZARD);
1150170d5fdcSmrg	opPtr = &lx_alpha_ops[exaScratch.op * 2];
1151170d5fdcSmrg	apply = (exaScratch.dstFormat->alphabits == 0) ?
1152170d5fdcSmrg	    CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL;
1153170d5fdcSmrg	gp_set_source_format(CIMGP_SOURCE_FMT_8_8_8_8);
1154170d5fdcSmrg	gp_set_strides(exaGetPixmapPitch(pxDst), opWidth * 4);
1155170d5fdcSmrg	gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
1156170d5fdcSmrg	type = CIMGP_CONVERTED_ALPHA;
1157170d5fdcSmrg	gp_set_alpha_operation(opPtr->operation, type, opPtr->channel,
1158170d5fdcSmrg	    apply, 0);
1159170d5fdcSmrg	gp_screen_to_screen_convert(dstOffset, exaScratch.bufferOffset,
1160170d5fdcSmrg	    opWidth, opHeight, 0);
1161170d5fdcSmrg
1162170d5fdcSmrg	if (width * height * 4 > DEFAULT_EXA_SCRATCH_BFRSZ) {
1163170d5fdcSmrg	    /* Finish the rendering */
1164170d5fdcSmrg	    if (opoverY + opHeight == opY + height)
1165170d5fdcSmrg		break;
1166170d5fdcSmrg	    /* Recalculate the Dest and Mask rendering start point */
1167170d5fdcSmrg	    srcPoint.y = srcPoint.y + F(opHeight);
1168170d5fdcSmrg	    opoverY = opoverY + opHeight;
1169170d5fdcSmrg	    if (opoverY + opHeight > opY + height)
1170170d5fdcSmrg		opHeight = opY + height - opoverY;
1171170d5fdcSmrg	    dstOffset = GetPixmapOffset(pxDst, opoverX, opoverY);
1172170d5fdcSmrg	    maskOffset = GetSrcOffset(I(srcPoint.x), I(srcPoint.y));
1173170d5fdcSmrg	} else
1174170d5fdcSmrg	    break;
1175170d5fdcSmrg    }
1176170d5fdcSmrg}
1177f29dbc25Smrg
1178f29dbc25Smrgstatic void
1179f29dbc25SmrgtransformPoint(PictTransform * t, xPointFixed * point)
1180f29dbc25Smrg{
1181f29dbc25Smrg    PictVector v;
1182f29dbc25Smrg
1183f29dbc25Smrg    v.vector[0] = point->x;
1184f29dbc25Smrg    v.vector[1] = point->y;
1185f29dbc25Smrg    v.vector[2] = xFixed1;
1186f29dbc25Smrg
1187f29dbc25Smrg    if (t != NULL)
1188f29dbc25Smrg	PictureTransformPoint(t, &v);
1189f29dbc25Smrg
1190f29dbc25Smrg    point->x = v.vector[0];
1191f29dbc25Smrg    point->y = v.vector[1];
1192f29dbc25Smrg}
1193f29dbc25Smrg
1194f29dbc25Smrgstatic void
1195f29dbc25Smrglx_do_composite(PixmapPtr pxDst, int srcX, int srcY, int maskX,
1196f29dbc25Smrg    int maskY, int dstX, int dstY, int width, int height)
1197f29dbc25Smrg{
1198f29dbc25Smrg    unsigned int dstOffset, srcOffset = 0;
1199f29dbc25Smrg
1200f29dbc25Smrg    xPointFixed srcPoint;
1201f29dbc25Smrg
1202f29dbc25Smrg    int opX = dstX;
1203f29dbc25Smrg    int opY = dstY;
1204f29dbc25Smrg    int opWidth = width;
1205f29dbc25Smrg    int opHeight = height;
1206f29dbc25Smrg
1207f29dbc25Smrg    /* Transform the source coordinates */
1208f29dbc25Smrg
1209f29dbc25Smrg    if (exaScratch.type == COMP_TYPE_MASK) {
1210f29dbc25Smrg	srcPoint.x = F(maskX);
1211f29dbc25Smrg	srcPoint.y = F(maskY);
1212f29dbc25Smrg    } else {
1213f29dbc25Smrg	srcPoint.x = F(srcX);
1214f29dbc25Smrg	srcPoint.y = F(srcY);
1215f29dbc25Smrg    }
1216f29dbc25Smrg
1217f29dbc25Smrg    /* srcX, srcY point to the upper right side of the bounding box
1218f29dbc25Smrg     * in the unrotated coordinate space.  Depending on the orientation,
1219f29dbc25Smrg     * we have to translate the coordinates to point to the origin of
1220f29dbc25Smrg     * the rectangle in the source pixmap */
1221f29dbc25Smrg
1222f29dbc25Smrg    switch (exaScratch.rotate) {
1223f29dbc25Smrg    case RR_Rotate_270:
1224f29dbc25Smrg	srcPoint.x += F(width);
1225f29dbc25Smrg
1226f29dbc25Smrg	opWidth = height;
1227f29dbc25Smrg	opHeight = width;
1228f29dbc25Smrg	break;
1229f29dbc25Smrg
1230f29dbc25Smrg    case RR_Rotate_180:
1231f29dbc25Smrg	srcPoint.x += F(width);
1232f29dbc25Smrg	srcPoint.y += F(height);
1233f29dbc25Smrg
1234f29dbc25Smrg	srcX += width;
1235f29dbc25Smrg	srcY += height;
1236f29dbc25Smrg	break;
1237f29dbc25Smrg
1238f29dbc25Smrg    case RR_Rotate_90:
1239f29dbc25Smrg	srcPoint.y += F(height);
1240f29dbc25Smrg
1241f29dbc25Smrg	opWidth = height;
1242f29dbc25Smrg	opHeight = width;
1243f29dbc25Smrg	break;
1244f29dbc25Smrg    }
1245f29dbc25Smrg
1246f29dbc25Smrg    transformPoint(exaScratch.transform, &srcPoint);
1247f29dbc25Smrg
1248f29dbc25Smrg    /* Adjust the point to fit into the pixmap */
1249f29dbc25Smrg
1250f29dbc25Smrg    if (I(srcPoint.x) < 0) {
1251f29dbc25Smrg	opWidth += I(srcPoint.x);
1252f29dbc25Smrg	srcPoint.x = F(0);
1253f29dbc25Smrg    }
1254f29dbc25Smrg
1255f29dbc25Smrg    if (I(srcPoint.y) < 0) {
1256f29dbc25Smrg	opHeight += I(srcPoint.y);
1257f29dbc25Smrg	srcPoint.y = F(0);
1258f29dbc25Smrg    }
1259f29dbc25Smrg
1260170d5fdcSmrg    /* Get the source point offset position */
1261170d5fdcSmrg
1262f29dbc25Smrg    srcOffset = GetSrcOffset(I(srcPoint.x), I(srcPoint.y));
1263f29dbc25Smrg
1264170d5fdcSmrg    /* When mask exists, exaScratch.srcWidth and exaScratch.srcHeight are
1265170d5fdcSmrg     * the source width and source height; Otherwise, they are mask width
1266170d5fdcSmrg     * and mask height */
1267170d5fdcSmrg    /* exaScratch.repeat is the source repeat attribute
1268170d5fdcSmrg     * exaScratch.maskrepeat is the mask repeat attribute */
1269170d5fdcSmrg    /* If type is COMP_TYPE_MASK, maskX and maskY are not zero, we should
1270170d5fdcSmrg     * subtract them to do the operation in the correct region */
1271f29dbc25Smrg
1272170d5fdcSmrg    /* FIXME:  Please add the code to handle the condition when the maskX
1273170d5fdcSmrg     * and maskY coordinate are negative or greater than
1274170d5fdcSmrg     * exaScratch.srcWidth and exaScratch.srcHeight */
1275170d5fdcSmrg
1276170d5fdcSmrg    if (exaScratch.type == COMP_TYPE_MASK) {
1277170d5fdcSmrg	if ((exaScratch.srcWidth - maskX) < opWidth)
1278170d5fdcSmrg	    opWidth = exaScratch.srcWidth - maskX;
1279170d5fdcSmrg	if ((exaScratch.srcHeight - maskY) < opHeight)
1280170d5fdcSmrg	    opHeight = exaScratch.srcHeight - maskY;
1281170d5fdcSmrg    } else {
1282170d5fdcSmrg	if (exaScratch.type == COMP_TYPE_ONEPASS) {
1283170d5fdcSmrg	    /* This is the condition srcX or/and srcY is/are out of source
1284170d5fdcSmrg	     * region */
1285170d5fdcSmrg	    if (((srcX >= 0 && srcY >= exaScratch.srcHeight)
1286170d5fdcSmrg		|| (srcX >= exaScratch.srcWidth  && srcY >= 0)) &&
1287170d5fdcSmrg		(exaScratch.op == PictOpOver || exaScratch.op == PictOpSrc)) {
1288170d5fdcSmrg		if (exaScratch.repeat == 1) {
1289170d5fdcSmrg		    opWidth = width;
1290170d5fdcSmrg		    opHeight = height;
1291170d5fdcSmrg		} else {
1292170d5fdcSmrg		    if (exaScratch.op == PictOpOver)
1293170d5fdcSmrg			return ;
1294170d5fdcSmrg		    else {
1295170d5fdcSmrg			exaScratch.op = PictOpClear;
1296170d5fdcSmrg			opWidth = width;
1297170d5fdcSmrg			opHeight = height;
1298170d5fdcSmrg		    }
1299170d5fdcSmrg		}
1300170d5fdcSmrg	    /* This is the condition srcX or/and srcY is/are in the source
1301170d5fdcSmrg	     * region */
1302170d5fdcSmrg	    } else if (srcX >= 0 && srcY >= 0 &&
1303170d5fdcSmrg		(exaScratch.op == PictOpOver || exaScratch.op == PictOpSrc)) {
1304170d5fdcSmrg		if (exaScratch.repeat == 1) {
1305170d5fdcSmrg		    opWidth = width;
1306170d5fdcSmrg		    opHeight = height;
1307170d5fdcSmrg		} else {
1308170d5fdcSmrg		    if ((exaScratch.srcWidth - srcX) < opWidth)
1309170d5fdcSmrg			opWidth = exaScratch.srcWidth - srcX;
1310170d5fdcSmrg		    if ((exaScratch.srcHeight - srcY) < opHeight)
1311170d5fdcSmrg			opHeight = exaScratch.srcHeight - srcY;
1312170d5fdcSmrg		}
1313170d5fdcSmrg	    /* This is the condition srcX or/and srcY is/are negative */
1314170d5fdcSmrg	    } else if ((srcX < 0 || srcY < 0) &&
1315170d5fdcSmrg		(exaScratch.op == PictOpOver || exaScratch.op == PictOpSrc)) {
1316170d5fdcSmrg		if (exaScratch.repeat == 1) {
1317170d5fdcSmrg		    opWidth = width;
1318170d5fdcSmrg		    opHeight = height;
1319170d5fdcSmrg		} else {
1320170d5fdcSmrg		/* Have not met this condition till now */
1321170d5fdcSmrg		    return ;
1322170d5fdcSmrg		}
1323170d5fdcSmrg	    } else {
1324170d5fdcSmrg		if (exaScratch.srcWidth < opWidth)
1325170d5fdcSmrg		    opWidth = exaScratch.srcWidth;
1326170d5fdcSmrg		if (exaScratch.srcHeight < opHeight)
1327170d5fdcSmrg		    opHeight = exaScratch.srcHeight;
1328170d5fdcSmrg	    }
1329170d5fdcSmrg	} else {
1330170d5fdcSmrg	    if (exaScratch.rotate == RR_Rotate_180) {
1331170d5fdcSmrg	    } else {
1332170d5fdcSmrg		if ((exaScratch.srcWidth - srcY) < opWidth)
1333170d5fdcSmrg		    opWidth = exaScratch.srcWidth - srcY;
1334170d5fdcSmrg		if ((exaScratch.srcHeight - srcX) < opHeight)
1335170d5fdcSmrg		    opHeight = exaScratch.srcHeight - srcX;
1336170d5fdcSmrg	    }
1337170d5fdcSmrg	}
1338170d5fdcSmrg    }
1339f29dbc25Smrg
1340f29dbc25Smrg    while (1) {
1341f29dbc25Smrg
1342f29dbc25Smrg	dstOffset = GetPixmapOffset(pxDst, opX, opY);
1343f29dbc25Smrg
1344f29dbc25Smrg	switch (exaScratch.type) {
1345f29dbc25Smrg
1346f29dbc25Smrg	case COMP_TYPE_MASK:{
1347170d5fdcSmrg	    if (exaScratch.op == PictOpOver || exaScratch.op ==
1348170d5fdcSmrg		PictOpOutReverse || exaScratch.op == PictOpInReverse ||
1349170d5fdcSmrg		exaScratch.op == PictOpIn || exaScratch.op == PictOpOut ||
1350170d5fdcSmrg		exaScratch.op == PictOpOverReverse)
1351170d5fdcSmrg		lx_do_composite_mask_two_pass(pxDst, dstOffset,
1352170d5fdcSmrg		    srcOffset, opWidth, opHeight, opX, opY, srcPoint);
1353170d5fdcSmrg	    else
1354170d5fdcSmrg		lx_do_composite_mask(pxDst, dstOffset, srcOffset,
1355170d5fdcSmrg		    opWidth, opHeight);
1356f29dbc25Smrg	    }
1357f29dbc25Smrg	    break;
1358f29dbc25Smrg
1359f29dbc25Smrg	case COMP_TYPE_ONEPASS:
1360170d5fdcSmrg	    if ((exaScratch.op == PictOpOver || exaScratch.op == PictOpSrc)
1361170d5fdcSmrg		&& (exaScratch.repeat == 1)) {
1362170d5fdcSmrg		lx_composite_onepass_special(pxDst, opWidth, opHeight, opX, opY,
1363170d5fdcSmrg		    srcX, srcY);
1364170d5fdcSmrg		return ;
1365170d5fdcSmrg	    } else if ((exaScratch.op == PictOpAdd) && (exaScratch.srcFormat->exa
1366170d5fdcSmrg		== PICT_a8) && (exaScratch.dstFormat->exa == PICT_a8))
1367170d5fdcSmrg		lx_composite_onepass_add_a8(pxDst, dstOffset, srcOffset,
1368170d5fdcSmrg		    opWidth, opHeight, opX, opY, srcX, srcY);
1369170d5fdcSmrg	    else
1370170d5fdcSmrg		lx_composite_onepass(pxDst, dstOffset, srcOffset, opWidth,
1371170d5fdcSmrg		    opHeight);
1372f29dbc25Smrg	    break;
1373f29dbc25Smrg
1374f29dbc25Smrg	case COMP_TYPE_TWOPASS:
1375f29dbc25Smrg	    lx_composite_multipass(pxDst, dstOffset, srcOffset, opWidth,
1376f29dbc25Smrg		opHeight);
1377f29dbc25Smrg
1378f29dbc25Smrg	case COMP_TYPE_ROTATE:
1379f29dbc25Smrg	    lx_composite_rotate(pxDst, dstOffset, srcOffset, opWidth,
1380f29dbc25Smrg		opHeight);
1381f29dbc25Smrg	    break;
1382f29dbc25Smrg	}
1383f29dbc25Smrg
1384f29dbc25Smrg	opX += opWidth;
1385f29dbc25Smrg
1386f29dbc25Smrg	if (opX >= dstX + width) {
1387f29dbc25Smrg	    opX = dstX;
1388f29dbc25Smrg	    opY += opHeight;
1389f29dbc25Smrg
1390f29dbc25Smrg	    if (opY >= dstY + height)
1391f29dbc25Smrg		break;
1392f29dbc25Smrg	}
1393f29dbc25Smrg
1394170d5fdcSmrg	/* FIXME:  Please add the code to handle the condition when the maskX
1395170d5fdcSmrg	 * and maskY coordinate are negative or greater than
1396170d5fdcSmrg	 * exaScratch.srcWidth and exaScratch.srcHeight */
1397170d5fdcSmrg
1398170d5fdcSmrg	if (exaScratch.type == COMP_TYPE_MASK) {
1399170d5fdcSmrg	    opWidth = ((dstX + width) - opX) > (exaScratch.srcWidth - maskX)
1400170d5fdcSmrg		? (exaScratch.srcWidth - maskX) : (dstX + width) - opX;
1401170d5fdcSmrg	    opHeight = ((dstY + height) - opY) > (exaScratch.srcHeight - maskY)
1402170d5fdcSmrg		? (exaScratch.srcHeight - maskY) : (dstY + height) - opY;
1403170d5fdcSmrg	    /* All black out of the mask */
1404170d5fdcSmrg	    if (!exaScratch.maskrepeat)
1405170d5fdcSmrg		exaScratch.srcColor = 0x0;
1406170d5fdcSmrg	} else {
1407170d5fdcSmrg	    if (exaScratch.type == COMP_TYPE_ONEPASS) {
1408170d5fdcSmrg		if (srcX >= 0 && srcY >= 0 && (exaScratch.op == PictOpOver ||
1409170d5fdcSmrg		    exaScratch.op == PictOpSrc || exaScratch.op ==
1410170d5fdcSmrg		    PictOpClear)) {
1411170d5fdcSmrg		    opWidth = ((dstX + width) - opX) > (exaScratch.srcWidth -
1412170d5fdcSmrg			srcX) ? (exaScratch.srcWidth - srcX) : (dstX + width)
1413170d5fdcSmrg			- opX;
1414170d5fdcSmrg		    opHeight = ((dstY + height) - opY) >
1415170d5fdcSmrg		    (exaScratch.srcHeight - srcY) ?
1416170d5fdcSmrg		    (exaScratch.srcHeight - srcY) : (dstY + height) - opY;
1417170d5fdcSmrg		} else {
1418170d5fdcSmrg		opWidth = ((dstX + width) - opX) > exaScratch.srcWidth ?
1419170d5fdcSmrg		    exaScratch.srcWidth : (dstX + width) - opX;
1420170d5fdcSmrg		opHeight = ((dstY + height) - opY) > exaScratch.srcHeight ?
1421170d5fdcSmrg		    exaScratch.srcHeight : (dstY + height) - opY;
1422170d5fdcSmrg		}
1423170d5fdcSmrg	    } else {
1424170d5fdcSmrg		opWidth = ((dstX + width) - opX) > (exaScratch.srcWidth - srcY)
1425170d5fdcSmrg		    ? (exaScratch.srcWidth - srcY) : (dstX + width) - opX;
1426170d5fdcSmrg		opHeight = ((dstY + height) - opY) > (exaScratch.srcHeight - srcX
1427170d5fdcSmrg		    ) ? (exaScratch.srcHeight - srcX) : (dstY + height) - opY;
1428170d5fdcSmrg	    }
1429170d5fdcSmrg	    /* All black out of the source */
1430170d5fdcSmrg	    if (!exaScratch.repeat && (exaScratch.type == COMP_TYPE_ONEPASS)) {
1431170d5fdcSmrg		    lx_composite_all_black(srcOffset, exaScratch.srcWidth,
1432170d5fdcSmrg			exaScratch.srcHeight);
1433170d5fdcSmrg	    }
1434170d5fdcSmrg	    if (!exaScratch.repeat && (exaScratch.type == COMP_TYPE_ROTATE))
1435170d5fdcSmrg		    break;
1436170d5fdcSmrg	}
1437f29dbc25Smrg    }
1438f29dbc25Smrg}
1439f29dbc25Smrg
1440f29dbc25Smrgstatic void
1441f29dbc25Smrglx_wait_marker(ScreenPtr PScreen, int marker)
1442f29dbc25Smrg{
1443f29dbc25Smrg    gp_wait_until_idle();
1444f29dbc25Smrg}
1445f29dbc25Smrg
1446f29dbc25Smrgstatic void
1447f29dbc25Smrglx_done(PixmapPtr ptr)
1448f29dbc25Smrg{
1449f29dbc25Smrg}
1450f29dbc25Smrg
1451f29dbc25Smrg#if 0
1452f29dbc25Smrgstatic void
1453f29dbc25Smrglx_upload_to_screen(PixmapPtr pxDst, int x, int y, int w, int h,
1454f29dbc25Smrg    char *src, int src_pitch)
1455f29dbc25Smrg{
1456f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR_FROM_PIXMAP(pxDst);
1457f29dbc25Smrg    int dst_pitch = exaGetPixmapPitch(pxDst);
1458f29dbc25Smrg    int cpp = (pxDst->drawable.bitsPerPixel + 7) / 8;
1459f29dbc25Smrg
1460f29dbc25Smrg    char *dst;
1461f29dbc25Smrg    int offset = exaGetPixmapOffset(pxDst);
1462f29dbc25Smrg
1463f29dbc25Smrg    dst = (char *)(pGeode->FBBase + offset + (y * dst_pitch) + (x * cpp));
1464f29dbc25Smrg    int i;
1465f29dbc25Smrg
1466f29dbc25Smrg    for (i = 0; i < h; i++) {
1467f29dbc25Smrg	memcpy(dst, src, w * cpp);
1468f29dbc25Smrg	dst += dst_pitch;
1469f29dbc25Smrg	src += src_pitch;
1470f29dbc25Smrg    }
1471f29dbc25Smrg}
1472f29dbc25Smrg#endif
1473f29dbc25Smrg
1474f29dbc25Smrg#if EXA_VERSION_MINOR >= 2
1475f29dbc25Smrg
1476f29dbc25Smrgstatic Bool
1477f29dbc25Smrglx_exa_pixmap_is_offscreen(PixmapPtr pPixmap)
1478f29dbc25Smrg{
1479f29dbc25Smrg    ScrnInfoPtr pScrni = xf86Screens[pPixmap->drawable.pScreen->myNum];
1480f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
1481f29dbc25Smrg    void *start = (void *)(pGeode->FBBase);
1482f29dbc25Smrg    void *end =
1483f29dbc25Smrg	(void *)(pGeode->FBBase + pGeode->offscreenStart +
1484f29dbc25Smrg	pGeode->offscreenSize);
1485f29dbc25Smrg
1486f29dbc25Smrg    if ((void *)pPixmap->devPrivate.ptr >= start &&
1487f29dbc25Smrg	(void *)pPixmap->devPrivate.ptr < end)
1488f29dbc25Smrg	return TRUE;
1489f29dbc25Smrg
1490f29dbc25Smrg    return FALSE;
1491f29dbc25Smrg}
1492f29dbc25Smrg
1493f29dbc25Smrg#endif
1494f29dbc25Smrg
1495f29dbc25SmrgBool
1496f29dbc25SmrgLXExaInit(ScreenPtr pScreen)
1497f29dbc25Smrg{
1498f29dbc25Smrg    ScrnInfoPtr pScrni = xf86Screens[pScreen->myNum];
1499f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
1500f29dbc25Smrg    ExaDriverPtr pExa = pGeode->pExa;
1501f29dbc25Smrg
1502f29dbc25Smrg    pExa->exa_major = EXA_VERSION_MAJOR;
1503f29dbc25Smrg    pExa->exa_minor = EXA_VERSION_MINOR;
1504f29dbc25Smrg
1505f29dbc25Smrg    pExa->WaitMarker = lx_wait_marker;
1506f29dbc25Smrg
1507f29dbc25Smrg    pExa->PrepareSolid = lx_prepare_solid;
1508f29dbc25Smrg    pExa->Solid = lx_do_solid;
1509f29dbc25Smrg    pExa->DoneSolid = lx_done;
1510f29dbc25Smrg
1511f29dbc25Smrg    pExa->PrepareCopy = lx_prepare_copy;
1512f29dbc25Smrg    pExa->Copy = lx_do_copy;
1513f29dbc25Smrg    pExa->DoneCopy = lx_done;
1514f29dbc25Smrg
1515f29dbc25Smrg    /* Composite */
1516f29dbc25Smrg    pExa->CheckComposite = lx_check_composite;
1517f29dbc25Smrg    pExa->PrepareComposite = lx_prepare_composite;
1518f29dbc25Smrg    pExa->Composite = lx_do_composite;
1519f29dbc25Smrg    pExa->DoneComposite = lx_done;
1520f29dbc25Smrg    //pExa->UploadToScreen =  lx_upload_to_screen;
1521f29dbc25Smrg
1522f29dbc25Smrg#if EXA_VERSION_MINOR >= 2
1523f29dbc25Smrg    pExa->PixmapIsOffscreen = lx_exa_pixmap_is_offscreen;
1524f29dbc25Smrg#endif
1525f29dbc25Smrg
1526f29dbc25Smrg    //pExa->flags = EXA_OFFSCREEN_PIXMAPS;
1527f29dbc25Smrg
1528f29dbc25Smrg    return exaDriverInit(pScreen, pGeode->pExa);
1529f29dbc25Smrg}
1530