lx_exa.c revision 04007eba
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
5104007ebaSmrg#define GEODE_TRACE_FALL 0
5204007ebaSmrg
5304007ebaSmrg#if GEODE_TRACE_FALL
5404007ebaSmrg#define GEODE_FALLBACK(x)               \
5504007ebaSmrgdo {                                    \
5604007ebaSmrg	ErrorF("%s: ", __FUNCTION__);   \
5704007ebaSmrg	ErrorF x;                       \
5804007ebaSmrg	return FALSE;                   \
5904007ebaSmrg} while (0)
6004007ebaSmrg#else
6104007ebaSmrg#define GEODE_FALLBACK(x) return FALSE
6204007ebaSmrg#endif
6304007ebaSmrg
6404007ebaSmrgstatic const struct exa_format_t {
65f29dbc25Smrg    int exa;
66f29dbc25Smrg    int bpp;
67f29dbc25Smrg    int fmt;
68f29dbc25Smrg    int alphabits;
69f29dbc25Smrg} lx_exa_formats[] = {
70f29dbc25Smrg    {
71f29dbc25Smrg    PICT_a8r8g8b8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 8}, {
72f29dbc25Smrg    PICT_x8r8g8b8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 0}, {
73f29dbc25Smrg    PICT_x8b8g8r8, 32, CIMGP_SOURCE_FMT_32BPP_BGR, 0}, {
74f29dbc25Smrg    PICT_a4r4g4b4, 16, CIMGP_SOURCE_FMT_4_4_4_4, 4}, {
75f29dbc25Smrg    PICT_a1r5g5b5, 16, CIMGP_SOURCE_FMT_1_5_5_5, 1}, {
76f29dbc25Smrg    PICT_r5g6b5, 16, CIMGP_SOURCE_FMT_0_5_6_5, 0}, {
77f29dbc25Smrg    PICT_b5g6r5, 16, CIMGP_SOURCE_FMT_16BPP_BGR, 0}, {
78f29dbc25Smrg    PICT_x1r5g5b5, 16, CIMGP_SOURCE_FMT_1_5_5_5, 0}, {
79f29dbc25Smrg    PICT_x1b5g5r5, 16, CIMGP_SOURCE_FMT_15BPP_BGR, 0}, {
80170d5fdcSmrg    PICT_r3g3b2, 8, CIMGP_SOURCE_FMT_3_3_2, 0}, {
81170d5fdcSmrg    PICT_a8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 8}
82f29dbc25Smrg};
83f29dbc25Smrg
84f29dbc25Smrg/* This is a chunk of memory we use for scratch space */
85f29dbc25Smrg
86f29dbc25Smrg#define COMP_TYPE_MASK 0
87f29dbc25Smrg#define COMP_TYPE_ONEPASS 1
88f29dbc25Smrg#define COMP_TYPE_TWOPASS 3
89f29dbc25Smrg#define COMP_TYPE_ROTATE  5
90f29dbc25Smrg
9104007ebaSmrgstatic struct {
92f29dbc25Smrg    int type;
93f29dbc25Smrg
94f29dbc25Smrg    unsigned int srcOffset;
95f29dbc25Smrg    unsigned int srcPitch;
96f29dbc25Smrg    unsigned int srcBpp;
97f29dbc25Smrg    unsigned int srcWidth, srcHeight;
98f29dbc25Smrg
99f29dbc25Smrg    unsigned int srcColor;
100f29dbc25Smrg    int op;
101f29dbc25Smrg    int repeat;
102170d5fdcSmrg    int maskrepeat;
103f29dbc25Smrg    unsigned int fourBpp;
104f29dbc25Smrg    unsigned int bufferOffset;
105f29dbc25Smrg    struct exa_format_t *srcFormat;
106f29dbc25Smrg    struct exa_format_t *dstFormat;
107f29dbc25Smrg
108f29dbc25Smrg    int rotate;
109f29dbc25Smrg    PictTransform *transform;
110f29dbc25Smrg
111f29dbc25Smrg} exaScratch;
112f29dbc25Smrg
113f29dbc25Smrgstatic const int SDfn[16] = {
114f29dbc25Smrg    0x00, 0x88, 0x44, 0xCC, 0x22, 0xAA, 0x66, 0xEE,
115f29dbc25Smrg    0x11, 0x99, 0x55, 0xDD, 0x33, 0xBB, 0x77, 0xFF
116f29dbc25Smrg};
117f29dbc25Smrg
118f29dbc25Smrgstatic const int SDfn_PM[16] = {
119f29dbc25Smrg    0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
120f29dbc25Smrg    0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA
121f29dbc25Smrg};
122f29dbc25Smrg
123f29dbc25Smrg/* These functions check to see if we can safely prefetch the memory
124f29dbc25Smrg * for the blt, or if we have to wait the previous blt to complete.
125f29dbc25Smrg * One function is for the fill, and the other is for the copy because
126f29dbc25Smrg * they have different requirements based on ROP
127f29dbc25Smrg */
128f29dbc25Smrg
129f29dbc25Smrgstatic int lx0 = -1, ly0 = -1, lx1 = -1, ly1 = -1;
130f29dbc25Smrg
131f29dbc25Smrgstatic int
132f29dbc25Smrglx_fill_flags(int x0, int y0, int w, int h, int rop)
133f29dbc25Smrg{
134f29dbc25Smrg    int x1 = x0 + w, y1 = y0 + h;
13504007ebaSmrg    int n = ((rop ^ (rop >> 1)) & 0x55) == 0 || /* no dst */
13604007ebaSmrg        x0 >= lx1 || y0 >= ly1 ||       /* rght/below */
13704007ebaSmrg        x1 <= lx0 || y1 <= ly0 ?        /* left/above */
13804007ebaSmrg        0 : CIMGP_BLTFLAGS_HAZARD;
139f29dbc25Smrg
140f29dbc25Smrg    lx0 = x0;
141f29dbc25Smrg    ly0 = y0;
142f29dbc25Smrg    lx1 = x1;
143f29dbc25Smrg    ly1 = y1;
144f29dbc25Smrg
145f29dbc25Smrg    return n;
146f29dbc25Smrg}
147f29dbc25Smrg
148f29dbc25Smrgstatic int
149f29dbc25Smrglx_copy_flags(int x0, int y0, int x1, int y1, int w, int h, int rop)
150f29dbc25Smrg{
151f29dbc25Smrg    int x2 = x1 + w, y2 = y1 + h;
152f29dbc25Smrg
153f29dbc25Smrg    /* dst not hazzard and src not hazzard */
154f29dbc25Smrg    int n = (((rop ^ (rop >> 1)) & 0x55) == 0 ||
15504007ebaSmrg             x1 >= lx1 || y1 >= ly1 ||
15604007ebaSmrg             x2 <= lx0 || y2 <= ly0) &&
15704007ebaSmrg        (((rop ^ (rop >> 2)) & 0x33) == 0 ||
15804007ebaSmrg         x0 >= lx1 || y0 >= ly1 ||
15904007ebaSmrg         x0 + w <= lx0 || y0 + h <= ly0) ? 0 : CIMGP_BLTFLAGS_HAZARD;
160f29dbc25Smrg
161f29dbc25Smrg    lx0 = x1;
162f29dbc25Smrg    ly0 = y1;
163f29dbc25Smrg    lx1 = x2;
164f29dbc25Smrg    ly1 = y2;
165f29dbc25Smrg
166f29dbc25Smrg    return n;
167f29dbc25Smrg}
168f29dbc25Smrg
169f29dbc25Smrg/* These are borrowed from the exa engine - they should be made global
170f29dbc25Smrg   and available to drivers, but until then....
171f29dbc25Smrg*/
172f29dbc25Smrg
173f29dbc25Smrg/* exaGetPixelFromRGBA (exa_render.c) */
174f29dbc25Smrg
175f29dbc25Smrgstatic Bool
17604007ebaSmrg_GetPixelFromRGBA(CARD32 *pixel,
17704007ebaSmrg                  CARD16 red, CARD16 green, CARD16 blue, CARD16 alpha,
17804007ebaSmrg                  CARD32 format)
179f29dbc25Smrg{
180f29dbc25Smrg    int rbits, bbits, gbits, abits;
181f29dbc25Smrg    int rshift, bshift, gshift, ashift;
182f29dbc25Smrg
183f29dbc25Smrg    *pixel = 0;
184f29dbc25Smrg
185f29dbc25Smrg    if (!PICT_FORMAT_COLOR(format))
18604007ebaSmrg        return FALSE;
187f29dbc25Smrg
188f29dbc25Smrg    rbits = PICT_FORMAT_R(format);
189f29dbc25Smrg    gbits = PICT_FORMAT_G(format);
190f29dbc25Smrg    bbits = PICT_FORMAT_B(format);
191f29dbc25Smrg    abits = PICT_FORMAT_A(format);
192f29dbc25Smrg
193f29dbc25Smrg    if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
19404007ebaSmrg        bshift = 0;
19504007ebaSmrg        gshift = bbits;
19604007ebaSmrg        rshift = gshift + gbits;
19704007ebaSmrg        ashift = rshift + rbits;
19804007ebaSmrg    }
19904007ebaSmrg    else {                      /* PICT_TYPE_ABGR */
20004007ebaSmrg        rshift = 0;
20104007ebaSmrg        gshift = rbits;
20204007ebaSmrg        bshift = gshift + gbits;
20304007ebaSmrg        ashift = bshift + bbits;
204f29dbc25Smrg    }
205f29dbc25Smrg
206f29dbc25Smrg    *pixel |= (blue >> (16 - bbits)) << bshift;
207f29dbc25Smrg    *pixel |= (red >> (16 - rbits)) << rshift;
208f29dbc25Smrg    *pixel |= (green >> (16 - gbits)) << gshift;
209f29dbc25Smrg    *pixel |= (alpha >> (16 - abits)) << ashift;
210f29dbc25Smrg
211f29dbc25Smrg    return TRUE;
212f29dbc25Smrg}
213f29dbc25Smrg
214f29dbc25Smrg/* exaGetRGBAFromPixel (exa_render.c) */
215f29dbc25Smrg
216f29dbc25Smrgstatic Bool
217f29dbc25Smrg_GetRGBAFromPixel(CARD32 pixel,
21804007ebaSmrg                  CARD16 *red,
21904007ebaSmrg                  CARD16 *green, CARD16 *blue, CARD16 *alpha, CARD32 format)
220f29dbc25Smrg{
221f29dbc25Smrg    int rbits, bbits, gbits, abits;
222f29dbc25Smrg    int rshift, bshift, gshift, ashift;
223f29dbc25Smrg
224f29dbc25Smrg    if (!PICT_FORMAT_COLOR(format))
22504007ebaSmrg        return FALSE;
226f29dbc25Smrg
227f29dbc25Smrg    rbits = PICT_FORMAT_R(format);
228f29dbc25Smrg    gbits = PICT_FORMAT_G(format);
229f29dbc25Smrg    bbits = PICT_FORMAT_B(format);
230f29dbc25Smrg    abits = PICT_FORMAT_A(format);
231f29dbc25Smrg
232f29dbc25Smrg    if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
23304007ebaSmrg        bshift = 0;
23404007ebaSmrg        gshift = bbits;
23504007ebaSmrg        rshift = gshift + gbits;
23604007ebaSmrg        ashift = rshift + rbits;
23704007ebaSmrg    }
23804007ebaSmrg    else {                      /* PICT_TYPE_ABGR */
23904007ebaSmrg        rshift = 0;
24004007ebaSmrg        gshift = rbits;
24104007ebaSmrg        bshift = gshift + gbits;
24204007ebaSmrg        ashift = bshift + bbits;
243f29dbc25Smrg    }
244f29dbc25Smrg
245f29dbc25Smrg    *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits);
246f29dbc25Smrg    while (rbits < 16) {
24704007ebaSmrg        *red |= *red >> rbits;
24804007ebaSmrg        rbits <<= 1;
249f29dbc25Smrg    }
250f29dbc25Smrg
251f29dbc25Smrg    *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits);
252f29dbc25Smrg    while (gbits < 16) {
25304007ebaSmrg        *green |= *green >> gbits;
25404007ebaSmrg        gbits <<= 1;
255f29dbc25Smrg    }
256f29dbc25Smrg
257f29dbc25Smrg    *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits);
258f29dbc25Smrg    while (bbits < 16) {
25904007ebaSmrg        *blue |= *blue >> bbits;
26004007ebaSmrg        bbits <<= 1;
261f29dbc25Smrg    }
262f29dbc25Smrg
263f29dbc25Smrg    if (abits) {
26404007ebaSmrg        *alpha = ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits);
26504007ebaSmrg        while (abits < 16) {
26604007ebaSmrg            *alpha |= *alpha >> abits;
26704007ebaSmrg            abits <<= 1;
26804007ebaSmrg        }
26904007ebaSmrg    }
27004007ebaSmrg    else
27104007ebaSmrg        *alpha = 0xffff;
272f29dbc25Smrg
273f29dbc25Smrg    return TRUE;
274f29dbc25Smrg}
275f29dbc25Smrg
276f29dbc25Smrgstatic unsigned int
277f29dbc25Smrglx_get_source_color(PixmapPtr pSrc, int srcFormat, int dstFormat)
278f29dbc25Smrg{
279f29dbc25Smrg    CARD32 in, out;
280f29dbc25Smrg    CARD16 red = 0, green = 0, blue = 0, alpha = 0;
281f29dbc25Smrg
282f29dbc25Smrg    /* Stall to avoid a race with the upload function */
283f29dbc25Smrg    /* for 1.4 and newer, the problem will be resolved within
284f29dbc25Smrg     * exaGetPixmapFirstPixel, so this should be adjusted so
285f29dbc25Smrg     * the stall isn't run needlessly
286f29dbc25Smrg     */
28704007ebaSmrg    /* FIXME: xserver-1.4 with a supposed fix for this is really old, so kill the stall? */
288f29dbc25Smrg
289f29dbc25Smrg    gp_wait_until_idle();
290f29dbc25Smrg    in = exaGetPixmapFirstPixel(pSrc);
291f29dbc25Smrg
292f29dbc25Smrg    _GetRGBAFromPixel(in, &red, &blue, &green, &alpha, srcFormat);
293f29dbc25Smrg    _GetPixelFromRGBA(&out, red, blue, green, alpha, dstFormat);
294f29dbc25Smrg
295f29dbc25Smrg    return out;
296f29dbc25Smrg}
297f29dbc25Smrg
298f29dbc25Smrgstatic Bool
299f29dbc25Smrglx_prepare_solid(PixmapPtr pxMap, int alu, Pixel planemask, Pixel fg)
300f29dbc25Smrg{
301f29dbc25Smrg    int pitch = exaGetPixmapPitch(pxMap);
302f29dbc25Smrg    int op = (planemask == ~0U) ? SDfn[alu] : SDfn_PM[alu];
303f29dbc25Smrg
304f29dbc25Smrg    gp_declare_blt(0);
305f29dbc25Smrg    gp_set_bpp(pxMap->drawable.bitsPerPixel);
306f29dbc25Smrg
307f29dbc25Smrg    gp_set_raster_operation(op);
308f29dbc25Smrg
309f29dbc25Smrg    if (planemask != ~0U)
31004007ebaSmrg        gp_set_solid_pattern(planemask);
311f29dbc25Smrg
312f29dbc25Smrg    exaScratch.op = op;
313f29dbc25Smrg
314f29dbc25Smrg    gp_set_solid_source(fg);
315f29dbc25Smrg
316f29dbc25Smrg    gp_set_strides(pitch, pitch);
317f29dbc25Smrg    gp_write_parameters();
318f29dbc25Smrg    return TRUE;
319f29dbc25Smrg}
320f29dbc25Smrg
321f29dbc25Smrgstatic void
322f29dbc25Smrglx_do_solid(PixmapPtr pxMap, int x1, int y1, int x2, int y2)
323f29dbc25Smrg{
324f29dbc25Smrg    int bpp = (pxMap->drawable.bitsPerPixel + 7) / 8;
325f29dbc25Smrg    int pitch = exaGetPixmapPitch(pxMap);
32604007ebaSmrg    unsigned int offset = exaGetPixmapOffset(pxMap) + (pitch * y1) + (bpp * x1);
327f29dbc25Smrg
328f29dbc25Smrg    gp_declare_blt(lx_fill_flags(x1, y1, x2 - x1, y2 - y1, exaScratch.op));
329f29dbc25Smrg    gp_pattern_fill(offset, x2 - x1, y2 - y1);
330f29dbc25Smrg}
331f29dbc25Smrg
332f29dbc25Smrgstatic Bool
333f29dbc25Smrglx_prepare_copy(PixmapPtr pxSrc, PixmapPtr pxDst, int dx, int dy,
33404007ebaSmrg                int alu, Pixel planemask)
335f29dbc25Smrg{
336f29dbc25Smrg    int dpitch = exaGetPixmapPitch(pxDst);
337f29dbc25Smrg    int op = (planemask == ~0U) ? SDfn[alu] : SDfn_PM[alu];
338f29dbc25Smrg
339f29dbc25Smrg    gp_declare_blt(0);
340f29dbc25Smrg    gp_set_bpp(pxDst->drawable.bitsPerPixel);
341f29dbc25Smrg
342f29dbc25Smrg    gp_set_raster_operation(op);
343f29dbc25Smrg
344f29dbc25Smrg    if (planemask != ~0U)
34504007ebaSmrg        gp_set_solid_pattern(planemask);
346f29dbc25Smrg
347f29dbc25Smrg    exaScratch.srcOffset = exaGetPixmapOffset(pxSrc);
348f29dbc25Smrg    exaScratch.srcPitch = exaGetPixmapPitch(pxSrc);
349f29dbc25Smrg    exaScratch.srcBpp = (pxSrc->drawable.bitsPerPixel + 7) / 8;
350f29dbc25Smrg
351f29dbc25Smrg    exaScratch.op = op;
352f29dbc25Smrg
353f29dbc25Smrg    gp_set_strides(dpitch, exaScratch.srcPitch);
354f29dbc25Smrg    gp_write_parameters();
355f29dbc25Smrg    return TRUE;
356f29dbc25Smrg}
357f29dbc25Smrg
358f29dbc25Smrgstatic void
359f29dbc25Smrglx_do_copy(PixmapPtr pxDst, int srcX, int srcY,
36004007ebaSmrg           int dstX, int dstY, int w, int h)
361f29dbc25Smrg{
362f29dbc25Smrg    int dstBpp = (pxDst->drawable.bitsPerPixel + 7) / 8;
363f29dbc25Smrg    int dstPitch = exaGetPixmapPitch(pxDst);
364f29dbc25Smrg    unsigned int srcOffset, dstOffset;
365f29dbc25Smrg    int flags = 0;
366f29dbc25Smrg
36704007ebaSmrg    gp_declare_blt(lx_copy_flags(srcX, srcY, dstX, dstY, w, h, exaScratch.op));
368f29dbc25Smrg
369f29dbc25Smrg    srcOffset = exaScratch.srcOffset + (exaScratch.srcPitch * srcY) +
37004007ebaSmrg        (exaScratch.srcBpp) * srcX;
371f29dbc25Smrg
37204007ebaSmrg    dstOffset = exaGetPixmapOffset(pxDst) + (dstPitch * dstY) + (dstBpp * dstX);
373f29dbc25Smrg
374f29dbc25Smrg    if (dstX > srcX)
37504007ebaSmrg        flags |= CIMGP_NEGXDIR;
376f29dbc25Smrg
377f29dbc25Smrg    if (dstY > srcY)
37804007ebaSmrg        flags |= CIMGP_NEGYDIR;
379f29dbc25Smrg
380f29dbc25Smrg    gp_screen_to_screen_blt(dstOffset, srcOffset, w, h, flags);
381f29dbc25Smrg}
382f29dbc25Smrg
383f29dbc25Smrg/* Composite operations
384f29dbc25Smrg
385f29dbc25SmrgThese are the simplest - one pass operations - if there is no format or
386f29dbc25Smrgmask, the we can make these happen pretty fast
387f29dbc25Smrg
388f29dbc25Smrg                       Operation  Type  Channel   Alpha
389f29dbc25SmrgPictOpClear            0          2     0         3
390f29dbc25SmrgPictOpSrc              0          3     0         3
391f29dbc25SmrgPictOpDst              0          3     1         3
392f29dbc25SmrgPictOpOver             2          0     0         3
393f29dbc25SmrgPictOpOverReverse      2          0     1         3
394f29dbc25SmrgPictOpIn               0          1     0         3
395f29dbc25SmrgPictOpInReverse        0          1     1         3
396f29dbc25SmrgPictOpOut              1          0     0         3
397f29dbc25SmrgPictOpOutReverse       1          0     1         3
398f29dbc25SmrgPictOpAdd              2          2     0         3
399f29dbc25Smrg
400f29dbc25SmrgThe following require multiple passes
401f29dbc25SmrgPictOpAtop
402f29dbc25SmrgPictOpXor
403f29dbc25Smrg*/
404f29dbc25Smrg
40504007ebaSmrgstruct blend_ops_t {
406f29dbc25Smrg    int operation;
407f29dbc25Smrg    int type;
408f29dbc25Smrg    int channel;
409f29dbc25Smrg} lx_alpha_ops[] = {
410f29dbc25Smrg    /* PictOpClear */
411f29dbc25Smrg    {
412f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONSTANT_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
413f29dbc25Smrg    },
41404007ebaSmrg        /* PictOpSrc */
415f29dbc25Smrg    {
416f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_ALPHA_EQUALS_ONE, CIMGP_CHANNEL_A_SOURCE}, {
417f29dbc25Smrg    },
41804007ebaSmrg        /* PictOpDst */
419f29dbc25Smrg    {
420f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_ALPHA_EQUALS_ONE, CIMGP_CHANNEL_A_DEST}, {
421f29dbc25Smrg    },
42204007ebaSmrg        /* PictOpOver */
423f29dbc25Smrg    {
424170d5fdcSmrg    CIMGP_A_PLUS_BETA_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
425170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
42604007ebaSmrg        /* PictOpOverReverse */
427f29dbc25Smrg    {
428170d5fdcSmrg    CIMGP_A_PLUS_BETA_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST}, {
429170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
43004007ebaSmrg        /* PictOpIn */
431f29dbc25Smrg    {
432f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
433170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
43404007ebaSmrg        /* PictOpInReverse */
435f29dbc25Smrg    {
436f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_DEST}, {
437170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
43804007ebaSmrg        /* PictOpOut */
439f29dbc25Smrg    {
440170d5fdcSmrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST}, {
441170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
44204007ebaSmrg        /* PictOpOutReverse */
443f29dbc25Smrg    {
444170d5fdcSmrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
445170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
44604007ebaSmrg        /* SrcAtop */
447f29dbc25Smrg    {
448f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_DEST}, {
449f29dbc25Smrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE},
45004007ebaSmrg        /* SrcAtopReverse */
451f29dbc25Smrg    {
452f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
453f29dbc25Smrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST},
45404007ebaSmrg        /* Xor */
455f29dbc25Smrg    {
456f29dbc25Smrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
457f29dbc25Smrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE},
45804007ebaSmrg        /* PictOpAdd */
459f29dbc25Smrg    {
460f29dbc25Smrg    CIMGP_A_PLUS_BETA_B, CIMGP_CONSTANT_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
461f29dbc25Smrg    }
462f29dbc25Smrg};
463f29dbc25Smrg
46404007ebaSmrg#ifndef ARRAY_SIZE
465f29dbc25Smrg#define ARRAY_SIZE(a) (sizeof((a)) / (sizeof(*(a))))
46604007ebaSmrg#endif
467f29dbc25Smrg
468f29dbc25Smrgstatic const struct exa_format_t *
469f29dbc25Smrglx_get_format(PicturePtr p)
470f29dbc25Smrg{
471f29dbc25Smrg    int i;
472f29dbc25Smrg    unsigned int format = p->format;
473f29dbc25Smrg
474170d5fdcSmrg    for (i = 0; i < ARRAY_SIZE(lx_exa_formats); i++)
47504007ebaSmrg        if (lx_exa_formats[i].exa == format)
47604007ebaSmrg            return (&lx_exa_formats[i]);
477f29dbc25Smrg
478f29dbc25Smrg    return NULL;
479f29dbc25Smrg}
480f29dbc25Smrg
481f29dbc25Smrgstatic Bool
482f29dbc25Smrglx_process_transform(PicturePtr pSrc)
483f29dbc25Smrg{
484f29dbc25Smrg    PictTransformPtr t = pSrc->transform;
485f29dbc25Smrg    xFixed c0 = t->matrix[0][0];
486f29dbc25Smrg    xFixed s0 = t->matrix[0][1];
487f29dbc25Smrg    xFixed s1 = t->matrix[1][0];
488f29dbc25Smrg    xFixed c1 = t->matrix[1][1];
489f29dbc25Smrg
490f29dbc25Smrg    /* If the transform doesn't have any rotation
491f29dbc25Smrg     * or scaling components, then just grab the
492f29dbc25Smrg     * translate coordinates */
493f29dbc25Smrg
494f29dbc25Smrg    if (t->matrix[0][0] == 0 &&
49504007ebaSmrg        t->matrix[0][1] == 0 && t->matrix[1][0] == 0 && t->matrix[1][1] == 0) {
49604007ebaSmrg        exaScratch.transform = pSrc->transform;
49704007ebaSmrg        return TRUE;
498f29dbc25Smrg    }
499f29dbc25Smrg
500f29dbc25Smrg    /* Otherwise, see if this is a simple
501f29dbc25Smrg     * rotate transform - if it isn't, then
502f29dbc25Smrg     * we have to punt back to software */
503f29dbc25Smrg
504f29dbc25Smrg    if (t->matrix[2][2] != F(1))
50504007ebaSmrg        return FALSE;
506f29dbc25Smrg
507f29dbc25Smrg    /* The rotate matrix looks like this:
508f29dbc25Smrg     * [ cos X   -sin x
509f29dbc25Smrg     * sin X   cos X ]
510f29dbc25Smrg     *
511f29dbc25Smrg     * Where X is the angle.  We do a simple
512f29dbc25Smrg     * check first - if [0,0] != [1,1], then
513f29dbc25Smrg     * scaling was specified too, and we can
514f29dbc25Smrg     * bail, and if [0,1] != -[1,1] then this
515f29dbc25Smrg     * isn't scaling that we can handle.
516f29dbc25Smrg     */
517f29dbc25Smrg
518f29dbc25Smrg    if ((c0 != c1) || (s0 != -s1))
51904007ebaSmrg        return FALSE;
520f29dbc25Smrg
521f29dbc25Smrg    /* Now, figure out what angle we want - we
522f29dbc25Smrg     * can only accelerate right angle rotations,
523f29dbc25Smrg     * so this turns into an easy set of if statements */
524f29dbc25Smrg
525f29dbc25Smrg    if (c0 == F(1) && s1 == F(0))
52604007ebaSmrg        exaScratch.rotate = RR_Rotate_0;
527f29dbc25Smrg    else if (c0 == F(0) && s1 == F(1))
52804007ebaSmrg        exaScratch.rotate = RR_Rotate_90;
529f29dbc25Smrg    else if (c0 == F(-1) && s1 == F(0))
53004007ebaSmrg        exaScratch.rotate = RR_Rotate_180;
531f29dbc25Smrg    else if (c0 == F(0) && s1 == F(-1))
53204007ebaSmrg        exaScratch.rotate = RR_Rotate_270;
533f29dbc25Smrg    else
53404007ebaSmrg        return FALSE;
535f29dbc25Smrg
536f29dbc25Smrg    exaScratch.transform = pSrc->transform;
537f29dbc25Smrg
538f29dbc25Smrg    return TRUE;
539f29dbc25Smrg}
540f29dbc25Smrg
541f29dbc25Smrgstatic Bool
542f29dbc25Smrglx_check_composite(int op, PicturePtr pSrc, PicturePtr pMsk, PicturePtr pDst)
543f29dbc25Smrg{
544f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR_FROM_PICTURE(pDst);
545170d5fdcSmrg    const struct exa_format_t *srcFmt, *dstFmt;
546f29dbc25Smrg
547f29dbc25Smrg    if (op > PictOpAdd)
54804007ebaSmrg        GEODE_FALLBACK(("Operation %d is not supported\n", op));
54904007ebaSmrg
55004007ebaSmrg    /* XXX - don't know if we can do any hwaccel on solid fills or gradient types in generic cases */
55104007ebaSmrg    if (pMsk && pMsk->pSourcePict)
55204007ebaSmrg        GEODE_FALLBACK(("%s are not supported as a mask\n",
55304007ebaSmrg                        pMsk->pSourcePict->type ==
55404007ebaSmrg                        SourcePictTypeSolidFill ? "Solid pictures" :
55504007ebaSmrg                        "Gradients"));
55604007ebaSmrg
55704007ebaSmrg    if (pSrc->pSourcePict && pSrc->pSourcePict->type != SourcePictTypeSolidFill)
55804007ebaSmrg        GEODE_FALLBACK(("Gradients are not supported as the source\n"));
55904007ebaSmrg
56004007ebaSmrg    if (pMsk && op == PictOpAdd)
56104007ebaSmrg        GEODE_FALLBACK(("PictOpAdd with mask is not supported\n"));
562f29dbc25Smrg
563170d5fdcSmrg    /* FIXME: Meet this conditions from the debug for PictOpAdd.
564170d5fdcSmrg     * Any Other possibilities? Add a judge for the future supplement */
565170d5fdcSmrg    if (op == PictOpAdd && pSrc->format == PICT_a8r8g8b8 &&
56604007ebaSmrg        pDst->format == PICT_a8)
56704007ebaSmrg        return TRUE;
568170d5fdcSmrg
569170d5fdcSmrg    if (op == PictOpAdd && pSrc->format == PICT_x8r8g8b8 &&
57004007ebaSmrg        pDst->format == PICT_a8)
57104007ebaSmrg        return TRUE;
572170d5fdcSmrg
573170d5fdcSmrg    if (op == PictOpAdd && pSrc->format == PICT_r5g6b5 &&
57404007ebaSmrg        pDst->format == PICT_a8)
57504007ebaSmrg        return TRUE;
576170d5fdcSmrg
577f29dbc25Smrg    if (usesPasses(op)) {
57804007ebaSmrg        /* FIXME: Slightly misleading fallback msg when !pMsk */
57904007ebaSmrg        if (pGeode->exaBfrOffset == 0 || !pMsk)
58004007ebaSmrg            GEODE_FALLBACK(("Multipass operation requires off-screen buffer\n"));
581f29dbc25Smrg    }
582f29dbc25Smrg
583f29dbc25Smrg    /* Check that the filter matches what we support */
584f29dbc25Smrg
585f29dbc25Smrg    switch (pSrc->filter) {
586f29dbc25Smrg    case PictFilterNearest:
587f29dbc25Smrg    case PictFilterFast:
588f29dbc25Smrg    case PictFilterGood:
589f29dbc25Smrg    case PictFilterBest:
59004007ebaSmrg        break;
591f29dbc25Smrg
592f29dbc25Smrg    default:
59304007ebaSmrg        GEODE_FALLBACK(("Bilinear or convolution filters are not supported\n"));
594f29dbc25Smrg    }
595f29dbc25Smrg
596f29dbc25Smrg    if (pMsk && pMsk->transform)
59704007ebaSmrg        GEODE_FALLBACK(("Mask transforms are not supported\n"));
598170d5fdcSmrg
599f29dbc25Smrg    /* Keep an eye out for source rotation transforms - those we can
600f29dbc25Smrg     * do something about */
601f29dbc25Smrg
602f29dbc25Smrg    exaScratch.rotate = RR_Rotate_0;
603f29dbc25Smrg    exaScratch.transform = NULL;
604f29dbc25Smrg
605f29dbc25Smrg    if (pSrc->transform && !lx_process_transform(pSrc))
60604007ebaSmrg        GEODE_FALLBACK(("Transform operation is non-trivial\n"));
607f29dbc25Smrg
608f29dbc25Smrg    /* XXX - I don't understand PICT_a8 enough - so I'm punting */
609170d5fdcSmrg    if ((op != PictOpAdd) && (pSrc->format == PICT_a8 ||
61004007ebaSmrg                              pDst->format == PICT_a8))
61104007ebaSmrg        GEODE_FALLBACK(("PICT_a8 as src or dst format is unsupported\n"));
612f29dbc25Smrg
613f29dbc25Smrg    if (pMsk && op != PictOpClear) {
61404007ebaSmrg        struct blend_ops_t *opPtr = &lx_alpha_ops[op * 2];
61504007ebaSmrg        int direction = (opPtr->channel == CIMGP_CHANNEL_A_SOURCE) ? 0 : 1;
61604007ebaSmrg
61704007ebaSmrg        /* Direction 0 indicates src->dst, 1 indicates dst->src */
61804007ebaSmrg        if (((direction == 0) &&
61904007ebaSmrg             (pSrc->pDrawable && pSrc->pDrawable->bitsPerPixel < 16)) ||
62004007ebaSmrg            ((direction == 1) && (pDst->pDrawable->bitsPerPixel < 16))) {
62104007ebaSmrg            ErrorF("Mask blending unsupported with <16bpp\n");
62204007ebaSmrg            return FALSE;
62304007ebaSmrg        }
62404007ebaSmrg        if (pMsk->format != PICT_a8 && pMsk->format != PICT_a4)
62504007ebaSmrg            GEODE_FALLBACK(("Masks can be only done with a 8bpp or 4bpp depth\n"));
62604007ebaSmrg
62704007ebaSmrg        /* The pSrc should be 1x1 pixel if the pMsk is not zero */
62804007ebaSmrg        if (pSrc->pDrawable &&
62904007ebaSmrg            (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1))
63004007ebaSmrg            GEODE_FALLBACK(("pSrc should be 1x1 pixel if pMsk is not zero\n"));
63104007ebaSmrg        /* FIXME: In lx_prepare_composite, there are no variables to record the
63204007ebaSmrg         * one pixel source's width and height when the mask is not zero.
63304007ebaSmrg         * That will lead to bigger region to render instead of one pixel in lx
63404007ebaSmrg         * _do_composite, so we should fallback currently to avoid this */
63504007ebaSmrg        /* Not an issue for solid pictures, because we'll treat it as 1x1R too */
63604007ebaSmrg        if (!pSrc->repeat &&
63704007ebaSmrg            !(pSrc->pSourcePict &&
63804007ebaSmrg              pSrc->pSourcePict->type == SourcePictTypeSolidFill)) {
63904007ebaSmrg            GEODE_FALLBACK(("FIXME: unzero mask might lead to bigger rendering region than 1x1 pixels\n"));
64004007ebaSmrg        }
64104007ebaSmrg    }
64204007ebaSmrg    else {
64304007ebaSmrg        if (pSrc->pSourcePict)
64404007ebaSmrg            GEODE_FALLBACK(("Solid source pictures without a mask are not supported\n"));
645f29dbc25Smrg    }
646f29dbc25Smrg
647f29dbc25Smrg    /* Get the formats for the source and destination */
648f29dbc25Smrg
64904007ebaSmrg    if ((srcFmt = lx_get_format(pSrc)) == NULL)
65004007ebaSmrg        GEODE_FALLBACK(("Unsupported source format %x\n", pSrc->format));
651f29dbc25Smrg
65204007ebaSmrg    if ((dstFmt = lx_get_format(pDst)) == NULL)
65304007ebaSmrg        GEODE_FALLBACK(("Unsupported destination format %x\n", pDst->format));
654f29dbc25Smrg
655f29dbc25Smrg    /* Make sure operations that need alpha bits have them */
656f29dbc25Smrg    /* If a mask is enabled, the alpha will come from there */
657f29dbc25Smrg
658f29dbc25Smrg    if (!pMsk && (!srcFmt->alphabits && usesSrcAlpha(op)))
65904007ebaSmrg        GEODE_FALLBACK(("Operation requires src alpha, but alphabits is unset\n"));
660f29dbc25Smrg
661f29dbc25Smrg    if (!pMsk && (!dstFmt->alphabits && usesDstAlpha(op)))
66204007ebaSmrg        GEODE_FALLBACK(("Operation requires dst alpha, but alphabits is unset\n"));
663f29dbc25Smrg
66404007ebaSmrg    /* FIXME: See a way around this! */
665f29dbc25Smrg    if (srcFmt->alphabits == 0 && dstFmt->alphabits != 0)
66604007ebaSmrg        GEODE_FALLBACK(("src_alphabits=0, dst_alphabits!=0\n"));
667f29dbc25Smrg
668f29dbc25Smrg    /* If this is a rotate operation, then make sure the src and dst
669f29dbc25Smrg     * formats are the same */
670f29dbc25Smrg    if (exaScratch.rotate != RR_Rotate_0 && srcFmt != dstFmt) {
67104007ebaSmrg        ErrorF("EXA: Unable to rotate and convert formats at the same time\n");
67204007ebaSmrg        return FALSE;
673f29dbc25Smrg    }
674170d5fdcSmrg    return TRUE;
675170d5fdcSmrg}
676170d5fdcSmrg
677170d5fdcSmrgstatic Bool
678170d5fdcSmrglx_prepare_composite(int op, PicturePtr pSrc, PicturePtr pMsk,
67904007ebaSmrg                     PicturePtr pDst, PixmapPtr pxSrc, PixmapPtr pxMsk,
68004007ebaSmrg                     PixmapPtr pxDst)
681170d5fdcSmrg{
682170d5fdcSmrg    GeodeRec *pGeode = GEODEPTR_FROM_PIXMAP(pxDst);
683170d5fdcSmrg    const struct exa_format_t *srcFmt, *dstFmt;
684170d5fdcSmrg
685170d5fdcSmrg    /* Get the formats for the source and destination */
686170d5fdcSmrg
687170d5fdcSmrg    srcFmt = lx_get_format(pSrc);
688170d5fdcSmrg    dstFmt = lx_get_format(pDst);
689f29dbc25Smrg
690f29dbc25Smrg    /* Set up the scratch buffer with the information we need */
691f29dbc25Smrg
69204007ebaSmrg    exaScratch.srcFormat = (struct exa_format_t *) srcFmt;
69304007ebaSmrg    exaScratch.dstFormat = (struct exa_format_t *) dstFmt;
694f29dbc25Smrg    exaScratch.op = op;
695f29dbc25Smrg    exaScratch.repeat = pSrc->repeat;
696f29dbc25Smrg    exaScratch.bufferOffset = pGeode->exaBfrOffset;
697f29dbc25Smrg
698f29dbc25Smrg    if (pMsk && op != PictOpClear) {
69904007ebaSmrg        /* Get the source color */
70004007ebaSmrg        if (pSrc->pSourcePict) {
70104007ebaSmrg            exaScratch.srcColor = pSrc->pSourcePict->solidFill.color;
70204007ebaSmrg        }
70304007ebaSmrg        else {
70404007ebaSmrg            /* If the op is PictOpOver(or PictOpOutReverse, PictOpInReverse,
70504007ebaSmrg             * PictOpIn, PictOpOut, PictOpOverReverse), we should get the
70604007ebaSmrg             * ARGB32 source format */
70704007ebaSmrg
70804007ebaSmrg            if ((op == PictOpOver || op == PictOpOutReverse || op ==
70904007ebaSmrg                 PictOpInReverse || op == PictOpIn || op == PictOpOut ||
71004007ebaSmrg                 op == PictOpOverReverse) && (srcFmt->alphabits != 0))
71104007ebaSmrg                exaScratch.srcColor = exaGetPixmapFirstPixel(pxSrc);
71204007ebaSmrg            else if ((op == PictOpOver || op == PictOpOutReverse || op ==
71304007ebaSmrg                      PictOpInReverse || op == PictOpIn || op == PictOpOut ||
71404007ebaSmrg                      op == PictOpOverReverse) && (srcFmt->alphabits == 0))
71504007ebaSmrg                exaScratch.srcColor = lx_get_source_color(pxSrc, pSrc->format,
71604007ebaSmrg                                                          PICT_a8r8g8b8);
71704007ebaSmrg            else
71804007ebaSmrg                exaScratch.srcColor = lx_get_source_color(pxSrc, pSrc->format,
71904007ebaSmrg                                                          pDst->format);
72004007ebaSmrg        }
72104007ebaSmrg
72204007ebaSmrg        /* Save off the info we need (reuse the source values to save space) */
72304007ebaSmrg        exaScratch.type = COMP_TYPE_MASK;
72404007ebaSmrg        exaScratch.maskrepeat = pMsk->repeat;
72504007ebaSmrg
72604007ebaSmrg        exaScratch.srcOffset = exaGetPixmapOffset(pxMsk);
72704007ebaSmrg        exaScratch.srcPitch = exaGetPixmapPitch(pxMsk);
72804007ebaSmrg        exaScratch.srcBpp = (pxMsk->drawable.bitsPerPixel + 7) / 8;
72904007ebaSmrg
73004007ebaSmrg        exaScratch.srcWidth = pMsk->pDrawable->width;
73104007ebaSmrg        exaScratch.srcHeight = pMsk->pDrawable->height;
73204007ebaSmrg
73304007ebaSmrg        /* Flag to indicate if this a 8BPP or a 4BPP mask */
73404007ebaSmrg        exaScratch.fourBpp = (pxMsk->drawable.bitsPerPixel == 4) ? 1 : 0;
73504007ebaSmrg    }
73604007ebaSmrg    else {
73704007ebaSmrg        if (usesPasses(op))
73804007ebaSmrg            exaScratch.type = COMP_TYPE_TWOPASS;
73904007ebaSmrg        else if (exaScratch.rotate != RR_Rotate_0)
74004007ebaSmrg            exaScratch.type = COMP_TYPE_ROTATE;
74104007ebaSmrg        else
74204007ebaSmrg            exaScratch.type = COMP_TYPE_ONEPASS;
74304007ebaSmrg
74404007ebaSmrg        exaScratch.srcOffset = exaGetPixmapOffset(pxSrc);
74504007ebaSmrg        exaScratch.srcPitch = exaGetPixmapPitch(pxSrc);
74604007ebaSmrg        exaScratch.srcBpp = (pxSrc->drawable.bitsPerPixel + 7) / 8;
74704007ebaSmrg
74804007ebaSmrg        exaScratch.srcWidth = pSrc->pDrawable->width;
74904007ebaSmrg        exaScratch.srcHeight = pSrc->pDrawable->height;
750f29dbc25Smrg    }
751f29dbc25Smrg
752f29dbc25Smrg    return TRUE;
753f29dbc25Smrg}
754f29dbc25Smrg
755f29dbc25Smrgstatic int
756f29dbc25Smrglx_get_bpp_from_format(int format)
757f29dbc25Smrg{
758f29dbc25Smrg
759f29dbc25Smrg    switch (format) {
760f29dbc25Smrg    case CIMGP_SOURCE_FMT_8_8_8_8:
761f29dbc25Smrg    case CIMGP_SOURCE_FMT_32BPP_BGR:
76204007ebaSmrg        return 32;
763f29dbc25Smrg
764f29dbc25Smrg    case CIMGP_SOURCE_FMT_4_4_4_4:
76504007ebaSmrg        return 12;
766f29dbc25Smrg
767f29dbc25Smrg    case CIMGP_SOURCE_FMT_0_5_6_5:
768f29dbc25Smrg    case CIMGP_SOURCE_FMT_16BPP_BGR:
76904007ebaSmrg        return 16;
770f29dbc25Smrg
771f29dbc25Smrg    case CIMGP_SOURCE_FMT_1_5_5_5:
772f29dbc25Smrg    case CIMGP_SOURCE_FMT_15BPP_BGR:
77304007ebaSmrg        return 15;
774f29dbc25Smrg
775f29dbc25Smrg    case CIMGP_SOURCE_FMT_3_3_2:
77604007ebaSmrg        return 8;
777f29dbc25Smrg    }
778f29dbc25Smrg
779f29dbc25Smrg    return 0;
780f29dbc25Smrg}
781f29dbc25Smrg
782f29dbc25Smrg/* BGR needs to be set in the source for it to take - so adjust the source
783f29dbc25Smrg * to enable BGR if the two formats are different, and disable it if they
784f29dbc25Smrg * are the same
785f29dbc25Smrg */
786f29dbc25Smrg
787f29dbc25Smrgstatic void
788f29dbc25Smrglx_set_source_format(int srcFormat, int dstFormat)
789f29dbc25Smrg{
790f29dbc25Smrg    if (!(srcFormat & 0x10) && (dstFormat & 0x10))
79104007ebaSmrg        gp_set_source_format(srcFormat | 0x10);
792f29dbc25Smrg    else if ((srcFormat & 0x10) && (dstFormat & 0x10))
79304007ebaSmrg        gp_set_source_format(srcFormat & ~0x10);
794f29dbc25Smrg    else
79504007ebaSmrg        gp_set_source_format(srcFormat);
796f29dbc25Smrg}
797f29dbc25Smrg
798f29dbc25Smrg/* If we are converting colors and we need the channel A alpha,
799f29dbc25Smrg * then use a special alpha type that preserves the alpha before
800f29dbc25Smrg * converting the format
801f29dbc25Smrg */
802f29dbc25Smrg
803f29dbc25Smrgstatic inline int
804f29dbc25Smrgget_op_type(struct exa_format_t *src, struct exa_format_t *dst, int type)
805f29dbc25Smrg{
806f29dbc25Smrg    return (type == CIMGP_CHANNEL_A_ALPHA &&
80704007ebaSmrg            src->alphabits != dst->alphabits) ? CIMGP_CONVERTED_ALPHA : type;
808f29dbc25Smrg}
809f29dbc25Smrg
810f29dbc25Smrg/* Note - this is the preferred onepass method.  The other will remain
811f29dbc25Smrg * ifdefed out until such time that we are sure its not needed
812f29dbc25Smrg */
813f29dbc25Smrg
814170d5fdcSmrg#define GetPixmapOffset(px, x, y) ( exaGetPixmapOffset((px)) + \
815170d5fdcSmrg  (exaGetPixmapPitch((px)) * (y)) + \
816170d5fdcSmrg  ((((px)->drawable.bitsPerPixel + 7) / 8) * (x)) )
817170d5fdcSmrg
818170d5fdcSmrg#define GetSrcOffset(_x, _y) (exaScratch.srcOffset + ((_y) * exaScratch.srcPitch) + \
819170d5fdcSmrg			      ((_x) * exaScratch.srcBpp))
820170d5fdcSmrg
821170d5fdcSmrgstatic void
822170d5fdcSmrglx_composite_onepass_add_a8(PixmapPtr pxDst, unsigned long dstOffset,
82304007ebaSmrg                            unsigned long srcOffset, int width, int height,
82404007ebaSmrg                            int opX, int opY, int srcX, int srcY)
825170d5fdcSmrg{
826170d5fdcSmrg    struct blend_ops_t *opPtr;
827170d5fdcSmrg    int apply, type;
828170d5fdcSmrg    int optempX, optempY;
829170d5fdcSmrg    int i, j;
830170d5fdcSmrg    unsigned long pixmapOffset, pixmapPitch, calBitsPixel;
831170d5fdcSmrg
832170d5fdcSmrg    pixmapOffset = exaGetPixmapOffset(pxDst);
833170d5fdcSmrg    pixmapPitch = exaGetPixmapPitch(pxDst);
834170d5fdcSmrg    calBitsPixel = (pxDst->drawable.bitsPerPixel + 7) / 8;
835170d5fdcSmrg
836170d5fdcSmrg    /* Keep this GP idle judge here. Otherwise the SW method has chance to
837170d5fdcSmrg     * conflict with the HW rendering method */
838170d5fdcSmrg    gp_wait_until_idle();
839170d5fdcSmrg
840170d5fdcSmrg    if (opX % 4 == 0 && srcX % 4 == 0) {
84104007ebaSmrg        /* HW acceleration */
84204007ebaSmrg        opPtr = &lx_alpha_ops[exaScratch.op * 2];
84304007ebaSmrg        apply = CIMGP_APPLY_BLEND_TO_ALL;
84404007ebaSmrg        gp_declare_blt(0);
84504007ebaSmrg        gp_set_bpp(32);
84604007ebaSmrg        gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
84704007ebaSmrg        gp_set_source_format(8);
84804007ebaSmrg        type = opPtr->type;
84904007ebaSmrg        gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply,
85004007ebaSmrg                               0);
85104007ebaSmrg        gp_screen_to_screen_convert(dstOffset, srcOffset, width / 4, height, 0);
85204007ebaSmrg        /* Calculate the pixels in the tail of each line */
85304007ebaSmrg        for (j = srcY; j < srcY + height; j++)
85404007ebaSmrg            for (i = srcX + (width / 4) * 4; i < srcX + width; i++) {
85504007ebaSmrg                srcOffset = GetSrcOffset(i, j);
85604007ebaSmrg                optempX = opX + i - srcX;
85704007ebaSmrg                optempY = opY + j - srcY;
85804007ebaSmrg                dstOffset = pixmapOffset + pixmapPitch * optempY +
85904007ebaSmrg                    calBitsPixel * optempX;
86004007ebaSmrg                *(cim_fb_ptr + dstOffset) = (*(cim_fb_ptr + srcOffset)
86104007ebaSmrg                                             + *(cim_fb_ptr + dstOffset) <=
86204007ebaSmrg                                             0xff) ? *(cim_fb_ptr + srcOffset) +
86304007ebaSmrg                    *(cim_fb_ptr + dstOffset) : 0xff;
86404007ebaSmrg            }
86504007ebaSmrg    }
86604007ebaSmrg    else {
86704007ebaSmrg        for (j = srcY; j < srcY + height; j++)
86804007ebaSmrg            for (i = srcX; i < srcX + width; i++) {
86904007ebaSmrg                srcOffset = GetSrcOffset(i, j);
87004007ebaSmrg                optempX = opX + i - srcX;
87104007ebaSmrg                optempY = opY + j - srcY;
87204007ebaSmrg                dstOffset = pixmapOffset + pixmapPitch * optempY +
87304007ebaSmrg                    calBitsPixel * optempX;
87404007ebaSmrg                *(cim_fb_ptr + dstOffset) = (*(cim_fb_ptr + srcOffset) +
87504007ebaSmrg                                             *(cim_fb_ptr + dstOffset) <=
87604007ebaSmrg                                             0xff) ? *(cim_fb_ptr + srcOffset) +
87704007ebaSmrg                    *(cim_fb_ptr + dstOffset) : 0xff;
87804007ebaSmrg            }
879170d5fdcSmrg    }
880170d5fdcSmrg}
881170d5fdcSmrg
882f29dbc25Smrgstatic void
883f29dbc25Smrglx_composite_onepass(PixmapPtr pxDst, unsigned long dstOffset,
88404007ebaSmrg                     unsigned long srcOffset, int width, int height)
885f29dbc25Smrg{
886f29dbc25Smrg    struct blend_ops_t *opPtr;
887f29dbc25Smrg    int apply, type;
888f29dbc25Smrg
889f29dbc25Smrg    opPtr = &lx_alpha_ops[exaScratch.op * 2];
890f29dbc25Smrg
891f29dbc25Smrg    apply = (exaScratch.dstFormat->alphabits != 0 &&
89204007ebaSmrg             exaScratch.srcFormat->alphabits != 0) ?
89304007ebaSmrg        CIMGP_APPLY_BLEND_TO_ALL : CIMGP_APPLY_BLEND_TO_RGB;
894f29dbc25Smrg
895f29dbc25Smrg    gp_declare_blt(0);
896f29dbc25Smrg    gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
897f29dbc25Smrg    gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
898f29dbc25Smrg
89904007ebaSmrg    lx_set_source_format(exaScratch.srcFormat->fmt, exaScratch.dstFormat->fmt);
900f29dbc25Smrg
90104007ebaSmrg    type = get_op_type(exaScratch.srcFormat, exaScratch.dstFormat, opPtr->type);
902f29dbc25Smrg
903f29dbc25Smrg    gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0);
904f29dbc25Smrg
905f29dbc25Smrg    gp_screen_to_screen_convert(dstOffset, srcOffset, width, height, 0);
906f29dbc25Smrg}
907f29dbc25Smrg
908170d5fdcSmrgstatic void
909170d5fdcSmrglx_composite_all_black(unsigned long srcOffset, int width, int height)
910170d5fdcSmrg{
911170d5fdcSmrg    struct blend_ops_t *opPtr;
912170d5fdcSmrg    int apply, type;
913170d5fdcSmrg
914170d5fdcSmrg    opPtr = &lx_alpha_ops[0];
915170d5fdcSmrg    apply = (exaScratch.srcFormat->alphabits != 0) ?
91604007ebaSmrg        CIMGP_APPLY_BLEND_TO_ALL : CIMGP_APPLY_BLEND_TO_RGB;
917170d5fdcSmrg    gp_declare_blt(0);
918170d5fdcSmrg    gp_set_bpp(lx_get_bpp_from_format(exaScratch.srcFormat->fmt));
919170d5fdcSmrg    gp_set_strides(exaScratch.srcPitch, exaScratch.srcPitch);
92004007ebaSmrg    lx_set_source_format(exaScratch.srcFormat->fmt, exaScratch.srcFormat->fmt);
92104007ebaSmrg    type = get_op_type(exaScratch.srcFormat, exaScratch.srcFormat, opPtr->type);
922170d5fdcSmrg    gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0);
923170d5fdcSmrg    gp_screen_to_screen_convert(srcOffset, srcOffset, width, height, 0);
924170d5fdcSmrg
925170d5fdcSmrg}
926170d5fdcSmrg
927170d5fdcSmrgstatic void
928170d5fdcSmrglx_composite_onepass_special(PixmapPtr pxDst, int width, int height, int opX,
92904007ebaSmrg                             int opY, int srcX, int srcY)
930170d5fdcSmrg{
931170d5fdcSmrg    struct blend_ops_t *opPtr;
932170d5fdcSmrg    int apply, type;
933170d5fdcSmrg    int opWidth, opHeight;
934170d5fdcSmrg    int optempX, optempY;
935170d5fdcSmrg    unsigned int dstOffset, srcOffset = 0;
936170d5fdcSmrg
937170d5fdcSmrg    optempX = opX;
938170d5fdcSmrg    optempY = opY;
939170d5fdcSmrg
940170d5fdcSmrg    /* Make sure srcX and srcY are in source region */
94104007ebaSmrg    srcX = ((srcX % (int) exaScratch.srcWidth) + (int) exaScratch.srcWidth)
94204007ebaSmrg        % (int) exaScratch.srcWidth;
94304007ebaSmrg    srcY = ((srcY % (int) exaScratch.srcHeight) + (int) exaScratch.srcHeight)
94404007ebaSmrg        % (int) exaScratch.srcHeight;
945170d5fdcSmrg
946170d5fdcSmrg    opWidth = exaScratch.srcWidth - srcX;
94704007ebaSmrg    opHeight = exaScratch.srcHeight - srcY;
948170d5fdcSmrg
949170d5fdcSmrg    srcOffset = GetSrcOffset(srcX, srcY);
950170d5fdcSmrg
951170d5fdcSmrg    if (width < opWidth)
95204007ebaSmrg        opWidth = width;
953170d5fdcSmrg    if (height < opHeight)
95404007ebaSmrg        opHeight = height;
955170d5fdcSmrg
956170d5fdcSmrg    while (1) {
95704007ebaSmrg        gp_wait_until_idle();
95804007ebaSmrg        dstOffset = GetPixmapOffset(pxDst, optempX, optempY);
95904007ebaSmrg        opPtr = &lx_alpha_ops[exaScratch.op * 2];
96004007ebaSmrg        apply = (exaScratch.dstFormat->alphabits != 0 &&
96104007ebaSmrg                 exaScratch.srcFormat->alphabits != 0) ?
96204007ebaSmrg            CIMGP_APPLY_BLEND_TO_ALL : CIMGP_APPLY_BLEND_TO_RGB;
96304007ebaSmrg        gp_declare_blt(0);
96404007ebaSmrg        gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
96504007ebaSmrg        gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
96604007ebaSmrg        lx_set_source_format(exaScratch.srcFormat->fmt,
96704007ebaSmrg                             exaScratch.dstFormat->fmt);
96804007ebaSmrg        type = get_op_type(exaScratch.srcFormat, exaScratch.dstFormat,
96904007ebaSmrg                           opPtr->type);
97004007ebaSmrg        gp_set_alpha_operation(opPtr->operation, type, opPtr->channel,
97104007ebaSmrg                               apply, 0);
97204007ebaSmrg        gp_screen_to_screen_convert(dstOffset, srcOffset, opWidth, opHeight, 0);
97304007ebaSmrg
97404007ebaSmrg        optempX += opWidth;
97504007ebaSmrg        if (optempX >= opX + width) {
97604007ebaSmrg            optempX = opX;
97704007ebaSmrg            optempY += opHeight;
97804007ebaSmrg            if (optempY >= opY + height)
97904007ebaSmrg                break;
98004007ebaSmrg        }
98104007ebaSmrg        if (optempX == opX) {
98204007ebaSmrg            srcOffset = GetSrcOffset(srcX, 0);
98304007ebaSmrg            opWidth = ((opX + width) - optempX) > (exaScratch.srcWidth - srcX)
98404007ebaSmrg                ? (exaScratch.srcWidth - srcX) : ((opX + width) - optempX);
98504007ebaSmrg            opHeight = ((opY + height) - optempY) > exaScratch.srcHeight
98604007ebaSmrg                ? exaScratch.srcHeight : ((opY + height) - optempY);
98704007ebaSmrg        }
98804007ebaSmrg        else if (optempY == opY) {
98904007ebaSmrg            srcOffset = GetSrcOffset(0, srcY);
99004007ebaSmrg            opWidth = ((opX + width) - optempX) > exaScratch.srcWidth
99104007ebaSmrg                ? exaScratch.srcWidth : ((opX + width) - optempX);
99204007ebaSmrg            opHeight = ((opY + height) - optempY) > (exaScratch.srcHeight -
99304007ebaSmrg                                                     srcY)
99404007ebaSmrg                ? (exaScratch.srcHeight - srcY) : ((opY + height)
99504007ebaSmrg                                                   - optempY);
99604007ebaSmrg        }
99704007ebaSmrg        else {
99804007ebaSmrg            srcOffset = GetSrcOffset(0, 0);
99904007ebaSmrg            opWidth = ((opX + width) - optempX) > exaScratch.srcWidth
100004007ebaSmrg                ? exaScratch.srcWidth : ((opX + width) - optempX);
100104007ebaSmrg            opHeight = ((opY + height) - optempY) > exaScratch.srcHeight
100204007ebaSmrg                ? exaScratch.srcHeight : ((opY + height) - optempY);
100304007ebaSmrg        }
1004170d5fdcSmrg    }
1005170d5fdcSmrg}
1006170d5fdcSmrg
1007f29dbc25Smrg/* This function handles the multipass blend functions */
1008f29dbc25Smrg
1009f29dbc25Smrgstatic void
1010f29dbc25Smrglx_composite_multipass(PixmapPtr pxDst, unsigned long dstOffset,
101104007ebaSmrg                       unsigned long srcOffset, int width, int height)
1012f29dbc25Smrg{
1013f29dbc25Smrg    struct blend_ops_t *opPtr;
1014f29dbc25Smrg    int sbpp = lx_get_bpp_from_format(exaScratch.srcFormat->fmt);
1015f29dbc25Smrg    int apply, type;
1016f29dbc25Smrg
1017f29dbc25Smrg    /* Wait until the GP is idle - this will ensure that the scratch buffer
1018f29dbc25Smrg     * isn't occupied */
1019f29dbc25Smrg
1020f29dbc25Smrg    gp_wait_until_idle();
1021f29dbc25Smrg
1022f29dbc25Smrg    /* Copy the destination to the scratch buffer, and convert it to the
1023f29dbc25Smrg     * source format */
1024f29dbc25Smrg
1025f29dbc25Smrg    gp_declare_blt(0);
1026f29dbc25Smrg
1027f29dbc25Smrg    gp_set_bpp(sbpp);
1028f29dbc25Smrg    gp_set_source_format(exaScratch.dstFormat->fmt);
1029f29dbc25Smrg    gp_set_raster_operation(0xCC);
1030f29dbc25Smrg    gp_set_strides(exaScratch.srcPitch, exaGetPixmapPitch(pxDst));
1031f29dbc25Smrg    gp_screen_to_screen_convert(exaScratch.bufferOffset, dstOffset,
103204007ebaSmrg                                width, height, 0);
1033f29dbc25Smrg
1034f29dbc25Smrg    /* Do the first blend from the source to the scratch buffer */
1035f29dbc25Smrg
1036f29dbc25Smrg    gp_declare_blt(CIMGP_BLTFLAGS_HAZARD);
1037f29dbc25Smrg    gp_set_bpp(sbpp);
1038f29dbc25Smrg    gp_set_source_format(exaScratch.srcFormat->fmt);
1039f29dbc25Smrg    gp_set_strides(exaScratch.srcPitch, exaScratch.srcPitch);
1040f29dbc25Smrg
1041f29dbc25Smrg    opPtr = &lx_alpha_ops[exaScratch.op * 2];
1042f29dbc25Smrg
1043f29dbc25Smrg    apply = (exaScratch.srcFormat->alphabits == 0) ?
104404007ebaSmrg        CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL;
1045f29dbc25Smrg
1046f29dbc25Smrg    /* If we're destroying the source alpha bits, then make sure we
1047f29dbc25Smrg     * use the alpha before the color conversion
1048f29dbc25Smrg     */
1049f29dbc25Smrg
1050f29dbc25Smrg    gp_screen_to_screen_blt(exaScratch.bufferOffset, srcOffset, width, height,
105104007ebaSmrg                            0);
1052f29dbc25Smrg
1053f29dbc25Smrg    /* Finally, do the second blend back to the destination */
1054f29dbc25Smrg
1055f29dbc25Smrg    opPtr = &lx_alpha_ops[(exaScratch.op * 2) + 1];
1056f29dbc25Smrg
1057f29dbc25Smrg    apply = (exaScratch.dstFormat->alphabits == 0) ?
105804007ebaSmrg        CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL;
1059f29dbc25Smrg
1060f29dbc25Smrg    gp_declare_blt(CIMGP_BLTFLAGS_HAZARD);
1061f29dbc25Smrg    gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
1062f29dbc25Smrg
106304007ebaSmrg    lx_set_source_format(exaScratch.srcFormat->fmt, exaScratch.dstFormat->fmt);
1064f29dbc25Smrg
106504007ebaSmrg    type = get_op_type(exaScratch.srcFormat, exaScratch.dstFormat, opPtr->type);
1066f29dbc25Smrg
1067f29dbc25Smrg    gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0);
1068f29dbc25Smrg
1069f29dbc25Smrg    gp_screen_to_screen_convert(dstOffset, exaScratch.bufferOffset,
107004007ebaSmrg                                width, height, 0);
1071f29dbc25Smrg}
1072f29dbc25Smrg
1073f29dbc25Smrgstatic void
1074f29dbc25Smrglx_composite_rotate(PixmapPtr pxDst, unsigned long dstOffset,
107504007ebaSmrg                    unsigned int srcOffset, int width, int height)
1076f29dbc25Smrg{
1077f29dbc25Smrg    int degrees = 0;
1078f29dbc25Smrg
1079f29dbc25Smrg    gp_declare_blt(0);
1080f29dbc25Smrg    gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
1081f29dbc25Smrg    gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
1082f29dbc25Smrg
108304007ebaSmrg    lx_set_source_format(exaScratch.srcFormat->fmt, exaScratch.dstFormat->fmt);
1084f29dbc25Smrg
1085f29dbc25Smrg    gp_set_raster_operation(0xCC);
1086f29dbc25Smrg
1087f29dbc25Smrg    /* RandR rotation is counter-clockwise, our rotation
1088f29dbc25Smrg     * is clockwise, so adjust the numbers accordingly */
1089f29dbc25Smrg
1090f29dbc25Smrg    switch (exaScratch.rotate) {
1091f29dbc25Smrg    case RR_Rotate_90:
109204007ebaSmrg        degrees = 270;
109304007ebaSmrg        break;
1094f29dbc25Smrg    case RR_Rotate_180:
109504007ebaSmrg        degrees = 180;
109604007ebaSmrg        break;
1097f29dbc25Smrg    case RR_Rotate_270:
109804007ebaSmrg        degrees = 90;
109904007ebaSmrg        break;
1100f29dbc25Smrg    }
1101f29dbc25Smrg
1102f29dbc25Smrg    gp_rotate_blt(dstOffset, srcOffset, width, height, degrees);
1103f29dbc25Smrg}
1104f29dbc25Smrg
1105f29dbc25Smrgstatic void
1106f29dbc25Smrglx_do_composite_mask(PixmapPtr pxDst, unsigned long dstOffset,
110704007ebaSmrg                     unsigned int maskOffset, int width, int height)
1108f29dbc25Smrg{
1109f29dbc25Smrg    struct blend_ops_t *opPtr = &lx_alpha_ops[exaScratch.op * 2];
1110f29dbc25Smrg
1111f29dbc25Smrg    gp_declare_blt(0);
1112f29dbc25Smrg
1113f29dbc25Smrg    gp_set_source_format(exaScratch.srcFormat->fmt);
1114f29dbc25Smrg    gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
1115f29dbc25Smrg    gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
1116f29dbc25Smrg    gp_set_solid_source(exaScratch.srcColor);
1117f29dbc25Smrg
1118f29dbc25Smrg    gp_blend_mask_blt(dstOffset, 0, width, height, maskOffset,
111904007ebaSmrg                      exaScratch.srcPitch, opPtr->operation,
112004007ebaSmrg                      exaScratch.fourBpp);
1121f29dbc25Smrg}
1122f29dbc25Smrg
1123170d5fdcSmrgstatic void
1124170d5fdcSmrglx_do_composite_mask_two_pass(PixmapPtr pxDst, unsigned long dstOffset,
112504007ebaSmrg                              unsigned int maskOffset, int width, int height,
112604007ebaSmrg                              int opX, int opY, xPointFixed srcPoint)
1127170d5fdcSmrg{
1128170d5fdcSmrg    int apply, type;
1129170d5fdcSmrg    struct blend_ops_t *opPtr;
1130170d5fdcSmrg    int opWidth, opHeight;
1131170d5fdcSmrg    int opoverX, opoverY;
1132170d5fdcSmrg
1133170d5fdcSmrg    opoverX = opX;
1134170d5fdcSmrg    opoverY = opY;
1135170d5fdcSmrg
1136170d5fdcSmrg    /* The rendering region should not be bigger than off-screen memory size
1137170d5fdcSmrg     * which equals to DEFAULT_EXA_SCRATCH_BFRSZ. If that happens, we split
1138170d5fdcSmrg     * the PictOpOver rendering region into several 256KB chunks. And because
1139170d5fdcSmrg     * of the Pitch(stride) parameter, so we use maximun width of mask picture.
1140170d5fdcSmrg     * that is to say it is a scanline rendering process */
1141170d5fdcSmrg    if (width * height * 4 > DEFAULT_EXA_SCRATCH_BFRSZ) {
114204007ebaSmrg        opWidth = width;
114304007ebaSmrg        opHeight = DEFAULT_EXA_SCRATCH_BFRSZ / (width * 4);
114404007ebaSmrg    }
114504007ebaSmrg    else {
114604007ebaSmrg        opWidth = width;
114704007ebaSmrg        opHeight = height;
1148170d5fdcSmrg    }
1149f29dbc25Smrg
1150170d5fdcSmrg    while (1) {
1151170d5fdcSmrg
115204007ebaSmrg        /* Wait until the GP is idle - this will ensure that the scratch buffer
115304007ebaSmrg         * isn't occupied */
115404007ebaSmrg
115504007ebaSmrg        gp_wait_until_idle();
115604007ebaSmrg
115704007ebaSmrg        /* Copy the source to the scratch buffer, and do a src * mask raster
115804007ebaSmrg         * operation */
115904007ebaSmrg
116004007ebaSmrg        gp_declare_blt(0);
116104007ebaSmrg        opPtr = &lx_alpha_ops[(exaScratch.op * 2) + 1];
116204007ebaSmrg        gp_set_source_format(CIMGP_SOURCE_FMT_8_8_8_8);
116304007ebaSmrg        gp_set_strides(opWidth * 4, exaScratch.srcPitch);
116404007ebaSmrg        gp_set_bpp(lx_get_bpp_from_format(CIMGP_SOURCE_FMT_8_8_8_8));
116504007ebaSmrg        gp_set_solid_source(exaScratch.srcColor);
116604007ebaSmrg        gp_blend_mask_blt(exaScratch.bufferOffset, 0, opWidth, opHeight,
116704007ebaSmrg                          maskOffset, exaScratch.srcPitch, opPtr->operation,
116804007ebaSmrg                          exaScratch.fourBpp);
116904007ebaSmrg
117004007ebaSmrg        /* Do a relative operation(refer rendercheck ops.c), and copy the
117104007ebaSmrg         * operation result to destination */
117204007ebaSmrg
117304007ebaSmrg        gp_declare_blt(CIMGP_BLTFLAGS_HAZARD);
117404007ebaSmrg        opPtr = &lx_alpha_ops[exaScratch.op * 2];
117504007ebaSmrg        apply = (exaScratch.dstFormat->alphabits == 0) ?
117604007ebaSmrg            CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL;
117704007ebaSmrg        gp_set_source_format(CIMGP_SOURCE_FMT_8_8_8_8);
117804007ebaSmrg        gp_set_strides(exaGetPixmapPitch(pxDst), opWidth * 4);
117904007ebaSmrg        gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
118004007ebaSmrg        type = CIMGP_CONVERTED_ALPHA;
118104007ebaSmrg        gp_set_alpha_operation(opPtr->operation, type, opPtr->channel,
118204007ebaSmrg                               apply, 0);
118304007ebaSmrg        gp_screen_to_screen_convert(dstOffset, exaScratch.bufferOffset,
118404007ebaSmrg                                    opWidth, opHeight, 0);
118504007ebaSmrg
118604007ebaSmrg        if (width * height * 4 > DEFAULT_EXA_SCRATCH_BFRSZ) {
118704007ebaSmrg            /* Finish the rendering */
118804007ebaSmrg            if (opoverY + opHeight == opY + height)
118904007ebaSmrg                break;
119004007ebaSmrg            /* Recalculate the Dest and Mask rendering start point */
119104007ebaSmrg            srcPoint.y = srcPoint.y + F(opHeight);
119204007ebaSmrg            opoverY = opoverY + opHeight;
119304007ebaSmrg            if (opoverY + opHeight > opY + height)
119404007ebaSmrg                opHeight = opY + height - opoverY;
119504007ebaSmrg            dstOffset = GetPixmapOffset(pxDst, opoverX, opoverY);
119604007ebaSmrg            maskOffset = GetSrcOffset(I(srcPoint.x), I(srcPoint.y));
119704007ebaSmrg        }
119804007ebaSmrg        else
119904007ebaSmrg            break;
1200170d5fdcSmrg    }
1201170d5fdcSmrg}
1202f29dbc25Smrg
1203f29dbc25Smrgstatic void
1204f29dbc25SmrgtransformPoint(PictTransform * t, xPointFixed * point)
1205f29dbc25Smrg{
1206f29dbc25Smrg    PictVector v;
1207f29dbc25Smrg
1208f29dbc25Smrg    v.vector[0] = point->x;
1209f29dbc25Smrg    v.vector[1] = point->y;
1210f29dbc25Smrg    v.vector[2] = xFixed1;
1211f29dbc25Smrg
1212f29dbc25Smrg    if (t != NULL)
121304007ebaSmrg        PictureTransformPoint(t, &v);
1214f29dbc25Smrg
1215f29dbc25Smrg    point->x = v.vector[0];
1216f29dbc25Smrg    point->y = v.vector[1];
1217f29dbc25Smrg}
1218f29dbc25Smrg
1219f29dbc25Smrgstatic void
1220f29dbc25Smrglx_do_composite(PixmapPtr pxDst, int srcX, int srcY, int maskX,
122104007ebaSmrg                int maskY, int dstX, int dstY, int width, int height)
1222f29dbc25Smrg{
1223f29dbc25Smrg    unsigned int dstOffset, srcOffset = 0;
1224f29dbc25Smrg
1225f29dbc25Smrg    xPointFixed srcPoint;
1226f29dbc25Smrg
1227f29dbc25Smrg    int opX = dstX;
1228f29dbc25Smrg    int opY = dstY;
1229f29dbc25Smrg    int opWidth = width;
1230f29dbc25Smrg    int opHeight = height;
1231f29dbc25Smrg
1232f29dbc25Smrg    /* Transform the source coordinates */
1233f29dbc25Smrg
1234f29dbc25Smrg    if (exaScratch.type == COMP_TYPE_MASK) {
123504007ebaSmrg        srcPoint.x = F(maskX);
123604007ebaSmrg        srcPoint.y = F(maskY);
123704007ebaSmrg    }
123804007ebaSmrg    else {
123904007ebaSmrg        srcPoint.x = F(srcX);
124004007ebaSmrg        srcPoint.y = F(srcY);
1241f29dbc25Smrg    }
1242f29dbc25Smrg
1243f29dbc25Smrg    /* srcX, srcY point to the upper right side of the bounding box
1244f29dbc25Smrg     * in the unrotated coordinate space.  Depending on the orientation,
1245f29dbc25Smrg     * we have to translate the coordinates to point to the origin of
1246f29dbc25Smrg     * the rectangle in the source pixmap */
1247f29dbc25Smrg
1248f29dbc25Smrg    switch (exaScratch.rotate) {
1249f29dbc25Smrg    case RR_Rotate_270:
125004007ebaSmrg        srcPoint.x += F(width);
1251f29dbc25Smrg
125204007ebaSmrg        opWidth = height;
125304007ebaSmrg        opHeight = width;
125404007ebaSmrg        break;
1255f29dbc25Smrg
1256f29dbc25Smrg    case RR_Rotate_180:
125704007ebaSmrg        srcPoint.x += F(width);
125804007ebaSmrg        srcPoint.y += F(height);
1259f29dbc25Smrg
126004007ebaSmrg        srcX += width;
126104007ebaSmrg        srcY += height;
126204007ebaSmrg        break;
1263f29dbc25Smrg
1264f29dbc25Smrg    case RR_Rotate_90:
126504007ebaSmrg        srcPoint.y += F(height);
1266f29dbc25Smrg
126704007ebaSmrg        opWidth = height;
126804007ebaSmrg        opHeight = width;
126904007ebaSmrg        break;
1270f29dbc25Smrg    }
1271f29dbc25Smrg
1272f29dbc25Smrg    transformPoint(exaScratch.transform, &srcPoint);
1273f29dbc25Smrg
1274f29dbc25Smrg    /* Adjust the point to fit into the pixmap */
1275f29dbc25Smrg
1276f29dbc25Smrg    if (I(srcPoint.x) < 0) {
127704007ebaSmrg        opWidth += I(srcPoint.x);
127804007ebaSmrg        srcPoint.x = F(0);
1279f29dbc25Smrg    }
1280f29dbc25Smrg
1281f29dbc25Smrg    if (I(srcPoint.y) < 0) {
128204007ebaSmrg        opHeight += I(srcPoint.y);
128304007ebaSmrg        srcPoint.y = F(0);
1284f29dbc25Smrg    }
1285f29dbc25Smrg
1286170d5fdcSmrg    /* Get the source point offset position */
1287170d5fdcSmrg
1288f29dbc25Smrg    srcOffset = GetSrcOffset(I(srcPoint.x), I(srcPoint.y));
1289f29dbc25Smrg
1290170d5fdcSmrg    /* When mask exists, exaScratch.srcWidth and exaScratch.srcHeight are
1291170d5fdcSmrg     * the source width and source height; Otherwise, they are mask width
1292170d5fdcSmrg     * and mask height */
1293170d5fdcSmrg    /* exaScratch.repeat is the source repeat attribute
1294170d5fdcSmrg     * exaScratch.maskrepeat is the mask repeat attribute */
1295170d5fdcSmrg    /* If type is COMP_TYPE_MASK, maskX and maskY are not zero, we should
1296170d5fdcSmrg     * subtract them to do the operation in the correct region */
1297f29dbc25Smrg
1298170d5fdcSmrg    /* FIXME:  Please add the code to handle the condition when the maskX
1299170d5fdcSmrg     * and maskY coordinate are negative or greater than
1300170d5fdcSmrg     * exaScratch.srcWidth and exaScratch.srcHeight */
1301170d5fdcSmrg
1302170d5fdcSmrg    if (exaScratch.type == COMP_TYPE_MASK) {
130304007ebaSmrg        if ((exaScratch.srcWidth - maskX) < opWidth)
130404007ebaSmrg            opWidth = exaScratch.srcWidth - maskX;
130504007ebaSmrg        if ((exaScratch.srcHeight - maskY) < opHeight)
130604007ebaSmrg            opHeight = exaScratch.srcHeight - maskY;
130704007ebaSmrg    }
130804007ebaSmrg    else {
130904007ebaSmrg        if (exaScratch.type == COMP_TYPE_ONEPASS) {
131004007ebaSmrg            /* This is the condition srcX or/and srcY is/are out of source
131104007ebaSmrg             * region */
131204007ebaSmrg            if (((srcY >= 0 && srcY >= exaScratch.srcHeight)
131304007ebaSmrg                 || (srcX >= 0 && srcX >= exaScratch.srcWidth)) &&
131404007ebaSmrg                (exaScratch.op == PictOpOver || exaScratch.op == PictOpSrc)) {
131504007ebaSmrg                if (exaScratch.repeat == 1) {
131604007ebaSmrg                    opWidth = width;
131704007ebaSmrg                    opHeight = height;
131804007ebaSmrg                }
131904007ebaSmrg                else {
132004007ebaSmrg                    if (exaScratch.op == PictOpOver)
132104007ebaSmrg                        return;
132204007ebaSmrg                    else {
132304007ebaSmrg                        exaScratch.op = PictOpClear;
132404007ebaSmrg                        opWidth = width;
132504007ebaSmrg                        opHeight = height;
132604007ebaSmrg                    }
132704007ebaSmrg                }
132804007ebaSmrg                /* This is the condition srcX or/and srcY is/are in the source
132904007ebaSmrg                 * region */
133004007ebaSmrg            }
133104007ebaSmrg            else if (srcX >= 0 && srcY >= 0 &&
133204007ebaSmrg                     (exaScratch.op == PictOpOver ||
133304007ebaSmrg                      exaScratch.op == PictOpSrc)) {
133404007ebaSmrg                if (exaScratch.repeat == 1) {
133504007ebaSmrg                    opWidth = width;
133604007ebaSmrg                    opHeight = height;
133704007ebaSmrg                }
133804007ebaSmrg                else {
133904007ebaSmrg                    if ((exaScratch.srcWidth - srcX) < opWidth)
134004007ebaSmrg                        opWidth = exaScratch.srcWidth - srcX;
134104007ebaSmrg                    if ((exaScratch.srcHeight - srcY) < opHeight)
134204007ebaSmrg                        opHeight = exaScratch.srcHeight - srcY;
134304007ebaSmrg                }
134404007ebaSmrg                /* This is the condition srcX or/and srcY is/are negative */
134504007ebaSmrg            }
134604007ebaSmrg            else if ((srcX < 0 || srcY < 0) &&
134704007ebaSmrg                     (exaScratch.op == PictOpOver ||
134804007ebaSmrg                      exaScratch.op == PictOpSrc)) {
134904007ebaSmrg                if (exaScratch.repeat == 1) {
135004007ebaSmrg                    opWidth = width;
135104007ebaSmrg                    opHeight = height;
135204007ebaSmrg                }
135304007ebaSmrg                else {
135404007ebaSmrg                    /* FIXME: We can't support negative srcX/Y for all corner cases in
135504007ebaSmrg                     * a sane way without a bit bigger refactoring. So as to avoid
135604007ebaSmrg                     * gross misrenderings (e.g missing tray icons) in current real-world
135704007ebaSmrg                     * applications, just shift destination appropriately for now and
135804007ebaSmrg                     * ignore out of bounds source pixmap zero-vector handling. This is
135904007ebaSmrg                     * actually correct for PictOpOver, but PictOpSrc out of bounds regions
136004007ebaSmrg                     * should be blacked out, but aren't - without this workaround however
136104007ebaSmrg                     * it'd be simply all black instead, which is probably worse till a full
136204007ebaSmrg                     * clean solution solves it for all cases. */
136304007ebaSmrg                    if (srcX < 0) {
136404007ebaSmrg                        opX -= srcX;
136504007ebaSmrg                        srcX = 0;
136604007ebaSmrg                    }
136704007ebaSmrg
136804007ebaSmrg                    if (srcY < 0) {
136904007ebaSmrg                        opY -= srcY;
137004007ebaSmrg                        srcY = 0;
137104007ebaSmrg                    }
137204007ebaSmrg
137304007ebaSmrg                    /* EXA has taken care of adjusting srcWidth if it gets cut on the right */
137404007ebaSmrg                    width = opWidth = exaScratch.srcWidth;
137504007ebaSmrg                    /* EXA has taken care of adjusting srcHeight if it gets cut on the bottom */
137604007ebaSmrg                    height = opHeight = exaScratch.srcHeight;
137704007ebaSmrg                }
137804007ebaSmrg            }
137904007ebaSmrg            else {
138004007ebaSmrg                if (exaScratch.srcWidth < opWidth)
138104007ebaSmrg                    opWidth = exaScratch.srcWidth;
138204007ebaSmrg                if (exaScratch.srcHeight < opHeight)
138304007ebaSmrg                    opHeight = exaScratch.srcHeight;
138404007ebaSmrg            }
138504007ebaSmrg        }
138604007ebaSmrg        else {
138704007ebaSmrg            if (exaScratch.rotate == RR_Rotate_180) {
138804007ebaSmrg            }
138904007ebaSmrg            else {
139004007ebaSmrg                if ((exaScratch.srcWidth - srcY) < opWidth)
139104007ebaSmrg                    opWidth = exaScratch.srcWidth - srcY;
139204007ebaSmrg                if ((exaScratch.srcHeight - srcX) < opHeight)
139304007ebaSmrg                    opHeight = exaScratch.srcHeight - srcX;
139404007ebaSmrg            }
139504007ebaSmrg        }
1396170d5fdcSmrg    }
1397f29dbc25Smrg
1398f29dbc25Smrg    while (1) {
1399f29dbc25Smrg
140004007ebaSmrg        dstOffset = GetPixmapOffset(pxDst, opX, opY);
140104007ebaSmrg
140204007ebaSmrg        switch (exaScratch.type) {
140304007ebaSmrg
140404007ebaSmrg        case COMP_TYPE_MASK:{
140504007ebaSmrg            if (exaScratch.op == PictOpOver || exaScratch.op ==
140604007ebaSmrg                PictOpOutReverse || exaScratch.op == PictOpInReverse ||
140704007ebaSmrg                exaScratch.op == PictOpIn || exaScratch.op == PictOpOut ||
140804007ebaSmrg                exaScratch.op == PictOpOverReverse)
140904007ebaSmrg                lx_do_composite_mask_two_pass(pxDst, dstOffset,
141004007ebaSmrg                                              srcOffset, opWidth, opHeight, opX,
141104007ebaSmrg                                              opY, srcPoint);
141204007ebaSmrg            else
141304007ebaSmrg                lx_do_composite_mask(pxDst, dstOffset, srcOffset,
141404007ebaSmrg                                     opWidth, opHeight);
141504007ebaSmrg        }
141604007ebaSmrg            break;
141704007ebaSmrg
141804007ebaSmrg        case COMP_TYPE_ONEPASS:
141904007ebaSmrg            if ((exaScratch.op == PictOpOver || exaScratch.op == PictOpSrc)
142004007ebaSmrg                && (exaScratch.repeat == 1)) {
142104007ebaSmrg                lx_composite_onepass_special(pxDst, opWidth, opHeight, opX, opY,
142204007ebaSmrg                                             srcX, srcY);
142304007ebaSmrg                return;
142404007ebaSmrg            }
142504007ebaSmrg            else if ((exaScratch.op == PictOpAdd) && (exaScratch.srcFormat->exa
142604007ebaSmrg                                                      == PICT_a8) &&
142704007ebaSmrg                     (exaScratch.dstFormat->exa == PICT_a8))
142804007ebaSmrg                lx_composite_onepass_add_a8(pxDst, dstOffset, srcOffset,
142904007ebaSmrg                                            opWidth, opHeight, opX, opY, srcX,
143004007ebaSmrg                                            srcY);
143104007ebaSmrg            else
143204007ebaSmrg                lx_composite_onepass(pxDst, dstOffset, srcOffset, opWidth,
143304007ebaSmrg                                     opHeight);
143404007ebaSmrg            break;
143504007ebaSmrg
143604007ebaSmrg        case COMP_TYPE_TWOPASS:
143704007ebaSmrg            lx_composite_multipass(pxDst, dstOffset, srcOffset, opWidth,
143804007ebaSmrg                                   opHeight);
143904007ebaSmrg
144004007ebaSmrg        case COMP_TYPE_ROTATE:
144104007ebaSmrg            lx_composite_rotate(pxDst, dstOffset, srcOffset, opWidth, opHeight);
144204007ebaSmrg            break;
144304007ebaSmrg        }
144404007ebaSmrg
144504007ebaSmrg        opX += opWidth;
144604007ebaSmrg
144704007ebaSmrg        if (opX >= dstX + width) {
144804007ebaSmrg            opX = dstX;
144904007ebaSmrg            opY += opHeight;
145004007ebaSmrg
145104007ebaSmrg            if (opY >= dstY + height)
145204007ebaSmrg                break;
145304007ebaSmrg        }
145404007ebaSmrg
145504007ebaSmrg        /* FIXME:  Please add the code to handle the condition when the maskX
145604007ebaSmrg         * and maskY coordinate are negative or greater than
145704007ebaSmrg         * exaScratch.srcWidth and exaScratch.srcHeight */
145804007ebaSmrg
145904007ebaSmrg        if (exaScratch.type == COMP_TYPE_MASK) {
146004007ebaSmrg            opWidth = ((dstX + width) - opX) > (exaScratch.srcWidth - maskX)
146104007ebaSmrg                ? (exaScratch.srcWidth - maskX) : (dstX + width) - opX;
146204007ebaSmrg            opHeight = ((dstY + height) - opY) > (exaScratch.srcHeight - maskY)
146304007ebaSmrg                ? (exaScratch.srcHeight - maskY) : (dstY + height) - opY;
146404007ebaSmrg            /* All black out of the mask */
146504007ebaSmrg            if (!exaScratch.maskrepeat)
146604007ebaSmrg                exaScratch.srcColor = 0x0;
146704007ebaSmrg        }
146804007ebaSmrg        else {
146904007ebaSmrg            if (exaScratch.type == COMP_TYPE_ONEPASS) {
147004007ebaSmrg                if (srcX >= 0 && srcY >= 0 && (exaScratch.op == PictOpOver ||
147104007ebaSmrg                                               exaScratch.op == PictOpSrc ||
147204007ebaSmrg                                               exaScratch.op == PictOpClear)) {
147304007ebaSmrg                    opWidth =
147404007ebaSmrg                        ((dstX + width) - opX) >
147504007ebaSmrg                        (exaScratch.srcWidth - srcX) ? (exaScratch.srcWidth -
147604007ebaSmrg                                                        srcX) : (dstX + width)
147704007ebaSmrg                        - opX;
147804007ebaSmrg                    opHeight = ((dstY + height) - opY) >
147904007ebaSmrg                        (exaScratch.srcHeight - srcY) ?
148004007ebaSmrg                        (exaScratch.srcHeight - srcY) : (dstY + height) - opY;
148104007ebaSmrg                }
148204007ebaSmrg                else {
148304007ebaSmrg                    opWidth = ((dstX + width) - opX) > exaScratch.srcWidth ?
148404007ebaSmrg                        exaScratch.srcWidth : (dstX + width) - opX;
148504007ebaSmrg                    opHeight = ((dstY + height) - opY) > exaScratch.srcHeight ?
148604007ebaSmrg                        exaScratch.srcHeight : (dstY + height) - opY;
148704007ebaSmrg                }
148804007ebaSmrg            }
148904007ebaSmrg            else {
149004007ebaSmrg                opWidth = ((dstX + width) - opX) > (exaScratch.srcWidth - srcY)
149104007ebaSmrg                    ? (exaScratch.srcWidth - srcY) : (dstX + width) - opX;
149204007ebaSmrg                opHeight =
149304007ebaSmrg                    ((dstY + height) - opY) >
149404007ebaSmrg                    (exaScratch.srcHeight - srcX) ? (exaScratch.srcHeight -
149504007ebaSmrg                                                     srcX) : (dstY + height) -
149604007ebaSmrg                    opY;
149704007ebaSmrg            }
149804007ebaSmrg            /* All black out of the source */
149904007ebaSmrg            if (!exaScratch.repeat && (exaScratch.type == COMP_TYPE_ONEPASS)) {
150004007ebaSmrg                /* FIXME: We black out the source here, so that any further regions
150104007ebaSmrg                 * in the loop get handled as a source that's a zero-vector (as
150204007ebaSmrg                 * defined for out-of-bounds from source pixmap for RepeatModeNone),
150304007ebaSmrg                 * but this will likely interfere with cases where srcX and/or srcY
150404007ebaSmrg                 * is negative - as opposed to e.g width being larger than srcWidth,
150504007ebaSmrg                 * which is exercised in rendercheck (always rectangle in top-left
150604007ebaSmrg                 * corner).
150704007ebaSmrg                 * Additionally it forces the drawing into tiles of srcWidth/srcHeight
150804007ebaSmrg                 * for non-repeat modes too, where we don't really need to tile it like
150904007ebaSmrg                 * this and could draw the out of bound regions all at once (or at most
151004007ebaSmrg                 * in 4 operations without the big loop). */
151104007ebaSmrg                lx_composite_all_black(srcOffset, exaScratch.srcWidth,
151204007ebaSmrg                                       exaScratch.srcHeight);
151304007ebaSmrg            }
151404007ebaSmrg            if (!exaScratch.repeat && (exaScratch.type == COMP_TYPE_ROTATE))
151504007ebaSmrg                break;
151604007ebaSmrg        }
1517f29dbc25Smrg    }
1518f29dbc25Smrg}
1519f29dbc25Smrg
1520f29dbc25Smrgstatic void
1521f29dbc25Smrglx_wait_marker(ScreenPtr PScreen, int marker)
1522f29dbc25Smrg{
1523f29dbc25Smrg    gp_wait_until_idle();
1524f29dbc25Smrg}
1525f29dbc25Smrg
1526f29dbc25Smrgstatic void
1527f29dbc25Smrglx_done(PixmapPtr ptr)
1528f29dbc25Smrg{
1529f29dbc25Smrg}
1530f29dbc25Smrg
1531f29dbc25Smrg#if 0
1532f29dbc25Smrgstatic void
1533f29dbc25Smrglx_upload_to_screen(PixmapPtr pxDst, int x, int y, int w, int h,
153404007ebaSmrg                    char *src, int src_pitch)
1535f29dbc25Smrg{
1536f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR_FROM_PIXMAP(pxDst);
1537f29dbc25Smrg    int dst_pitch = exaGetPixmapPitch(pxDst);
1538f29dbc25Smrg    int cpp = (pxDst->drawable.bitsPerPixel + 7) / 8;
1539f29dbc25Smrg
1540f29dbc25Smrg    char *dst;
1541f29dbc25Smrg    int offset = exaGetPixmapOffset(pxDst);
1542f29dbc25Smrg
154304007ebaSmrg    dst = (char *) (pGeode->FBBase + offset + (y * dst_pitch) + (x * cpp));
1544f29dbc25Smrg    int i;
1545f29dbc25Smrg
1546f29dbc25Smrg    for (i = 0; i < h; i++) {
154704007ebaSmrg        memcpy(dst, src, w * cpp);
154804007ebaSmrg        dst += dst_pitch;
154904007ebaSmrg        src += src_pitch;
1550f29dbc25Smrg    }
1551f29dbc25Smrg}
1552f29dbc25Smrg#endif
1553f29dbc25Smrg
155404007ebaSmrg#if EXA_VERSION_MAJOR > 2 || (EXA_VERSION_MAJOR == 2 && EXA_VERSION_MINOR >= 2)
1555f29dbc25Smrg
1556f29dbc25Smrgstatic Bool
1557f29dbc25Smrglx_exa_pixmap_is_offscreen(PixmapPtr pPixmap)
1558f29dbc25Smrg{
155904007ebaSmrg    ScrnInfoPtr pScrni = xf86ScreenToScrn(pPixmap->drawable.pScreen);
1560f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
156104007ebaSmrg    void *start = (void *) (pGeode->FBBase);
1562f29dbc25Smrg    void *end =
156304007ebaSmrg        (void *) (pGeode->FBBase + pGeode->offscreenStart +
156404007ebaSmrg                  pGeode->offscreenSize);
1565f29dbc25Smrg
156604007ebaSmrg    if ((void *) pPixmap->devPrivate.ptr >= start &&
156704007ebaSmrg        (void *) pPixmap->devPrivate.ptr < end)
156804007ebaSmrg        return TRUE;
1569f29dbc25Smrg
1570f29dbc25Smrg    return FALSE;
1571f29dbc25Smrg}
1572f29dbc25Smrg
1573f29dbc25Smrg#endif
1574f29dbc25Smrg
1575f29dbc25SmrgBool
1576f29dbc25SmrgLXExaInit(ScreenPtr pScreen)
1577f29dbc25Smrg{
157804007ebaSmrg    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScreen);
1579f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
1580f29dbc25Smrg    ExaDriverPtr pExa = pGeode->pExa;
1581f29dbc25Smrg
1582f29dbc25Smrg    pExa->exa_major = EXA_VERSION_MAJOR;
1583f29dbc25Smrg    pExa->exa_minor = EXA_VERSION_MINOR;
1584f29dbc25Smrg
1585f29dbc25Smrg    pExa->WaitMarker = lx_wait_marker;
1586f29dbc25Smrg
1587f29dbc25Smrg    pExa->PrepareSolid = lx_prepare_solid;
1588f29dbc25Smrg    pExa->Solid = lx_do_solid;
1589f29dbc25Smrg    pExa->DoneSolid = lx_done;
1590f29dbc25Smrg
1591f29dbc25Smrg    pExa->PrepareCopy = lx_prepare_copy;
1592f29dbc25Smrg    pExa->Copy = lx_do_copy;
1593f29dbc25Smrg    pExa->DoneCopy = lx_done;
1594f29dbc25Smrg
1595f29dbc25Smrg    /* Composite */
1596f29dbc25Smrg    pExa->CheckComposite = lx_check_composite;
1597f29dbc25Smrg    pExa->PrepareComposite = lx_prepare_composite;
1598f29dbc25Smrg    pExa->Composite = lx_do_composite;
1599f29dbc25Smrg    pExa->DoneComposite = lx_done;
1600f29dbc25Smrg    //pExa->UploadToScreen =  lx_upload_to_screen;
1601f29dbc25Smrg
160204007ebaSmrg#if EXA_VERSION_MAJOR > 2 || (EXA_VERSION_MAJOR == 2 && EXA_VERSION_MINOR >= 2)
1603f29dbc25Smrg    pExa->PixmapIsOffscreen = lx_exa_pixmap_is_offscreen;
1604f29dbc25Smrg#endif
1605f29dbc25Smrg
1606f29dbc25Smrg    //pExa->flags = EXA_OFFSCREEN_PIXMAPS;
1607f29dbc25Smrg
1608f29dbc25Smrg    return exaDriverInit(pScreen, pGeode->pExa);
1609f29dbc25Smrg}
1610