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
3900be8644Schristos#include "xorg-server.h"
4000be8644Schristos
41f29dbc25Smrg#include "xf86.h"
42f29dbc25Smrg#include "exa.h"
43f29dbc25Smrg
44f29dbc25Smrg#include "geode.h"
45f29dbc25Smrg#include "cim_defs.h"
46f29dbc25Smrg#include "cim_regs.h"
47f29dbc25Smrg
48f29dbc25Smrg#include "geode_blend.h"
49f29dbc25Smrg
50f29dbc25Smrg#define F(x)    IntToxFixed(x)
51f29dbc25Smrg#define I(x)    xFixedToInt(x)
52f29dbc25Smrg
5304007ebaSmrg#define GEODE_TRACE_FALL 0
5404007ebaSmrg
5504007ebaSmrg#if GEODE_TRACE_FALL
5604007ebaSmrg#define GEODE_FALLBACK(x)               \
5704007ebaSmrgdo {                                    \
5804007ebaSmrg	ErrorF("%s: ", __FUNCTION__);   \
5904007ebaSmrg	ErrorF x;                       \
6004007ebaSmrg	return FALSE;                   \
6104007ebaSmrg} while (0)
6204007ebaSmrg#else
6304007ebaSmrg#define GEODE_FALLBACK(x) return FALSE
6404007ebaSmrg#endif
6504007ebaSmrg
6604007ebaSmrgstatic const struct exa_format_t {
67f29dbc25Smrg    int exa;
68f29dbc25Smrg    int bpp;
69f29dbc25Smrg    int fmt;
70f29dbc25Smrg    int alphabits;
71f29dbc25Smrg} lx_exa_formats[] = {
72f29dbc25Smrg    {
73f29dbc25Smrg    PICT_a8r8g8b8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 8}, {
74f29dbc25Smrg    PICT_x8r8g8b8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 0}, {
75f29dbc25Smrg    PICT_x8b8g8r8, 32, CIMGP_SOURCE_FMT_32BPP_BGR, 0}, {
76f29dbc25Smrg    PICT_a4r4g4b4, 16, CIMGP_SOURCE_FMT_4_4_4_4, 4}, {
77f29dbc25Smrg    PICT_a1r5g5b5, 16, CIMGP_SOURCE_FMT_1_5_5_5, 1}, {
78f29dbc25Smrg    PICT_r5g6b5, 16, CIMGP_SOURCE_FMT_0_5_6_5, 0}, {
79f29dbc25Smrg    PICT_b5g6r5, 16, CIMGP_SOURCE_FMT_16BPP_BGR, 0}, {
80f29dbc25Smrg    PICT_x1r5g5b5, 16, CIMGP_SOURCE_FMT_1_5_5_5, 0}, {
81f29dbc25Smrg    PICT_x1b5g5r5, 16, CIMGP_SOURCE_FMT_15BPP_BGR, 0}, {
82170d5fdcSmrg    PICT_r3g3b2, 8, CIMGP_SOURCE_FMT_3_3_2, 0}, {
83170d5fdcSmrg    PICT_a8, 32, CIMGP_SOURCE_FMT_8_8_8_8, 8}
84f29dbc25Smrg};
85f29dbc25Smrg
86f29dbc25Smrg/* This is a chunk of memory we use for scratch space */
87f29dbc25Smrg
88f29dbc25Smrg#define COMP_TYPE_MASK 0
89f29dbc25Smrg#define COMP_TYPE_ONEPASS 1
90f29dbc25Smrg#define COMP_TYPE_TWOPASS 3
91f29dbc25Smrg#define COMP_TYPE_ROTATE  5
92f29dbc25Smrg
9304007ebaSmrgstatic struct {
94f29dbc25Smrg    int type;
95f29dbc25Smrg
96f29dbc25Smrg    unsigned int srcOffset;
97f29dbc25Smrg    unsigned int srcPitch;
98f29dbc25Smrg    unsigned int srcBpp;
99f29dbc25Smrg    unsigned int srcWidth, srcHeight;
100f29dbc25Smrg
101f29dbc25Smrg    unsigned int srcColor;
102f29dbc25Smrg    int op;
103f29dbc25Smrg    int repeat;
104170d5fdcSmrg    int maskrepeat;
105f29dbc25Smrg    unsigned int fourBpp;
106f29dbc25Smrg    unsigned int bufferOffset;
107f29dbc25Smrg    struct exa_format_t *srcFormat;
108f29dbc25Smrg    struct exa_format_t *dstFormat;
109f29dbc25Smrg
110f29dbc25Smrg    int rotate;
111f29dbc25Smrg    PictTransform *transform;
112f29dbc25Smrg
113f29dbc25Smrg} exaScratch;
114f29dbc25Smrg
115f29dbc25Smrgstatic const int SDfn[16] = {
116f29dbc25Smrg    0x00, 0x88, 0x44, 0xCC, 0x22, 0xAA, 0x66, 0xEE,
117f29dbc25Smrg    0x11, 0x99, 0x55, 0xDD, 0x33, 0xBB, 0x77, 0xFF
118f29dbc25Smrg};
119f29dbc25Smrg
120f29dbc25Smrgstatic const int SDfn_PM[16] = {
121f29dbc25Smrg    0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
122f29dbc25Smrg    0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA
123f29dbc25Smrg};
124f29dbc25Smrg
125f29dbc25Smrg/* These functions check to see if we can safely prefetch the memory
126f29dbc25Smrg * for the blt, or if we have to wait the previous blt to complete.
127f29dbc25Smrg * One function is for the fill, and the other is for the copy because
128f29dbc25Smrg * they have different requirements based on ROP
129f29dbc25Smrg */
130f29dbc25Smrg
131f29dbc25Smrgstatic int lx0 = -1, ly0 = -1, lx1 = -1, ly1 = -1;
132f29dbc25Smrg
133f29dbc25Smrgstatic int
134f29dbc25Smrglx_fill_flags(int x0, int y0, int w, int h, int rop)
135f29dbc25Smrg{
136f29dbc25Smrg    int x1 = x0 + w, y1 = y0 + h;
13704007ebaSmrg    int n = ((rop ^ (rop >> 1)) & 0x55) == 0 || /* no dst */
13804007ebaSmrg        x0 >= lx1 || y0 >= ly1 ||       /* rght/below */
13904007ebaSmrg        x1 <= lx0 || y1 <= ly0 ?        /* left/above */
14004007ebaSmrg        0 : CIMGP_BLTFLAGS_HAZARD;
141f29dbc25Smrg
142f29dbc25Smrg    lx0 = x0;
143f29dbc25Smrg    ly0 = y0;
144f29dbc25Smrg    lx1 = x1;
145f29dbc25Smrg    ly1 = y1;
146f29dbc25Smrg
147f29dbc25Smrg    return n;
148f29dbc25Smrg}
149f29dbc25Smrg
150f29dbc25Smrgstatic int
151f29dbc25Smrglx_copy_flags(int x0, int y0, int x1, int y1, int w, int h, int rop)
152f29dbc25Smrg{
153f29dbc25Smrg    int x2 = x1 + w, y2 = y1 + h;
154f29dbc25Smrg
155f29dbc25Smrg    /* dst not hazzard and src not hazzard */
156f29dbc25Smrg    int n = (((rop ^ (rop >> 1)) & 0x55) == 0 ||
15704007ebaSmrg             x1 >= lx1 || y1 >= ly1 ||
15804007ebaSmrg             x2 <= lx0 || y2 <= ly0) &&
15904007ebaSmrg        (((rop ^ (rop >> 2)) & 0x33) == 0 ||
16004007ebaSmrg         x0 >= lx1 || y0 >= ly1 ||
16104007ebaSmrg         x0 + w <= lx0 || y0 + h <= ly0) ? 0 : CIMGP_BLTFLAGS_HAZARD;
162f29dbc25Smrg
163f29dbc25Smrg    lx0 = x1;
164f29dbc25Smrg    ly0 = y1;
165f29dbc25Smrg    lx1 = x2;
166f29dbc25Smrg    ly1 = y2;
167f29dbc25Smrg
168f29dbc25Smrg    return n;
169f29dbc25Smrg}
170f29dbc25Smrg
171f29dbc25Smrg/* These are borrowed from the exa engine - they should be made global
172f29dbc25Smrg   and available to drivers, but until then....
173f29dbc25Smrg*/
174f29dbc25Smrg
175f29dbc25Smrg/* exaGetPixelFromRGBA (exa_render.c) */
176f29dbc25Smrg
177f29dbc25Smrgstatic Bool
17804007ebaSmrg_GetPixelFromRGBA(CARD32 *pixel,
17904007ebaSmrg                  CARD16 red, CARD16 green, CARD16 blue, CARD16 alpha,
18004007ebaSmrg                  CARD32 format)
181f29dbc25Smrg{
182f29dbc25Smrg    int rbits, bbits, gbits, abits;
183f29dbc25Smrg    int rshift, bshift, gshift, ashift;
184f29dbc25Smrg
185f29dbc25Smrg    *pixel = 0;
186f29dbc25Smrg
187f29dbc25Smrg    if (!PICT_FORMAT_COLOR(format))
18804007ebaSmrg        return FALSE;
189f29dbc25Smrg
190f29dbc25Smrg    rbits = PICT_FORMAT_R(format);
191f29dbc25Smrg    gbits = PICT_FORMAT_G(format);
192f29dbc25Smrg    bbits = PICT_FORMAT_B(format);
193f29dbc25Smrg    abits = PICT_FORMAT_A(format);
194f29dbc25Smrg
195f29dbc25Smrg    if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
19604007ebaSmrg        bshift = 0;
19704007ebaSmrg        gshift = bbits;
19804007ebaSmrg        rshift = gshift + gbits;
19904007ebaSmrg        ashift = rshift + rbits;
20004007ebaSmrg    }
20104007ebaSmrg    else {                      /* PICT_TYPE_ABGR */
20204007ebaSmrg        rshift = 0;
20304007ebaSmrg        gshift = rbits;
20404007ebaSmrg        bshift = gshift + gbits;
20504007ebaSmrg        ashift = bshift + bbits;
206f29dbc25Smrg    }
207f29dbc25Smrg
208f29dbc25Smrg    *pixel |= (blue >> (16 - bbits)) << bshift;
209f29dbc25Smrg    *pixel |= (red >> (16 - rbits)) << rshift;
210f29dbc25Smrg    *pixel |= (green >> (16 - gbits)) << gshift;
211f29dbc25Smrg    *pixel |= (alpha >> (16 - abits)) << ashift;
212f29dbc25Smrg
213f29dbc25Smrg    return TRUE;
214f29dbc25Smrg}
215f29dbc25Smrg
216f29dbc25Smrg/* exaGetRGBAFromPixel (exa_render.c) */
217f29dbc25Smrg
218f29dbc25Smrgstatic Bool
219f29dbc25Smrg_GetRGBAFromPixel(CARD32 pixel,
22004007ebaSmrg                  CARD16 *red,
22104007ebaSmrg                  CARD16 *green, CARD16 *blue, CARD16 *alpha, CARD32 format)
222f29dbc25Smrg{
223f29dbc25Smrg    int rbits, bbits, gbits, abits;
224f29dbc25Smrg    int rshift, bshift, gshift, ashift;
225f29dbc25Smrg
226f29dbc25Smrg    if (!PICT_FORMAT_COLOR(format))
22704007ebaSmrg        return FALSE;
228f29dbc25Smrg
229f29dbc25Smrg    rbits = PICT_FORMAT_R(format);
230f29dbc25Smrg    gbits = PICT_FORMAT_G(format);
231f29dbc25Smrg    bbits = PICT_FORMAT_B(format);
232f29dbc25Smrg    abits = PICT_FORMAT_A(format);
233f29dbc25Smrg
234f29dbc25Smrg    if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
23504007ebaSmrg        bshift = 0;
23604007ebaSmrg        gshift = bbits;
23704007ebaSmrg        rshift = gshift + gbits;
23804007ebaSmrg        ashift = rshift + rbits;
23904007ebaSmrg    }
24004007ebaSmrg    else {                      /* PICT_TYPE_ABGR */
24104007ebaSmrg        rshift = 0;
24204007ebaSmrg        gshift = rbits;
24304007ebaSmrg        bshift = gshift + gbits;
24404007ebaSmrg        ashift = bshift + bbits;
245f29dbc25Smrg    }
246f29dbc25Smrg
247f29dbc25Smrg    *red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits);
248f29dbc25Smrg    while (rbits < 16) {
24904007ebaSmrg        *red |= *red >> rbits;
25004007ebaSmrg        rbits <<= 1;
251f29dbc25Smrg    }
252f29dbc25Smrg
253f29dbc25Smrg    *green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits);
254f29dbc25Smrg    while (gbits < 16) {
25504007ebaSmrg        *green |= *green >> gbits;
25604007ebaSmrg        gbits <<= 1;
257f29dbc25Smrg    }
258f29dbc25Smrg
259f29dbc25Smrg    *blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits);
260f29dbc25Smrg    while (bbits < 16) {
26104007ebaSmrg        *blue |= *blue >> bbits;
26204007ebaSmrg        bbits <<= 1;
263f29dbc25Smrg    }
264f29dbc25Smrg
265f29dbc25Smrg    if (abits) {
26604007ebaSmrg        *alpha = ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits);
26704007ebaSmrg        while (abits < 16) {
26804007ebaSmrg            *alpha |= *alpha >> abits;
26904007ebaSmrg            abits <<= 1;
27004007ebaSmrg        }
27104007ebaSmrg    }
27204007ebaSmrg    else
27304007ebaSmrg        *alpha = 0xffff;
274f29dbc25Smrg
275f29dbc25Smrg    return TRUE;
276f29dbc25Smrg}
277f29dbc25Smrg
278f29dbc25Smrgstatic unsigned int
279f29dbc25Smrglx_get_source_color(PixmapPtr pSrc, int srcFormat, int dstFormat)
280f29dbc25Smrg{
281f29dbc25Smrg    CARD32 in, out;
282f29dbc25Smrg    CARD16 red = 0, green = 0, blue = 0, alpha = 0;
283f29dbc25Smrg
284f29dbc25Smrg    /* Stall to avoid a race with the upload function */
285f29dbc25Smrg    /* for 1.4 and newer, the problem will be resolved within
286f29dbc25Smrg     * exaGetPixmapFirstPixel, so this should be adjusted so
287f29dbc25Smrg     * the stall isn't run needlessly
288f29dbc25Smrg     */
28904007ebaSmrg    /* FIXME: xserver-1.4 with a supposed fix for this is really old, so kill the stall? */
290f29dbc25Smrg
291f29dbc25Smrg    gp_wait_until_idle();
292f29dbc25Smrg    in = exaGetPixmapFirstPixel(pSrc);
293f29dbc25Smrg
294f29dbc25Smrg    _GetRGBAFromPixel(in, &red, &blue, &green, &alpha, srcFormat);
295f29dbc25Smrg    _GetPixelFromRGBA(&out, red, blue, green, alpha, dstFormat);
296f29dbc25Smrg
297f29dbc25Smrg    return out;
298f29dbc25Smrg}
299f29dbc25Smrg
300f29dbc25Smrgstatic Bool
301f29dbc25Smrglx_prepare_solid(PixmapPtr pxMap, int alu, Pixel planemask, Pixel fg)
302f29dbc25Smrg{
303f29dbc25Smrg    int pitch = exaGetPixmapPitch(pxMap);
304f29dbc25Smrg    int op = (planemask == ~0U) ? SDfn[alu] : SDfn_PM[alu];
305f29dbc25Smrg
306f29dbc25Smrg    gp_declare_blt(0);
307f29dbc25Smrg    gp_set_bpp(pxMap->drawable.bitsPerPixel);
308f29dbc25Smrg
309f29dbc25Smrg    gp_set_raster_operation(op);
310f29dbc25Smrg
311f29dbc25Smrg    if (planemask != ~0U)
31204007ebaSmrg        gp_set_solid_pattern(planemask);
313f29dbc25Smrg
314f29dbc25Smrg    exaScratch.op = op;
315f29dbc25Smrg
316f29dbc25Smrg    gp_set_solid_source(fg);
317f29dbc25Smrg
318f29dbc25Smrg    gp_set_strides(pitch, pitch);
319f29dbc25Smrg    gp_write_parameters();
320f29dbc25Smrg    return TRUE;
321f29dbc25Smrg}
322f29dbc25Smrg
323f29dbc25Smrgstatic void
324f29dbc25Smrglx_do_solid(PixmapPtr pxMap, int x1, int y1, int x2, int y2)
325f29dbc25Smrg{
326f29dbc25Smrg    int bpp = (pxMap->drawable.bitsPerPixel + 7) / 8;
327f29dbc25Smrg    int pitch = exaGetPixmapPitch(pxMap);
32804007ebaSmrg    unsigned int offset = exaGetPixmapOffset(pxMap) + (pitch * y1) + (bpp * x1);
329f29dbc25Smrg
330f29dbc25Smrg    gp_declare_blt(lx_fill_flags(x1, y1, x2 - x1, y2 - y1, exaScratch.op));
331f29dbc25Smrg    gp_pattern_fill(offset, x2 - x1, y2 - y1);
332f29dbc25Smrg}
333f29dbc25Smrg
334f29dbc25Smrgstatic Bool
335f29dbc25Smrglx_prepare_copy(PixmapPtr pxSrc, PixmapPtr pxDst, int dx, int dy,
33604007ebaSmrg                int alu, Pixel planemask)
337f29dbc25Smrg{
338f29dbc25Smrg    int dpitch = exaGetPixmapPitch(pxDst);
339f29dbc25Smrg    int op = (planemask == ~0U) ? SDfn[alu] : SDfn_PM[alu];
340f29dbc25Smrg
341f29dbc25Smrg    gp_declare_blt(0);
342f29dbc25Smrg    gp_set_bpp(pxDst->drawable.bitsPerPixel);
343f29dbc25Smrg
344f29dbc25Smrg    gp_set_raster_operation(op);
345f29dbc25Smrg
346f29dbc25Smrg    if (planemask != ~0U)
34704007ebaSmrg        gp_set_solid_pattern(planemask);
348f29dbc25Smrg
349f29dbc25Smrg    exaScratch.srcOffset = exaGetPixmapOffset(pxSrc);
350f29dbc25Smrg    exaScratch.srcPitch = exaGetPixmapPitch(pxSrc);
351f29dbc25Smrg    exaScratch.srcBpp = (pxSrc->drawable.bitsPerPixel + 7) / 8;
352f29dbc25Smrg
353f29dbc25Smrg    exaScratch.op = op;
354f29dbc25Smrg
355f29dbc25Smrg    gp_set_strides(dpitch, exaScratch.srcPitch);
356f29dbc25Smrg    gp_write_parameters();
357f29dbc25Smrg    return TRUE;
358f29dbc25Smrg}
359f29dbc25Smrg
360f29dbc25Smrgstatic void
361f29dbc25Smrglx_do_copy(PixmapPtr pxDst, int srcX, int srcY,
36204007ebaSmrg           int dstX, int dstY, int w, int h)
363f29dbc25Smrg{
364f29dbc25Smrg    int dstBpp = (pxDst->drawable.bitsPerPixel + 7) / 8;
365f29dbc25Smrg    int dstPitch = exaGetPixmapPitch(pxDst);
366f29dbc25Smrg    unsigned int srcOffset, dstOffset;
367f29dbc25Smrg    int flags = 0;
368f29dbc25Smrg
36904007ebaSmrg    gp_declare_blt(lx_copy_flags(srcX, srcY, dstX, dstY, w, h, exaScratch.op));
370f29dbc25Smrg
371f29dbc25Smrg    srcOffset = exaScratch.srcOffset + (exaScratch.srcPitch * srcY) +
37204007ebaSmrg        (exaScratch.srcBpp) * srcX;
373f29dbc25Smrg
37404007ebaSmrg    dstOffset = exaGetPixmapOffset(pxDst) + (dstPitch * dstY) + (dstBpp * dstX);
375f29dbc25Smrg
376f29dbc25Smrg    if (dstX > srcX)
37704007ebaSmrg        flags |= CIMGP_NEGXDIR;
378f29dbc25Smrg
379f29dbc25Smrg    if (dstY > srcY)
38004007ebaSmrg        flags |= CIMGP_NEGYDIR;
381f29dbc25Smrg
382f29dbc25Smrg    gp_screen_to_screen_blt(dstOffset, srcOffset, w, h, flags);
383f29dbc25Smrg}
384f29dbc25Smrg
385f29dbc25Smrg/* Composite operations
386f29dbc25Smrg
387f29dbc25SmrgThese are the simplest - one pass operations - if there is no format or
388f29dbc25Smrgmask, the we can make these happen pretty fast
389f29dbc25Smrg
390f29dbc25Smrg                       Operation  Type  Channel   Alpha
391f29dbc25SmrgPictOpClear            0          2     0         3
392f29dbc25SmrgPictOpSrc              0          3     0         3
393f29dbc25SmrgPictOpDst              0          3     1         3
394f29dbc25SmrgPictOpOver             2          0     0         3
395f29dbc25SmrgPictOpOverReverse      2          0     1         3
396f29dbc25SmrgPictOpIn               0          1     0         3
397f29dbc25SmrgPictOpInReverse        0          1     1         3
398f29dbc25SmrgPictOpOut              1          0     0         3
399f29dbc25SmrgPictOpOutReverse       1          0     1         3
400f29dbc25SmrgPictOpAdd              2          2     0         3
401f29dbc25Smrg
402f29dbc25SmrgThe following require multiple passes
403f29dbc25SmrgPictOpAtop
404f29dbc25SmrgPictOpXor
405f29dbc25Smrg*/
406f29dbc25Smrg
40704007ebaSmrgstruct blend_ops_t {
408f29dbc25Smrg    int operation;
409f29dbc25Smrg    int type;
410f29dbc25Smrg    int channel;
411f29dbc25Smrg} lx_alpha_ops[] = {
412f29dbc25Smrg    /* PictOpClear */
413f29dbc25Smrg    {
414f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONSTANT_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
415f29dbc25Smrg    },
41604007ebaSmrg        /* PictOpSrc */
417f29dbc25Smrg    {
418f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_ALPHA_EQUALS_ONE, CIMGP_CHANNEL_A_SOURCE}, {
419f29dbc25Smrg    },
42004007ebaSmrg        /* PictOpDst */
421f29dbc25Smrg    {
422f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_ALPHA_EQUALS_ONE, CIMGP_CHANNEL_A_DEST}, {
423f29dbc25Smrg    },
42404007ebaSmrg        /* PictOpOver */
425f29dbc25Smrg    {
426170d5fdcSmrg    CIMGP_A_PLUS_BETA_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
427170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
42804007ebaSmrg        /* PictOpOverReverse */
429f29dbc25Smrg    {
430170d5fdcSmrg    CIMGP_A_PLUS_BETA_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST}, {
431170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
43204007ebaSmrg        /* PictOpIn */
433f29dbc25Smrg    {
434f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
435170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
43604007ebaSmrg        /* PictOpInReverse */
437f29dbc25Smrg    {
438f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_DEST}, {
439170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
44004007ebaSmrg        /* PictOpOut */
441f29dbc25Smrg    {
442170d5fdcSmrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST}, {
443170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
44404007ebaSmrg        /* PictOpOutReverse */
445f29dbc25Smrg    {
446170d5fdcSmrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
447170d5fdcSmrg    CIMGP_ALPHA_TIMES_A, CIMGP_CONVERTED_ALPHA, CIMGP_CHANNEL_A_SOURCE},
44804007ebaSmrg        /* SrcAtop */
449f29dbc25Smrg    {
450f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_DEST}, {
451f29dbc25Smrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE},
45204007ebaSmrg        /* SrcAtopReverse */
453f29dbc25Smrg    {
454f29dbc25Smrg    CIMGP_ALPHA_TIMES_A, CIMGP_CHANNEL_B_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
455f29dbc25Smrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_DEST},
45604007ebaSmrg        /* Xor */
457f29dbc25Smrg    {
458f29dbc25Smrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
459f29dbc25Smrg    CIMGP_BETA_TIMES_B, CIMGP_CHANNEL_A_ALPHA, CIMGP_CHANNEL_A_SOURCE},
46004007ebaSmrg        /* PictOpAdd */
461f29dbc25Smrg    {
462f29dbc25Smrg    CIMGP_A_PLUS_BETA_B, CIMGP_CONSTANT_ALPHA, CIMGP_CHANNEL_A_SOURCE}, {
463f29dbc25Smrg    }
464f29dbc25Smrg};
465f29dbc25Smrg
46604007ebaSmrg#ifndef ARRAY_SIZE
467f29dbc25Smrg#define ARRAY_SIZE(a) (sizeof((a)) / (sizeof(*(a))))
46804007ebaSmrg#endif
469f29dbc25Smrg
470f29dbc25Smrgstatic const struct exa_format_t *
471f29dbc25Smrglx_get_format(PicturePtr p)
472f29dbc25Smrg{
473f29dbc25Smrg    int i;
474f29dbc25Smrg    unsigned int format = p->format;
475f29dbc25Smrg
476170d5fdcSmrg    for (i = 0; i < ARRAY_SIZE(lx_exa_formats); i++)
47704007ebaSmrg        if (lx_exa_formats[i].exa == format)
47804007ebaSmrg            return (&lx_exa_formats[i]);
479f29dbc25Smrg
480f29dbc25Smrg    return NULL;
481f29dbc25Smrg}
482f29dbc25Smrg
483f29dbc25Smrgstatic Bool
484f29dbc25Smrglx_process_transform(PicturePtr pSrc)
485f29dbc25Smrg{
486f29dbc25Smrg    PictTransformPtr t = pSrc->transform;
487f29dbc25Smrg    xFixed c0 = t->matrix[0][0];
488f29dbc25Smrg    xFixed s0 = t->matrix[0][1];
489f29dbc25Smrg    xFixed s1 = t->matrix[1][0];
490f29dbc25Smrg    xFixed c1 = t->matrix[1][1];
491f29dbc25Smrg
492f29dbc25Smrg    /* If the transform doesn't have any rotation
493f29dbc25Smrg     * or scaling components, then just grab the
494f29dbc25Smrg     * translate coordinates */
495f29dbc25Smrg
496f29dbc25Smrg    if (t->matrix[0][0] == 0 &&
49704007ebaSmrg        t->matrix[0][1] == 0 && t->matrix[1][0] == 0 && t->matrix[1][1] == 0) {
49804007ebaSmrg        exaScratch.transform = pSrc->transform;
49904007ebaSmrg        return TRUE;
500f29dbc25Smrg    }
501f29dbc25Smrg
502f29dbc25Smrg    /* Otherwise, see if this is a simple
503f29dbc25Smrg     * rotate transform - if it isn't, then
504f29dbc25Smrg     * we have to punt back to software */
505f29dbc25Smrg
506f29dbc25Smrg    if (t->matrix[2][2] != F(1))
50704007ebaSmrg        return FALSE;
508f29dbc25Smrg
509f29dbc25Smrg    /* The rotate matrix looks like this:
510f29dbc25Smrg     * [ cos X   -sin x
511f29dbc25Smrg     * sin X   cos X ]
512f29dbc25Smrg     *
513f29dbc25Smrg     * Where X is the angle.  We do a simple
514f29dbc25Smrg     * check first - if [0,0] != [1,1], then
515f29dbc25Smrg     * scaling was specified too, and we can
516f29dbc25Smrg     * bail, and if [0,1] != -[1,1] then this
517f29dbc25Smrg     * isn't scaling that we can handle.
518f29dbc25Smrg     */
519f29dbc25Smrg
520f29dbc25Smrg    if ((c0 != c1) || (s0 != -s1))
52104007ebaSmrg        return FALSE;
522f29dbc25Smrg
523f29dbc25Smrg    /* Now, figure out what angle we want - we
524f29dbc25Smrg     * can only accelerate right angle rotations,
525f29dbc25Smrg     * so this turns into an easy set of if statements */
526f29dbc25Smrg
527f29dbc25Smrg    if (c0 == F(1) && s1 == F(0))
52804007ebaSmrg        exaScratch.rotate = RR_Rotate_0;
529f29dbc25Smrg    else if (c0 == F(0) && s1 == F(1))
53004007ebaSmrg        exaScratch.rotate = RR_Rotate_90;
531f29dbc25Smrg    else if (c0 == F(-1) && s1 == F(0))
53204007ebaSmrg        exaScratch.rotate = RR_Rotate_180;
533f29dbc25Smrg    else if (c0 == F(0) && s1 == F(-1))
53404007ebaSmrg        exaScratch.rotate = RR_Rotate_270;
535f29dbc25Smrg    else
53604007ebaSmrg        return FALSE;
537f29dbc25Smrg
538f29dbc25Smrg    exaScratch.transform = pSrc->transform;
539f29dbc25Smrg
540f29dbc25Smrg    return TRUE;
541f29dbc25Smrg}
542f29dbc25Smrg
543f29dbc25Smrgstatic Bool
544f29dbc25Smrglx_check_composite(int op, PicturePtr pSrc, PicturePtr pMsk, PicturePtr pDst)
545f29dbc25Smrg{
546f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR_FROM_PICTURE(pDst);
547170d5fdcSmrg    const struct exa_format_t *srcFmt, *dstFmt;
548f29dbc25Smrg
549f29dbc25Smrg    if (op > PictOpAdd)
55004007ebaSmrg        GEODE_FALLBACK(("Operation %d is not supported\n", op));
55104007ebaSmrg
55204007ebaSmrg    /* XXX - don't know if we can do any hwaccel on solid fills or gradient types in generic cases */
55304007ebaSmrg    if (pMsk && pMsk->pSourcePict)
55404007ebaSmrg        GEODE_FALLBACK(("%s are not supported as a mask\n",
55504007ebaSmrg                        pMsk->pSourcePict->type ==
55604007ebaSmrg                        SourcePictTypeSolidFill ? "Solid pictures" :
55704007ebaSmrg                        "Gradients"));
55804007ebaSmrg
55904007ebaSmrg    if (pSrc->pSourcePict && pSrc->pSourcePict->type != SourcePictTypeSolidFill)
56004007ebaSmrg        GEODE_FALLBACK(("Gradients are not supported as the source\n"));
56104007ebaSmrg
56204007ebaSmrg    if (pMsk && op == PictOpAdd)
56304007ebaSmrg        GEODE_FALLBACK(("PictOpAdd with mask is not supported\n"));
564f29dbc25Smrg
565170d5fdcSmrg    /* FIXME: Meet this conditions from the debug for PictOpAdd.
566170d5fdcSmrg     * Any Other possibilities? Add a judge for the future supplement */
567170d5fdcSmrg    if (op == PictOpAdd && pSrc->format == PICT_a8r8g8b8 &&
56804007ebaSmrg        pDst->format == PICT_a8)
56904007ebaSmrg        return TRUE;
570170d5fdcSmrg
571170d5fdcSmrg    if (op == PictOpAdd && pSrc->format == PICT_x8r8g8b8 &&
57204007ebaSmrg        pDst->format == PICT_a8)
57304007ebaSmrg        return TRUE;
574170d5fdcSmrg
575170d5fdcSmrg    if (op == PictOpAdd && pSrc->format == PICT_r5g6b5 &&
57604007ebaSmrg        pDst->format == PICT_a8)
57704007ebaSmrg        return TRUE;
578170d5fdcSmrg
579f29dbc25Smrg    if (usesPasses(op)) {
58004007ebaSmrg        /* FIXME: Slightly misleading fallback msg when !pMsk */
58104007ebaSmrg        if (pGeode->exaBfrOffset == 0 || !pMsk)
58204007ebaSmrg            GEODE_FALLBACK(("Multipass operation requires off-screen buffer\n"));
583f29dbc25Smrg    }
584f29dbc25Smrg
585f29dbc25Smrg    /* Check that the filter matches what we support */
586f29dbc25Smrg
587f29dbc25Smrg    switch (pSrc->filter) {
588f29dbc25Smrg    case PictFilterNearest:
589f29dbc25Smrg    case PictFilterFast:
590f29dbc25Smrg    case PictFilterGood:
591f29dbc25Smrg    case PictFilterBest:
59204007ebaSmrg        break;
593f29dbc25Smrg
594f29dbc25Smrg    default:
59504007ebaSmrg        GEODE_FALLBACK(("Bilinear or convolution filters are not supported\n"));
596f29dbc25Smrg    }
597f29dbc25Smrg
598f29dbc25Smrg    if (pMsk && pMsk->transform)
59904007ebaSmrg        GEODE_FALLBACK(("Mask transforms are not supported\n"));
600170d5fdcSmrg
601f29dbc25Smrg    /* Keep an eye out for source rotation transforms - those we can
602f29dbc25Smrg     * do something about */
603f29dbc25Smrg
604f29dbc25Smrg    exaScratch.rotate = RR_Rotate_0;
605f29dbc25Smrg    exaScratch.transform = NULL;
606f29dbc25Smrg
607f29dbc25Smrg    if (pSrc->transform && !lx_process_transform(pSrc))
60804007ebaSmrg        GEODE_FALLBACK(("Transform operation is non-trivial\n"));
609f29dbc25Smrg
610f29dbc25Smrg    /* XXX - I don't understand PICT_a8 enough - so I'm punting */
611170d5fdcSmrg    if ((op != PictOpAdd) && (pSrc->format == PICT_a8 ||
61204007ebaSmrg                              pDst->format == PICT_a8))
61304007ebaSmrg        GEODE_FALLBACK(("PICT_a8 as src or dst format is unsupported\n"));
614f29dbc25Smrg
615f29dbc25Smrg    if (pMsk && op != PictOpClear) {
61604007ebaSmrg        struct blend_ops_t *opPtr = &lx_alpha_ops[op * 2];
61704007ebaSmrg        int direction = (opPtr->channel == CIMGP_CHANNEL_A_SOURCE) ? 0 : 1;
61804007ebaSmrg
61904007ebaSmrg        /* Direction 0 indicates src->dst, 1 indicates dst->src */
62004007ebaSmrg        if (((direction == 0) &&
62104007ebaSmrg             (pSrc->pDrawable && pSrc->pDrawable->bitsPerPixel < 16)) ||
62204007ebaSmrg            ((direction == 1) && (pDst->pDrawable->bitsPerPixel < 16))) {
62304007ebaSmrg            ErrorF("Mask blending unsupported with <16bpp\n");
62404007ebaSmrg            return FALSE;
62504007ebaSmrg        }
62604007ebaSmrg        if (pMsk->format != PICT_a8 && pMsk->format != PICT_a4)
62704007ebaSmrg            GEODE_FALLBACK(("Masks can be only done with a 8bpp or 4bpp depth\n"));
62804007ebaSmrg
62904007ebaSmrg        /* The pSrc should be 1x1 pixel if the pMsk is not zero */
63004007ebaSmrg        if (pSrc->pDrawable &&
63104007ebaSmrg            (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1))
63204007ebaSmrg            GEODE_FALLBACK(("pSrc should be 1x1 pixel if pMsk is not zero\n"));
63304007ebaSmrg        /* FIXME: In lx_prepare_composite, there are no variables to record the
63404007ebaSmrg         * one pixel source's width and height when the mask is not zero.
63504007ebaSmrg         * That will lead to bigger region to render instead of one pixel in lx
63604007ebaSmrg         * _do_composite, so we should fallback currently to avoid this */
63704007ebaSmrg        /* Not an issue for solid pictures, because we'll treat it as 1x1R too */
63804007ebaSmrg        if (!pSrc->repeat &&
63904007ebaSmrg            !(pSrc->pSourcePict &&
64004007ebaSmrg              pSrc->pSourcePict->type == SourcePictTypeSolidFill)) {
64104007ebaSmrg            GEODE_FALLBACK(("FIXME: unzero mask might lead to bigger rendering region than 1x1 pixels\n"));
64204007ebaSmrg        }
64304007ebaSmrg    }
64404007ebaSmrg    else {
64504007ebaSmrg        if (pSrc->pSourcePict)
64604007ebaSmrg            GEODE_FALLBACK(("Solid source pictures without a mask are not supported\n"));
647f29dbc25Smrg    }
648f29dbc25Smrg
649f29dbc25Smrg    /* Get the formats for the source and destination */
650f29dbc25Smrg
65104007ebaSmrg    if ((srcFmt = lx_get_format(pSrc)) == NULL)
65204007ebaSmrg        GEODE_FALLBACK(("Unsupported source format %x\n", pSrc->format));
653f29dbc25Smrg
65404007ebaSmrg    if ((dstFmt = lx_get_format(pDst)) == NULL)
65504007ebaSmrg        GEODE_FALLBACK(("Unsupported destination format %x\n", pDst->format));
656f29dbc25Smrg
657f29dbc25Smrg    /* Make sure operations that need alpha bits have them */
658f29dbc25Smrg    /* If a mask is enabled, the alpha will come from there */
659f29dbc25Smrg
660f29dbc25Smrg    if (!pMsk && (!srcFmt->alphabits && usesSrcAlpha(op)))
66104007ebaSmrg        GEODE_FALLBACK(("Operation requires src alpha, but alphabits is unset\n"));
662f29dbc25Smrg
663f29dbc25Smrg    if (!pMsk && (!dstFmt->alphabits && usesDstAlpha(op)))
66404007ebaSmrg        GEODE_FALLBACK(("Operation requires dst alpha, but alphabits is unset\n"));
665f29dbc25Smrg
66604007ebaSmrg    /* FIXME: See a way around this! */
667f29dbc25Smrg    if (srcFmt->alphabits == 0 && dstFmt->alphabits != 0)
66804007ebaSmrg        GEODE_FALLBACK(("src_alphabits=0, dst_alphabits!=0\n"));
669f29dbc25Smrg
670f29dbc25Smrg    /* If this is a rotate operation, then make sure the src and dst
671f29dbc25Smrg     * formats are the same */
672f29dbc25Smrg    if (exaScratch.rotate != RR_Rotate_0 && srcFmt != dstFmt) {
67304007ebaSmrg        ErrorF("EXA: Unable to rotate and convert formats at the same time\n");
67404007ebaSmrg        return FALSE;
675f29dbc25Smrg    }
676170d5fdcSmrg    return TRUE;
677170d5fdcSmrg}
678170d5fdcSmrg
679170d5fdcSmrgstatic Bool
680170d5fdcSmrglx_prepare_composite(int op, PicturePtr pSrc, PicturePtr pMsk,
68104007ebaSmrg                     PicturePtr pDst, PixmapPtr pxSrc, PixmapPtr pxMsk,
68204007ebaSmrg                     PixmapPtr pxDst)
683170d5fdcSmrg{
684170d5fdcSmrg    GeodeRec *pGeode = GEODEPTR_FROM_PIXMAP(pxDst);
685170d5fdcSmrg    const struct exa_format_t *srcFmt, *dstFmt;
686170d5fdcSmrg
687170d5fdcSmrg    /* Get the formats for the source and destination */
688170d5fdcSmrg
689170d5fdcSmrg    srcFmt = lx_get_format(pSrc);
690170d5fdcSmrg    dstFmt = lx_get_format(pDst);
691f29dbc25Smrg
692f29dbc25Smrg    /* Set up the scratch buffer with the information we need */
693f29dbc25Smrg
69404007ebaSmrg    exaScratch.srcFormat = (struct exa_format_t *) srcFmt;
69504007ebaSmrg    exaScratch.dstFormat = (struct exa_format_t *) dstFmt;
696f29dbc25Smrg    exaScratch.op = op;
697f29dbc25Smrg    exaScratch.repeat = pSrc->repeat;
698f29dbc25Smrg    exaScratch.bufferOffset = pGeode->exaBfrOffset;
699f29dbc25Smrg
700f29dbc25Smrg    if (pMsk && op != PictOpClear) {
70104007ebaSmrg        /* Get the source color */
70204007ebaSmrg        if (pSrc->pSourcePict) {
70304007ebaSmrg            exaScratch.srcColor = pSrc->pSourcePict->solidFill.color;
70404007ebaSmrg        }
70504007ebaSmrg        else {
70604007ebaSmrg            /* If the op is PictOpOver(or PictOpOutReverse, PictOpInReverse,
70704007ebaSmrg             * PictOpIn, PictOpOut, PictOpOverReverse), we should get the
70804007ebaSmrg             * ARGB32 source format */
70904007ebaSmrg
71004007ebaSmrg            if ((op == PictOpOver || op == PictOpOutReverse || op ==
71104007ebaSmrg                 PictOpInReverse || op == PictOpIn || op == PictOpOut ||
71204007ebaSmrg                 op == PictOpOverReverse) && (srcFmt->alphabits != 0))
71304007ebaSmrg                exaScratch.srcColor = exaGetPixmapFirstPixel(pxSrc);
71404007ebaSmrg            else if ((op == PictOpOver || op == PictOpOutReverse || op ==
71504007ebaSmrg                      PictOpInReverse || op == PictOpIn || op == PictOpOut ||
71604007ebaSmrg                      op == PictOpOverReverse) && (srcFmt->alphabits == 0))
71704007ebaSmrg                exaScratch.srcColor = lx_get_source_color(pxSrc, pSrc->format,
71804007ebaSmrg                                                          PICT_a8r8g8b8);
71904007ebaSmrg            else
72004007ebaSmrg                exaScratch.srcColor = lx_get_source_color(pxSrc, pSrc->format,
72104007ebaSmrg                                                          pDst->format);
72204007ebaSmrg        }
72304007ebaSmrg
72404007ebaSmrg        /* Save off the info we need (reuse the source values to save space) */
72504007ebaSmrg        exaScratch.type = COMP_TYPE_MASK;
72604007ebaSmrg        exaScratch.maskrepeat = pMsk->repeat;
72704007ebaSmrg
72804007ebaSmrg        exaScratch.srcOffset = exaGetPixmapOffset(pxMsk);
72904007ebaSmrg        exaScratch.srcPitch = exaGetPixmapPitch(pxMsk);
73004007ebaSmrg        exaScratch.srcBpp = (pxMsk->drawable.bitsPerPixel + 7) / 8;
73104007ebaSmrg
73204007ebaSmrg        exaScratch.srcWidth = pMsk->pDrawable->width;
73304007ebaSmrg        exaScratch.srcHeight = pMsk->pDrawable->height;
73404007ebaSmrg
73504007ebaSmrg        /* Flag to indicate if this a 8BPP or a 4BPP mask */
73604007ebaSmrg        exaScratch.fourBpp = (pxMsk->drawable.bitsPerPixel == 4) ? 1 : 0;
73704007ebaSmrg    }
73804007ebaSmrg    else {
73904007ebaSmrg        if (usesPasses(op))
74004007ebaSmrg            exaScratch.type = COMP_TYPE_TWOPASS;
74104007ebaSmrg        else if (exaScratch.rotate != RR_Rotate_0)
74204007ebaSmrg            exaScratch.type = COMP_TYPE_ROTATE;
74304007ebaSmrg        else
74404007ebaSmrg            exaScratch.type = COMP_TYPE_ONEPASS;
74504007ebaSmrg
74604007ebaSmrg        exaScratch.srcOffset = exaGetPixmapOffset(pxSrc);
74704007ebaSmrg        exaScratch.srcPitch = exaGetPixmapPitch(pxSrc);
74804007ebaSmrg        exaScratch.srcBpp = (pxSrc->drawable.bitsPerPixel + 7) / 8;
74904007ebaSmrg
75004007ebaSmrg        exaScratch.srcWidth = pSrc->pDrawable->width;
75104007ebaSmrg        exaScratch.srcHeight = pSrc->pDrawable->height;
752f29dbc25Smrg    }
753f29dbc25Smrg
754f29dbc25Smrg    return TRUE;
755f29dbc25Smrg}
756f29dbc25Smrg
757f29dbc25Smrgstatic int
758f29dbc25Smrglx_get_bpp_from_format(int format)
759f29dbc25Smrg{
760f29dbc25Smrg
761f29dbc25Smrg    switch (format) {
762f29dbc25Smrg    case CIMGP_SOURCE_FMT_8_8_8_8:
763f29dbc25Smrg    case CIMGP_SOURCE_FMT_32BPP_BGR:
76404007ebaSmrg        return 32;
765f29dbc25Smrg
766f29dbc25Smrg    case CIMGP_SOURCE_FMT_4_4_4_4:
76704007ebaSmrg        return 12;
768f29dbc25Smrg
769f29dbc25Smrg    case CIMGP_SOURCE_FMT_0_5_6_5:
770f29dbc25Smrg    case CIMGP_SOURCE_FMT_16BPP_BGR:
77104007ebaSmrg        return 16;
772f29dbc25Smrg
773f29dbc25Smrg    case CIMGP_SOURCE_FMT_1_5_5_5:
774f29dbc25Smrg    case CIMGP_SOURCE_FMT_15BPP_BGR:
77504007ebaSmrg        return 15;
776f29dbc25Smrg
777f29dbc25Smrg    case CIMGP_SOURCE_FMT_3_3_2:
77804007ebaSmrg        return 8;
779f29dbc25Smrg    }
780f29dbc25Smrg
781f29dbc25Smrg    return 0;
782f29dbc25Smrg}
783f29dbc25Smrg
784f29dbc25Smrg/* BGR needs to be set in the source for it to take - so adjust the source
785f29dbc25Smrg * to enable BGR if the two formats are different, and disable it if they
786f29dbc25Smrg * are the same
787f29dbc25Smrg */
788f29dbc25Smrg
789f29dbc25Smrgstatic void
790f29dbc25Smrglx_set_source_format(int srcFormat, int dstFormat)
791f29dbc25Smrg{
792f29dbc25Smrg    if (!(srcFormat & 0x10) && (dstFormat & 0x10))
79304007ebaSmrg        gp_set_source_format(srcFormat | 0x10);
794f29dbc25Smrg    else if ((srcFormat & 0x10) && (dstFormat & 0x10))
79504007ebaSmrg        gp_set_source_format(srcFormat & ~0x10);
796f29dbc25Smrg    else
79704007ebaSmrg        gp_set_source_format(srcFormat);
798f29dbc25Smrg}
799f29dbc25Smrg
800f29dbc25Smrg/* If we are converting colors and we need the channel A alpha,
801f29dbc25Smrg * then use a special alpha type that preserves the alpha before
802f29dbc25Smrg * converting the format
803f29dbc25Smrg */
804f29dbc25Smrg
805f29dbc25Smrgstatic inline int
806f29dbc25Smrgget_op_type(struct exa_format_t *src, struct exa_format_t *dst, int type)
807f29dbc25Smrg{
808f29dbc25Smrg    return (type == CIMGP_CHANNEL_A_ALPHA &&
80904007ebaSmrg            src->alphabits != dst->alphabits) ? CIMGP_CONVERTED_ALPHA : type;
810f29dbc25Smrg}
811f29dbc25Smrg
812f29dbc25Smrg/* Note - this is the preferred onepass method.  The other will remain
813f29dbc25Smrg * ifdefed out until such time that we are sure its not needed
814f29dbc25Smrg */
815f29dbc25Smrg
816170d5fdcSmrg#define GetPixmapOffset(px, x, y) ( exaGetPixmapOffset((px)) + \
817170d5fdcSmrg  (exaGetPixmapPitch((px)) * (y)) + \
818170d5fdcSmrg  ((((px)->drawable.bitsPerPixel + 7) / 8) * (x)) )
819170d5fdcSmrg
820170d5fdcSmrg#define GetSrcOffset(_x, _y) (exaScratch.srcOffset + ((_y) * exaScratch.srcPitch) + \
821170d5fdcSmrg			      ((_x) * exaScratch.srcBpp))
822170d5fdcSmrg
823170d5fdcSmrgstatic void
824170d5fdcSmrglx_composite_onepass_add_a8(PixmapPtr pxDst, unsigned long dstOffset,
82504007ebaSmrg                            unsigned long srcOffset, int width, int height,
82604007ebaSmrg                            int opX, int opY, int srcX, int srcY)
827170d5fdcSmrg{
828170d5fdcSmrg    struct blend_ops_t *opPtr;
829170d5fdcSmrg    int apply, type;
830170d5fdcSmrg    int optempX, optempY;
831170d5fdcSmrg    int i, j;
832170d5fdcSmrg    unsigned long pixmapOffset, pixmapPitch, calBitsPixel;
833170d5fdcSmrg
834170d5fdcSmrg    pixmapOffset = exaGetPixmapOffset(pxDst);
835170d5fdcSmrg    pixmapPitch = exaGetPixmapPitch(pxDst);
836170d5fdcSmrg    calBitsPixel = (pxDst->drawable.bitsPerPixel + 7) / 8;
837170d5fdcSmrg
838170d5fdcSmrg    /* Keep this GP idle judge here. Otherwise the SW method has chance to
839170d5fdcSmrg     * conflict with the HW rendering method */
840170d5fdcSmrg    gp_wait_until_idle();
841170d5fdcSmrg
842170d5fdcSmrg    if (opX % 4 == 0 && srcX % 4 == 0) {
84304007ebaSmrg        /* HW acceleration */
84404007ebaSmrg        opPtr = &lx_alpha_ops[exaScratch.op * 2];
84504007ebaSmrg        apply = CIMGP_APPLY_BLEND_TO_ALL;
84604007ebaSmrg        gp_declare_blt(0);
84704007ebaSmrg        gp_set_bpp(32);
84804007ebaSmrg        gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
84904007ebaSmrg        gp_set_source_format(8);
85004007ebaSmrg        type = opPtr->type;
85104007ebaSmrg        gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply,
85204007ebaSmrg                               0);
85304007ebaSmrg        gp_screen_to_screen_convert(dstOffset, srcOffset, width / 4, height, 0);
85404007ebaSmrg        /* Calculate the pixels in the tail of each line */
85504007ebaSmrg        for (j = srcY; j < srcY + height; j++)
85604007ebaSmrg            for (i = srcX + (width / 4) * 4; i < srcX + width; i++) {
85704007ebaSmrg                srcOffset = GetSrcOffset(i, j);
85804007ebaSmrg                optempX = opX + i - srcX;
85904007ebaSmrg                optempY = opY + j - srcY;
86004007ebaSmrg                dstOffset = pixmapOffset + pixmapPitch * optempY +
86104007ebaSmrg                    calBitsPixel * optempX;
86204007ebaSmrg                *(cim_fb_ptr + dstOffset) = (*(cim_fb_ptr + srcOffset)
86304007ebaSmrg                                             + *(cim_fb_ptr + dstOffset) <=
86404007ebaSmrg                                             0xff) ? *(cim_fb_ptr + srcOffset) +
86504007ebaSmrg                    *(cim_fb_ptr + dstOffset) : 0xff;
86604007ebaSmrg            }
86704007ebaSmrg    }
86804007ebaSmrg    else {
86904007ebaSmrg        for (j = srcY; j < srcY + height; j++)
87004007ebaSmrg            for (i = srcX; i < srcX + width; i++) {
87104007ebaSmrg                srcOffset = GetSrcOffset(i, j);
87204007ebaSmrg                optempX = opX + i - srcX;
87304007ebaSmrg                optempY = opY + j - srcY;
87404007ebaSmrg                dstOffset = pixmapOffset + pixmapPitch * optempY +
87504007ebaSmrg                    calBitsPixel * optempX;
87604007ebaSmrg                *(cim_fb_ptr + dstOffset) = (*(cim_fb_ptr + srcOffset) +
87704007ebaSmrg                                             *(cim_fb_ptr + dstOffset) <=
87804007ebaSmrg                                             0xff) ? *(cim_fb_ptr + srcOffset) +
87904007ebaSmrg                    *(cim_fb_ptr + dstOffset) : 0xff;
88004007ebaSmrg            }
881170d5fdcSmrg    }
882170d5fdcSmrg}
883170d5fdcSmrg
884f29dbc25Smrgstatic void
885f29dbc25Smrglx_composite_onepass(PixmapPtr pxDst, unsigned long dstOffset,
88604007ebaSmrg                     unsigned long srcOffset, int width, int height)
887f29dbc25Smrg{
888f29dbc25Smrg    struct blend_ops_t *opPtr;
889f29dbc25Smrg    int apply, type;
890f29dbc25Smrg
891f29dbc25Smrg    opPtr = &lx_alpha_ops[exaScratch.op * 2];
892f29dbc25Smrg
893f29dbc25Smrg    apply = (exaScratch.dstFormat->alphabits != 0 &&
89404007ebaSmrg             exaScratch.srcFormat->alphabits != 0) ?
89504007ebaSmrg        CIMGP_APPLY_BLEND_TO_ALL : CIMGP_APPLY_BLEND_TO_RGB;
896f29dbc25Smrg
897f29dbc25Smrg    gp_declare_blt(0);
898f29dbc25Smrg    gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
899f29dbc25Smrg    gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
900f29dbc25Smrg
90104007ebaSmrg    lx_set_source_format(exaScratch.srcFormat->fmt, exaScratch.dstFormat->fmt);
902f29dbc25Smrg
90304007ebaSmrg    type = get_op_type(exaScratch.srcFormat, exaScratch.dstFormat, opPtr->type);
904f29dbc25Smrg
905f29dbc25Smrg    gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0);
906f29dbc25Smrg
907f29dbc25Smrg    gp_screen_to_screen_convert(dstOffset, srcOffset, width, height, 0);
908f29dbc25Smrg}
909f29dbc25Smrg
910170d5fdcSmrgstatic void
911170d5fdcSmrglx_composite_all_black(unsigned long srcOffset, int width, int height)
912170d5fdcSmrg{
913170d5fdcSmrg    struct blend_ops_t *opPtr;
914170d5fdcSmrg    int apply, type;
915170d5fdcSmrg
916170d5fdcSmrg    opPtr = &lx_alpha_ops[0];
917170d5fdcSmrg    apply = (exaScratch.srcFormat->alphabits != 0) ?
91804007ebaSmrg        CIMGP_APPLY_BLEND_TO_ALL : CIMGP_APPLY_BLEND_TO_RGB;
919170d5fdcSmrg    gp_declare_blt(0);
920170d5fdcSmrg    gp_set_bpp(lx_get_bpp_from_format(exaScratch.srcFormat->fmt));
921170d5fdcSmrg    gp_set_strides(exaScratch.srcPitch, exaScratch.srcPitch);
92204007ebaSmrg    lx_set_source_format(exaScratch.srcFormat->fmt, exaScratch.srcFormat->fmt);
92304007ebaSmrg    type = get_op_type(exaScratch.srcFormat, exaScratch.srcFormat, opPtr->type);
924170d5fdcSmrg    gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0);
925170d5fdcSmrg    gp_screen_to_screen_convert(srcOffset, srcOffset, width, height, 0);
926170d5fdcSmrg
927170d5fdcSmrg}
928170d5fdcSmrg
929170d5fdcSmrgstatic void
930170d5fdcSmrglx_composite_onepass_special(PixmapPtr pxDst, int width, int height, int opX,
93104007ebaSmrg                             int opY, int srcX, int srcY)
932170d5fdcSmrg{
933170d5fdcSmrg    struct blend_ops_t *opPtr;
934170d5fdcSmrg    int apply, type;
935170d5fdcSmrg    int opWidth, opHeight;
936170d5fdcSmrg    int optempX, optempY;
937170d5fdcSmrg    unsigned int dstOffset, srcOffset = 0;
938170d5fdcSmrg
939170d5fdcSmrg    optempX = opX;
940170d5fdcSmrg    optempY = opY;
941170d5fdcSmrg
942170d5fdcSmrg    /* Make sure srcX and srcY are in source region */
94304007ebaSmrg    srcX = ((srcX % (int) exaScratch.srcWidth) + (int) exaScratch.srcWidth)
94404007ebaSmrg        % (int) exaScratch.srcWidth;
94504007ebaSmrg    srcY = ((srcY % (int) exaScratch.srcHeight) + (int) exaScratch.srcHeight)
94604007ebaSmrg        % (int) exaScratch.srcHeight;
947170d5fdcSmrg
948170d5fdcSmrg    opWidth = exaScratch.srcWidth - srcX;
94904007ebaSmrg    opHeight = exaScratch.srcHeight - srcY;
950170d5fdcSmrg
951170d5fdcSmrg    srcOffset = GetSrcOffset(srcX, srcY);
952170d5fdcSmrg
953170d5fdcSmrg    if (width < opWidth)
95404007ebaSmrg        opWidth = width;
955170d5fdcSmrg    if (height < opHeight)
95604007ebaSmrg        opHeight = height;
957170d5fdcSmrg
958170d5fdcSmrg    while (1) {
95904007ebaSmrg        gp_wait_until_idle();
96004007ebaSmrg        dstOffset = GetPixmapOffset(pxDst, optempX, optempY);
96104007ebaSmrg        opPtr = &lx_alpha_ops[exaScratch.op * 2];
96204007ebaSmrg        apply = (exaScratch.dstFormat->alphabits != 0 &&
96304007ebaSmrg                 exaScratch.srcFormat->alphabits != 0) ?
96404007ebaSmrg            CIMGP_APPLY_BLEND_TO_ALL : CIMGP_APPLY_BLEND_TO_RGB;
96504007ebaSmrg        gp_declare_blt(0);
96604007ebaSmrg        gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
96704007ebaSmrg        gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
96804007ebaSmrg        lx_set_source_format(exaScratch.srcFormat->fmt,
96904007ebaSmrg                             exaScratch.dstFormat->fmt);
97004007ebaSmrg        type = get_op_type(exaScratch.srcFormat, exaScratch.dstFormat,
97104007ebaSmrg                           opPtr->type);
97204007ebaSmrg        gp_set_alpha_operation(opPtr->operation, type, opPtr->channel,
97304007ebaSmrg                               apply, 0);
97404007ebaSmrg        gp_screen_to_screen_convert(dstOffset, srcOffset, opWidth, opHeight, 0);
97504007ebaSmrg
97604007ebaSmrg        optempX += opWidth;
97704007ebaSmrg        if (optempX >= opX + width) {
97804007ebaSmrg            optempX = opX;
97904007ebaSmrg            optempY += opHeight;
98004007ebaSmrg            if (optempY >= opY + height)
98104007ebaSmrg                break;
98204007ebaSmrg        }
98304007ebaSmrg        if (optempX == opX) {
98404007ebaSmrg            srcOffset = GetSrcOffset(srcX, 0);
98504007ebaSmrg            opWidth = ((opX + width) - optempX) > (exaScratch.srcWidth - srcX)
98604007ebaSmrg                ? (exaScratch.srcWidth - srcX) : ((opX + width) - optempX);
98704007ebaSmrg            opHeight = ((opY + height) - optempY) > exaScratch.srcHeight
98804007ebaSmrg                ? exaScratch.srcHeight : ((opY + height) - optempY);
98904007ebaSmrg        }
99004007ebaSmrg        else if (optempY == opY) {
99104007ebaSmrg            srcOffset = GetSrcOffset(0, srcY);
99204007ebaSmrg            opWidth = ((opX + width) - optempX) > exaScratch.srcWidth
99304007ebaSmrg                ? exaScratch.srcWidth : ((opX + width) - optempX);
99404007ebaSmrg            opHeight = ((opY + height) - optempY) > (exaScratch.srcHeight -
99504007ebaSmrg                                                     srcY)
99604007ebaSmrg                ? (exaScratch.srcHeight - srcY) : ((opY + height)
99704007ebaSmrg                                                   - optempY);
99804007ebaSmrg        }
99904007ebaSmrg        else {
100004007ebaSmrg            srcOffset = GetSrcOffset(0, 0);
100104007ebaSmrg            opWidth = ((opX + width) - optempX) > exaScratch.srcWidth
100204007ebaSmrg                ? exaScratch.srcWidth : ((opX + width) - optempX);
100304007ebaSmrg            opHeight = ((opY + height) - optempY) > exaScratch.srcHeight
100404007ebaSmrg                ? exaScratch.srcHeight : ((opY + height) - optempY);
100504007ebaSmrg        }
1006170d5fdcSmrg    }
1007170d5fdcSmrg}
1008170d5fdcSmrg
1009f29dbc25Smrg/* This function handles the multipass blend functions */
1010f29dbc25Smrg
1011f29dbc25Smrgstatic void
1012f29dbc25Smrglx_composite_multipass(PixmapPtr pxDst, unsigned long dstOffset,
101304007ebaSmrg                       unsigned long srcOffset, int width, int height)
1014f29dbc25Smrg{
1015f29dbc25Smrg    struct blend_ops_t *opPtr;
1016f29dbc25Smrg    int sbpp = lx_get_bpp_from_format(exaScratch.srcFormat->fmt);
1017f29dbc25Smrg    int apply, type;
1018f29dbc25Smrg
1019f29dbc25Smrg    /* Wait until the GP is idle - this will ensure that the scratch buffer
1020f29dbc25Smrg     * isn't occupied */
1021f29dbc25Smrg
1022f29dbc25Smrg    gp_wait_until_idle();
1023f29dbc25Smrg
1024f29dbc25Smrg    /* Copy the destination to the scratch buffer, and convert it to the
1025f29dbc25Smrg     * source format */
1026f29dbc25Smrg
1027f29dbc25Smrg    gp_declare_blt(0);
1028f29dbc25Smrg
1029f29dbc25Smrg    gp_set_bpp(sbpp);
1030f29dbc25Smrg    gp_set_source_format(exaScratch.dstFormat->fmt);
1031f29dbc25Smrg    gp_set_raster_operation(0xCC);
1032f29dbc25Smrg    gp_set_strides(exaScratch.srcPitch, exaGetPixmapPitch(pxDst));
1033f29dbc25Smrg    gp_screen_to_screen_convert(exaScratch.bufferOffset, dstOffset,
103404007ebaSmrg                                width, height, 0);
1035f29dbc25Smrg
1036f29dbc25Smrg    /* Do the first blend from the source to the scratch buffer */
1037f29dbc25Smrg
1038f29dbc25Smrg    gp_declare_blt(CIMGP_BLTFLAGS_HAZARD);
1039f29dbc25Smrg    gp_set_bpp(sbpp);
1040f29dbc25Smrg    gp_set_source_format(exaScratch.srcFormat->fmt);
1041f29dbc25Smrg    gp_set_strides(exaScratch.srcPitch, exaScratch.srcPitch);
1042f29dbc25Smrg
1043f29dbc25Smrg    opPtr = &lx_alpha_ops[exaScratch.op * 2];
1044f29dbc25Smrg
1045f29dbc25Smrg    apply = (exaScratch.srcFormat->alphabits == 0) ?
104604007ebaSmrg        CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL;
1047f29dbc25Smrg
1048f29dbc25Smrg    /* If we're destroying the source alpha bits, then make sure we
1049f29dbc25Smrg     * use the alpha before the color conversion
1050f29dbc25Smrg     */
1051f29dbc25Smrg
1052f29dbc25Smrg    gp_screen_to_screen_blt(exaScratch.bufferOffset, srcOffset, width, height,
105304007ebaSmrg                            0);
1054f29dbc25Smrg
1055f29dbc25Smrg    /* Finally, do the second blend back to the destination */
1056f29dbc25Smrg
1057f29dbc25Smrg    opPtr = &lx_alpha_ops[(exaScratch.op * 2) + 1];
1058f29dbc25Smrg
1059f29dbc25Smrg    apply = (exaScratch.dstFormat->alphabits == 0) ?
106004007ebaSmrg        CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL;
1061f29dbc25Smrg
1062f29dbc25Smrg    gp_declare_blt(CIMGP_BLTFLAGS_HAZARD);
1063f29dbc25Smrg    gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
1064f29dbc25Smrg
106504007ebaSmrg    lx_set_source_format(exaScratch.srcFormat->fmt, exaScratch.dstFormat->fmt);
1066f29dbc25Smrg
106704007ebaSmrg    type = get_op_type(exaScratch.srcFormat, exaScratch.dstFormat, opPtr->type);
1068f29dbc25Smrg
1069f29dbc25Smrg    gp_set_alpha_operation(opPtr->operation, type, opPtr->channel, apply, 0);
1070f29dbc25Smrg
1071f29dbc25Smrg    gp_screen_to_screen_convert(dstOffset, exaScratch.bufferOffset,
107204007ebaSmrg                                width, height, 0);
1073f29dbc25Smrg}
1074f29dbc25Smrg
1075f29dbc25Smrgstatic void
1076f29dbc25Smrglx_composite_rotate(PixmapPtr pxDst, unsigned long dstOffset,
107704007ebaSmrg                    unsigned int srcOffset, int width, int height)
1078f29dbc25Smrg{
1079f29dbc25Smrg    int degrees = 0;
1080f29dbc25Smrg
1081f29dbc25Smrg    gp_declare_blt(0);
1082f29dbc25Smrg    gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
1083f29dbc25Smrg    gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
1084f29dbc25Smrg
108504007ebaSmrg    lx_set_source_format(exaScratch.srcFormat->fmt, exaScratch.dstFormat->fmt);
1086f29dbc25Smrg
1087f29dbc25Smrg    gp_set_raster_operation(0xCC);
1088f29dbc25Smrg
1089f29dbc25Smrg    /* RandR rotation is counter-clockwise, our rotation
1090f29dbc25Smrg     * is clockwise, so adjust the numbers accordingly */
1091f29dbc25Smrg
1092f29dbc25Smrg    switch (exaScratch.rotate) {
1093f29dbc25Smrg    case RR_Rotate_90:
109404007ebaSmrg        degrees = 270;
109504007ebaSmrg        break;
1096f29dbc25Smrg    case RR_Rotate_180:
109704007ebaSmrg        degrees = 180;
109804007ebaSmrg        break;
1099f29dbc25Smrg    case RR_Rotate_270:
110004007ebaSmrg        degrees = 90;
110104007ebaSmrg        break;
1102f29dbc25Smrg    }
1103f29dbc25Smrg
1104f29dbc25Smrg    gp_rotate_blt(dstOffset, srcOffset, width, height, degrees);
1105f29dbc25Smrg}
1106f29dbc25Smrg
1107f29dbc25Smrgstatic void
1108f29dbc25Smrglx_do_composite_mask(PixmapPtr pxDst, unsigned long dstOffset,
110904007ebaSmrg                     unsigned int maskOffset, int width, int height)
1110f29dbc25Smrg{
1111f29dbc25Smrg    struct blend_ops_t *opPtr = &lx_alpha_ops[exaScratch.op * 2];
1112f29dbc25Smrg
1113f29dbc25Smrg    gp_declare_blt(0);
1114f29dbc25Smrg
1115f29dbc25Smrg    gp_set_source_format(exaScratch.srcFormat->fmt);
1116f29dbc25Smrg    gp_set_strides(exaGetPixmapPitch(pxDst), exaScratch.srcPitch);
1117f29dbc25Smrg    gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
1118f29dbc25Smrg    gp_set_solid_source(exaScratch.srcColor);
1119f29dbc25Smrg
1120f29dbc25Smrg    gp_blend_mask_blt(dstOffset, 0, width, height, maskOffset,
112104007ebaSmrg                      exaScratch.srcPitch, opPtr->operation,
112204007ebaSmrg                      exaScratch.fourBpp);
1123f29dbc25Smrg}
1124f29dbc25Smrg
1125170d5fdcSmrgstatic void
1126170d5fdcSmrglx_do_composite_mask_two_pass(PixmapPtr pxDst, unsigned long dstOffset,
112704007ebaSmrg                              unsigned int maskOffset, int width, int height,
112804007ebaSmrg                              int opX, int opY, xPointFixed srcPoint)
1129170d5fdcSmrg{
1130170d5fdcSmrg    int apply, type;
1131170d5fdcSmrg    struct blend_ops_t *opPtr;
1132170d5fdcSmrg    int opWidth, opHeight;
1133170d5fdcSmrg    int opoverX, opoverY;
1134170d5fdcSmrg
1135170d5fdcSmrg    opoverX = opX;
1136170d5fdcSmrg    opoverY = opY;
1137170d5fdcSmrg
1138170d5fdcSmrg    /* The rendering region should not be bigger than off-screen memory size
1139170d5fdcSmrg     * which equals to DEFAULT_EXA_SCRATCH_BFRSZ. If that happens, we split
1140170d5fdcSmrg     * the PictOpOver rendering region into several 256KB chunks. And because
1141c744f008Smrg     * of the Pitch(stride) parameter, so we use maximum width of mask picture.
1142170d5fdcSmrg     * that is to say it is a scanline rendering process */
1143170d5fdcSmrg    if (width * height * 4 > DEFAULT_EXA_SCRATCH_BFRSZ) {
114404007ebaSmrg        opWidth = width;
114504007ebaSmrg        opHeight = DEFAULT_EXA_SCRATCH_BFRSZ / (width * 4);
114604007ebaSmrg    }
114704007ebaSmrg    else {
114804007ebaSmrg        opWidth = width;
114904007ebaSmrg        opHeight = height;
1150170d5fdcSmrg    }
1151f29dbc25Smrg
1152170d5fdcSmrg    while (1) {
1153170d5fdcSmrg
115404007ebaSmrg        /* Wait until the GP is idle - this will ensure that the scratch buffer
115504007ebaSmrg         * isn't occupied */
115604007ebaSmrg
115704007ebaSmrg        gp_wait_until_idle();
115804007ebaSmrg
115904007ebaSmrg        /* Copy the source to the scratch buffer, and do a src * mask raster
116004007ebaSmrg         * operation */
116104007ebaSmrg
116204007ebaSmrg        gp_declare_blt(0);
116304007ebaSmrg        opPtr = &lx_alpha_ops[(exaScratch.op * 2) + 1];
116404007ebaSmrg        gp_set_source_format(CIMGP_SOURCE_FMT_8_8_8_8);
116504007ebaSmrg        gp_set_strides(opWidth * 4, exaScratch.srcPitch);
116604007ebaSmrg        gp_set_bpp(lx_get_bpp_from_format(CIMGP_SOURCE_FMT_8_8_8_8));
116704007ebaSmrg        gp_set_solid_source(exaScratch.srcColor);
116804007ebaSmrg        gp_blend_mask_blt(exaScratch.bufferOffset, 0, opWidth, opHeight,
116904007ebaSmrg                          maskOffset, exaScratch.srcPitch, opPtr->operation,
117004007ebaSmrg                          exaScratch.fourBpp);
117104007ebaSmrg
117204007ebaSmrg        /* Do a relative operation(refer rendercheck ops.c), and copy the
117304007ebaSmrg         * operation result to destination */
117404007ebaSmrg
117504007ebaSmrg        gp_declare_blt(CIMGP_BLTFLAGS_HAZARD);
117604007ebaSmrg        opPtr = &lx_alpha_ops[exaScratch.op * 2];
117704007ebaSmrg        apply = (exaScratch.dstFormat->alphabits == 0) ?
117804007ebaSmrg            CIMGP_APPLY_BLEND_TO_RGB : CIMGP_APPLY_BLEND_TO_ALL;
117904007ebaSmrg        gp_set_source_format(CIMGP_SOURCE_FMT_8_8_8_8);
118004007ebaSmrg        gp_set_strides(exaGetPixmapPitch(pxDst), opWidth * 4);
118104007ebaSmrg        gp_set_bpp(lx_get_bpp_from_format(exaScratch.dstFormat->fmt));
118204007ebaSmrg        type = CIMGP_CONVERTED_ALPHA;
118304007ebaSmrg        gp_set_alpha_operation(opPtr->operation, type, opPtr->channel,
118404007ebaSmrg                               apply, 0);
118504007ebaSmrg        gp_screen_to_screen_convert(dstOffset, exaScratch.bufferOffset,
118604007ebaSmrg                                    opWidth, opHeight, 0);
118704007ebaSmrg
118804007ebaSmrg        if (width * height * 4 > DEFAULT_EXA_SCRATCH_BFRSZ) {
118904007ebaSmrg            /* Finish the rendering */
119004007ebaSmrg            if (opoverY + opHeight == opY + height)
119104007ebaSmrg                break;
119204007ebaSmrg            /* Recalculate the Dest and Mask rendering start point */
119304007ebaSmrg            srcPoint.y = srcPoint.y + F(opHeight);
119404007ebaSmrg            opoverY = opoverY + opHeight;
119504007ebaSmrg            if (opoverY + opHeight > opY + height)
119604007ebaSmrg                opHeight = opY + height - opoverY;
119704007ebaSmrg            dstOffset = GetPixmapOffset(pxDst, opoverX, opoverY);
119804007ebaSmrg            maskOffset = GetSrcOffset(I(srcPoint.x), I(srcPoint.y));
119904007ebaSmrg        }
120004007ebaSmrg        else
120104007ebaSmrg            break;
1202170d5fdcSmrg    }
1203170d5fdcSmrg}
1204f29dbc25Smrg
1205f29dbc25Smrgstatic void
1206f29dbc25SmrgtransformPoint(PictTransform * t, xPointFixed * point)
1207f29dbc25Smrg{
1208f29dbc25Smrg    PictVector v;
1209f29dbc25Smrg
1210f29dbc25Smrg    v.vector[0] = point->x;
1211f29dbc25Smrg    v.vector[1] = point->y;
1212f29dbc25Smrg    v.vector[2] = xFixed1;
1213f29dbc25Smrg
1214f29dbc25Smrg    if (t != NULL)
121504007ebaSmrg        PictureTransformPoint(t, &v);
1216f29dbc25Smrg
1217f29dbc25Smrg    point->x = v.vector[0];
1218f29dbc25Smrg    point->y = v.vector[1];
1219f29dbc25Smrg}
1220f29dbc25Smrg
1221f29dbc25Smrgstatic void
1222f29dbc25Smrglx_do_composite(PixmapPtr pxDst, int srcX, int srcY, int maskX,
122304007ebaSmrg                int maskY, int dstX, int dstY, int width, int height)
1224f29dbc25Smrg{
1225f29dbc25Smrg    unsigned int dstOffset, srcOffset = 0;
1226f29dbc25Smrg
1227f29dbc25Smrg    xPointFixed srcPoint;
1228f29dbc25Smrg
1229f29dbc25Smrg    int opX = dstX;
1230f29dbc25Smrg    int opY = dstY;
1231f29dbc25Smrg    int opWidth = width;
1232f29dbc25Smrg    int opHeight = height;
1233f29dbc25Smrg
1234f29dbc25Smrg    /* Transform the source coordinates */
1235f29dbc25Smrg
1236f29dbc25Smrg    if (exaScratch.type == COMP_TYPE_MASK) {
123704007ebaSmrg        srcPoint.x = F(maskX);
123804007ebaSmrg        srcPoint.y = F(maskY);
123904007ebaSmrg    }
124004007ebaSmrg    else {
124104007ebaSmrg        srcPoint.x = F(srcX);
124204007ebaSmrg        srcPoint.y = F(srcY);
1243f29dbc25Smrg    }
1244f29dbc25Smrg
1245f29dbc25Smrg    /* srcX, srcY point to the upper right side of the bounding box
1246f29dbc25Smrg     * in the unrotated coordinate space.  Depending on the orientation,
1247f29dbc25Smrg     * we have to translate the coordinates to point to the origin of
1248f29dbc25Smrg     * the rectangle in the source pixmap */
1249f29dbc25Smrg
1250f29dbc25Smrg    switch (exaScratch.rotate) {
1251f29dbc25Smrg    case RR_Rotate_270:
125204007ebaSmrg        srcPoint.x += F(width);
1253f29dbc25Smrg
125404007ebaSmrg        opWidth = height;
125504007ebaSmrg        opHeight = width;
125604007ebaSmrg        break;
1257f29dbc25Smrg
1258f29dbc25Smrg    case RR_Rotate_180:
125904007ebaSmrg        srcPoint.x += F(width);
126004007ebaSmrg        srcPoint.y += F(height);
1261f29dbc25Smrg
126204007ebaSmrg        srcX += width;
126304007ebaSmrg        srcY += height;
126404007ebaSmrg        break;
1265f29dbc25Smrg
1266f29dbc25Smrg    case RR_Rotate_90:
126704007ebaSmrg        srcPoint.y += F(height);
1268f29dbc25Smrg
126904007ebaSmrg        opWidth = height;
127004007ebaSmrg        opHeight = width;
127104007ebaSmrg        break;
1272f29dbc25Smrg    }
1273f29dbc25Smrg
1274f29dbc25Smrg    transformPoint(exaScratch.transform, &srcPoint);
1275f29dbc25Smrg
1276f29dbc25Smrg    /* Adjust the point to fit into the pixmap */
1277f29dbc25Smrg
1278f29dbc25Smrg    if (I(srcPoint.x) < 0) {
127904007ebaSmrg        opWidth += I(srcPoint.x);
128004007ebaSmrg        srcPoint.x = F(0);
1281f29dbc25Smrg    }
1282f29dbc25Smrg
1283f29dbc25Smrg    if (I(srcPoint.y) < 0) {
128404007ebaSmrg        opHeight += I(srcPoint.y);
128504007ebaSmrg        srcPoint.y = F(0);
1286f29dbc25Smrg    }
1287f29dbc25Smrg
1288170d5fdcSmrg    /* Get the source point offset position */
1289170d5fdcSmrg
1290f29dbc25Smrg    srcOffset = GetSrcOffset(I(srcPoint.x), I(srcPoint.y));
1291f29dbc25Smrg
1292170d5fdcSmrg    /* When mask exists, exaScratch.srcWidth and exaScratch.srcHeight are
1293170d5fdcSmrg     * the source width and source height; Otherwise, they are mask width
1294170d5fdcSmrg     * and mask height */
1295170d5fdcSmrg    /* exaScratch.repeat is the source repeat attribute
1296170d5fdcSmrg     * exaScratch.maskrepeat is the mask repeat attribute */
1297170d5fdcSmrg    /* If type is COMP_TYPE_MASK, maskX and maskY are not zero, we should
1298170d5fdcSmrg     * subtract them to do the operation in the correct region */
1299f29dbc25Smrg
1300170d5fdcSmrg    /* FIXME:  Please add the code to handle the condition when the maskX
1301170d5fdcSmrg     * and maskY coordinate are negative or greater than
1302170d5fdcSmrg     * exaScratch.srcWidth and exaScratch.srcHeight */
1303170d5fdcSmrg
1304170d5fdcSmrg    if (exaScratch.type == COMP_TYPE_MASK) {
130504007ebaSmrg        if ((exaScratch.srcWidth - maskX) < opWidth)
130604007ebaSmrg            opWidth = exaScratch.srcWidth - maskX;
130704007ebaSmrg        if ((exaScratch.srcHeight - maskY) < opHeight)
130804007ebaSmrg            opHeight = exaScratch.srcHeight - maskY;
130904007ebaSmrg    }
131004007ebaSmrg    else {
131104007ebaSmrg        if (exaScratch.type == COMP_TYPE_ONEPASS) {
131204007ebaSmrg            /* This is the condition srcX or/and srcY is/are out of source
131304007ebaSmrg             * region */
131404007ebaSmrg            if (((srcY >= 0 && srcY >= exaScratch.srcHeight)
131504007ebaSmrg                 || (srcX >= 0 && srcX >= exaScratch.srcWidth)) &&
131604007ebaSmrg                (exaScratch.op == PictOpOver || exaScratch.op == PictOpSrc)) {
131704007ebaSmrg                if (exaScratch.repeat == 1) {
131804007ebaSmrg                    opWidth = width;
131904007ebaSmrg                    opHeight = height;
132004007ebaSmrg                }
132104007ebaSmrg                else {
132204007ebaSmrg                    if (exaScratch.op == PictOpOver)
132304007ebaSmrg                        return;
132404007ebaSmrg                    else {
132504007ebaSmrg                        exaScratch.op = PictOpClear;
132604007ebaSmrg                        opWidth = width;
132704007ebaSmrg                        opHeight = height;
132804007ebaSmrg                    }
132904007ebaSmrg                }
133004007ebaSmrg                /* This is the condition srcX or/and srcY is/are in the source
133104007ebaSmrg                 * region */
133204007ebaSmrg            }
133304007ebaSmrg            else if (srcX >= 0 && srcY >= 0 &&
133404007ebaSmrg                     (exaScratch.op == PictOpOver ||
133504007ebaSmrg                      exaScratch.op == PictOpSrc)) {
133604007ebaSmrg                if (exaScratch.repeat == 1) {
133704007ebaSmrg                    opWidth = width;
133804007ebaSmrg                    opHeight = height;
133904007ebaSmrg                }
134004007ebaSmrg                else {
134104007ebaSmrg                    if ((exaScratch.srcWidth - srcX) < opWidth)
134204007ebaSmrg                        opWidth = exaScratch.srcWidth - srcX;
134304007ebaSmrg                    if ((exaScratch.srcHeight - srcY) < opHeight)
134404007ebaSmrg                        opHeight = exaScratch.srcHeight - srcY;
134504007ebaSmrg                }
134604007ebaSmrg                /* This is the condition srcX or/and srcY is/are negative */
134704007ebaSmrg            }
134804007ebaSmrg            else if ((srcX < 0 || srcY < 0) &&
134904007ebaSmrg                     (exaScratch.op == PictOpOver ||
135004007ebaSmrg                      exaScratch.op == PictOpSrc)) {
135104007ebaSmrg                if (exaScratch.repeat == 1) {
135204007ebaSmrg                    opWidth = width;
135304007ebaSmrg                    opHeight = height;
135404007ebaSmrg                }
135504007ebaSmrg                else {
135604007ebaSmrg                    /* FIXME: We can't support negative srcX/Y for all corner cases in
135704007ebaSmrg                     * a sane way without a bit bigger refactoring. So as to avoid
135804007ebaSmrg                     * gross misrenderings (e.g missing tray icons) in current real-world
135904007ebaSmrg                     * applications, just shift destination appropriately for now and
136004007ebaSmrg                     * ignore out of bounds source pixmap zero-vector handling. This is
136104007ebaSmrg                     * actually correct for PictOpOver, but PictOpSrc out of bounds regions
136204007ebaSmrg                     * should be blacked out, but aren't - without this workaround however
136304007ebaSmrg                     * it'd be simply all black instead, which is probably worse till a full
136404007ebaSmrg                     * clean solution solves it for all cases. */
136504007ebaSmrg                    if (srcX < 0) {
136604007ebaSmrg                        opX -= srcX;
136704007ebaSmrg                        srcX = 0;
136804007ebaSmrg                    }
136904007ebaSmrg
137004007ebaSmrg                    if (srcY < 0) {
137104007ebaSmrg                        opY -= srcY;
137204007ebaSmrg                        srcY = 0;
137304007ebaSmrg                    }
137404007ebaSmrg
137504007ebaSmrg                    /* EXA has taken care of adjusting srcWidth if it gets cut on the right */
137604007ebaSmrg                    width = opWidth = exaScratch.srcWidth;
137704007ebaSmrg                    /* EXA has taken care of adjusting srcHeight if it gets cut on the bottom */
137804007ebaSmrg                    height = opHeight = exaScratch.srcHeight;
137904007ebaSmrg                }
138004007ebaSmrg            }
138104007ebaSmrg            else {
138204007ebaSmrg                if (exaScratch.srcWidth < opWidth)
138304007ebaSmrg                    opWidth = exaScratch.srcWidth;
138404007ebaSmrg                if (exaScratch.srcHeight < opHeight)
138504007ebaSmrg                    opHeight = exaScratch.srcHeight;
138604007ebaSmrg            }
138704007ebaSmrg        }
138804007ebaSmrg        else {
138904007ebaSmrg            if (exaScratch.rotate == RR_Rotate_180) {
139004007ebaSmrg            }
139104007ebaSmrg            else {
139204007ebaSmrg                if ((exaScratch.srcWidth - srcY) < opWidth)
139304007ebaSmrg                    opWidth = exaScratch.srcWidth - srcY;
139404007ebaSmrg                if ((exaScratch.srcHeight - srcX) < opHeight)
139504007ebaSmrg                    opHeight = exaScratch.srcHeight - srcX;
139604007ebaSmrg            }
139704007ebaSmrg        }
1398170d5fdcSmrg    }
1399f29dbc25Smrg
1400f29dbc25Smrg    while (1) {
1401f29dbc25Smrg
140204007ebaSmrg        dstOffset = GetPixmapOffset(pxDst, opX, opY);
140304007ebaSmrg
140404007ebaSmrg        switch (exaScratch.type) {
140504007ebaSmrg
140604007ebaSmrg        case COMP_TYPE_MASK:{
140704007ebaSmrg            if (exaScratch.op == PictOpOver || exaScratch.op ==
140804007ebaSmrg                PictOpOutReverse || exaScratch.op == PictOpInReverse ||
140904007ebaSmrg                exaScratch.op == PictOpIn || exaScratch.op == PictOpOut ||
141004007ebaSmrg                exaScratch.op == PictOpOverReverse)
141104007ebaSmrg                lx_do_composite_mask_two_pass(pxDst, dstOffset,
141204007ebaSmrg                                              srcOffset, opWidth, opHeight, opX,
141304007ebaSmrg                                              opY, srcPoint);
141404007ebaSmrg            else
141504007ebaSmrg                lx_do_composite_mask(pxDst, dstOffset, srcOffset,
141604007ebaSmrg                                     opWidth, opHeight);
141704007ebaSmrg        }
141804007ebaSmrg            break;
141904007ebaSmrg
142004007ebaSmrg        case COMP_TYPE_ONEPASS:
142104007ebaSmrg            if ((exaScratch.op == PictOpOver || exaScratch.op == PictOpSrc)
142204007ebaSmrg                && (exaScratch.repeat == 1)) {
142304007ebaSmrg                lx_composite_onepass_special(pxDst, opWidth, opHeight, opX, opY,
142404007ebaSmrg                                             srcX, srcY);
142504007ebaSmrg                return;
142604007ebaSmrg            }
142704007ebaSmrg            else if ((exaScratch.op == PictOpAdd) && (exaScratch.srcFormat->exa
142804007ebaSmrg                                                      == PICT_a8) &&
142904007ebaSmrg                     (exaScratch.dstFormat->exa == PICT_a8))
143004007ebaSmrg                lx_composite_onepass_add_a8(pxDst, dstOffset, srcOffset,
143104007ebaSmrg                                            opWidth, opHeight, opX, opY, srcX,
143204007ebaSmrg                                            srcY);
143304007ebaSmrg            else
143404007ebaSmrg                lx_composite_onepass(pxDst, dstOffset, srcOffset, opWidth,
143504007ebaSmrg                                     opHeight);
143604007ebaSmrg            break;
143704007ebaSmrg
143804007ebaSmrg        case COMP_TYPE_TWOPASS:
143904007ebaSmrg            lx_composite_multipass(pxDst, dstOffset, srcOffset, opWidth,
144004007ebaSmrg                                   opHeight);
144104007ebaSmrg
144204007ebaSmrg        case COMP_TYPE_ROTATE:
144304007ebaSmrg            lx_composite_rotate(pxDst, dstOffset, srcOffset, opWidth, opHeight);
144404007ebaSmrg            break;
144504007ebaSmrg        }
144604007ebaSmrg
144704007ebaSmrg        opX += opWidth;
144804007ebaSmrg
144904007ebaSmrg        if (opX >= dstX + width) {
145004007ebaSmrg            opX = dstX;
145104007ebaSmrg            opY += opHeight;
145204007ebaSmrg
145304007ebaSmrg            if (opY >= dstY + height)
145404007ebaSmrg                break;
145504007ebaSmrg        }
145604007ebaSmrg
145704007ebaSmrg        /* FIXME:  Please add the code to handle the condition when the maskX
145804007ebaSmrg         * and maskY coordinate are negative or greater than
145904007ebaSmrg         * exaScratch.srcWidth and exaScratch.srcHeight */
146004007ebaSmrg
146104007ebaSmrg        if (exaScratch.type == COMP_TYPE_MASK) {
146204007ebaSmrg            opWidth = ((dstX + width) - opX) > (exaScratch.srcWidth - maskX)
146304007ebaSmrg                ? (exaScratch.srcWidth - maskX) : (dstX + width) - opX;
146404007ebaSmrg            opHeight = ((dstY + height) - opY) > (exaScratch.srcHeight - maskY)
146504007ebaSmrg                ? (exaScratch.srcHeight - maskY) : (dstY + height) - opY;
146604007ebaSmrg            /* All black out of the mask */
146704007ebaSmrg            if (!exaScratch.maskrepeat)
146804007ebaSmrg                exaScratch.srcColor = 0x0;
146904007ebaSmrg        }
147004007ebaSmrg        else {
147104007ebaSmrg            if (exaScratch.type == COMP_TYPE_ONEPASS) {
147204007ebaSmrg                if (srcX >= 0 && srcY >= 0 && (exaScratch.op == PictOpOver ||
147304007ebaSmrg                                               exaScratch.op == PictOpSrc ||
147404007ebaSmrg                                               exaScratch.op == PictOpClear)) {
147504007ebaSmrg                    opWidth =
147604007ebaSmrg                        ((dstX + width) - opX) >
147704007ebaSmrg                        (exaScratch.srcWidth - srcX) ? (exaScratch.srcWidth -
147804007ebaSmrg                                                        srcX) : (dstX + width)
147904007ebaSmrg                        - opX;
148004007ebaSmrg                    opHeight = ((dstY + height) - opY) >
148104007ebaSmrg                        (exaScratch.srcHeight - srcY) ?
148204007ebaSmrg                        (exaScratch.srcHeight - srcY) : (dstY + height) - opY;
148304007ebaSmrg                }
148404007ebaSmrg                else {
148504007ebaSmrg                    opWidth = ((dstX + width) - opX) > exaScratch.srcWidth ?
148604007ebaSmrg                        exaScratch.srcWidth : (dstX + width) - opX;
148704007ebaSmrg                    opHeight = ((dstY + height) - opY) > exaScratch.srcHeight ?
148804007ebaSmrg                        exaScratch.srcHeight : (dstY + height) - opY;
148904007ebaSmrg                }
149004007ebaSmrg            }
149104007ebaSmrg            else {
149204007ebaSmrg                opWidth = ((dstX + width) - opX) > (exaScratch.srcWidth - srcY)
149304007ebaSmrg                    ? (exaScratch.srcWidth - srcY) : (dstX + width) - opX;
149404007ebaSmrg                opHeight =
149504007ebaSmrg                    ((dstY + height) - opY) >
149604007ebaSmrg                    (exaScratch.srcHeight - srcX) ? (exaScratch.srcHeight -
149704007ebaSmrg                                                     srcX) : (dstY + height) -
149804007ebaSmrg                    opY;
149904007ebaSmrg            }
150004007ebaSmrg            /* All black out of the source */
150104007ebaSmrg            if (!exaScratch.repeat && (exaScratch.type == COMP_TYPE_ONEPASS)) {
150204007ebaSmrg                /* FIXME: We black out the source here, so that any further regions
150304007ebaSmrg                 * in the loop get handled as a source that's a zero-vector (as
150404007ebaSmrg                 * defined for out-of-bounds from source pixmap for RepeatModeNone),
150504007ebaSmrg                 * but this will likely interfere with cases where srcX and/or srcY
150604007ebaSmrg                 * is negative - as opposed to e.g width being larger than srcWidth,
150704007ebaSmrg                 * which is exercised in rendercheck (always rectangle in top-left
150804007ebaSmrg                 * corner).
150904007ebaSmrg                 * Additionally it forces the drawing into tiles of srcWidth/srcHeight
151004007ebaSmrg                 * for non-repeat modes too, where we don't really need to tile it like
151104007ebaSmrg                 * this and could draw the out of bound regions all at once (or at most
151204007ebaSmrg                 * in 4 operations without the big loop). */
151304007ebaSmrg                lx_composite_all_black(srcOffset, exaScratch.srcWidth,
151404007ebaSmrg                                       exaScratch.srcHeight);
151504007ebaSmrg            }
151604007ebaSmrg            if (!exaScratch.repeat && (exaScratch.type == COMP_TYPE_ROTATE))
151704007ebaSmrg                break;
151804007ebaSmrg        }
1519f29dbc25Smrg    }
1520f29dbc25Smrg}
1521f29dbc25Smrg
1522f29dbc25Smrgstatic void
1523f29dbc25Smrglx_wait_marker(ScreenPtr PScreen, int marker)
1524f29dbc25Smrg{
1525f29dbc25Smrg    gp_wait_until_idle();
1526f29dbc25Smrg}
1527f29dbc25Smrg
1528f29dbc25Smrgstatic void
1529f29dbc25Smrglx_done(PixmapPtr ptr)
1530f29dbc25Smrg{
1531f29dbc25Smrg}
1532f29dbc25Smrg
1533f29dbc25Smrg#if 0
1534f29dbc25Smrgstatic void
1535f29dbc25Smrglx_upload_to_screen(PixmapPtr pxDst, int x, int y, int w, int h,
153604007ebaSmrg                    char *src, int src_pitch)
1537f29dbc25Smrg{
1538f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR_FROM_PIXMAP(pxDst);
1539f29dbc25Smrg    int dst_pitch = exaGetPixmapPitch(pxDst);
1540f29dbc25Smrg    int cpp = (pxDst->drawable.bitsPerPixel + 7) / 8;
1541f29dbc25Smrg
1542f29dbc25Smrg    char *dst;
1543f29dbc25Smrg    int offset = exaGetPixmapOffset(pxDst);
1544f29dbc25Smrg
154504007ebaSmrg    dst = (char *) (pGeode->FBBase + offset + (y * dst_pitch) + (x * cpp));
1546f29dbc25Smrg    int i;
1547f29dbc25Smrg
1548f29dbc25Smrg    for (i = 0; i < h; i++) {
154904007ebaSmrg        memcpy(dst, src, w * cpp);
155004007ebaSmrg        dst += dst_pitch;
155104007ebaSmrg        src += src_pitch;
1552f29dbc25Smrg    }
1553f29dbc25Smrg}
1554f29dbc25Smrg#endif
1555f29dbc25Smrg
155604007ebaSmrg#if EXA_VERSION_MAJOR > 2 || (EXA_VERSION_MAJOR == 2 && EXA_VERSION_MINOR >= 2)
1557f29dbc25Smrg
1558f29dbc25Smrgstatic Bool
1559f29dbc25Smrglx_exa_pixmap_is_offscreen(PixmapPtr pPixmap)
1560f29dbc25Smrg{
156104007ebaSmrg    ScrnInfoPtr pScrni = xf86ScreenToScrn(pPixmap->drawable.pScreen);
1562f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
156304007ebaSmrg    void *start = (void *) (pGeode->FBBase);
1564f29dbc25Smrg    void *end =
156504007ebaSmrg        (void *) (pGeode->FBBase + pGeode->offscreenStart +
156604007ebaSmrg                  pGeode->offscreenSize);
1567f29dbc25Smrg
156804007ebaSmrg    if ((void *) pPixmap->devPrivate.ptr >= start &&
156904007ebaSmrg        (void *) pPixmap->devPrivate.ptr < end)
157004007ebaSmrg        return TRUE;
1571f29dbc25Smrg
1572f29dbc25Smrg    return FALSE;
1573f29dbc25Smrg}
1574f29dbc25Smrg
1575f29dbc25Smrg#endif
1576f29dbc25Smrg
1577f29dbc25SmrgBool
1578f29dbc25SmrgLXExaInit(ScreenPtr pScreen)
1579f29dbc25Smrg{
158004007ebaSmrg    ScrnInfoPtr pScrni = xf86ScreenToScrn(pScreen);
1581f29dbc25Smrg    GeodeRec *pGeode = GEODEPTR(pScrni);
1582f29dbc25Smrg    ExaDriverPtr pExa = pGeode->pExa;
1583f29dbc25Smrg
1584f29dbc25Smrg    pExa->exa_major = EXA_VERSION_MAJOR;
1585f29dbc25Smrg    pExa->exa_minor = EXA_VERSION_MINOR;
1586f29dbc25Smrg
1587f29dbc25Smrg    pExa->WaitMarker = lx_wait_marker;
1588f29dbc25Smrg
1589f29dbc25Smrg    pExa->PrepareSolid = lx_prepare_solid;
1590f29dbc25Smrg    pExa->Solid = lx_do_solid;
1591f29dbc25Smrg    pExa->DoneSolid = lx_done;
1592f29dbc25Smrg
1593f29dbc25Smrg    pExa->PrepareCopy = lx_prepare_copy;
1594f29dbc25Smrg    pExa->Copy = lx_do_copy;
1595f29dbc25Smrg    pExa->DoneCopy = lx_done;
1596f29dbc25Smrg
1597f29dbc25Smrg    /* Composite */
1598f29dbc25Smrg    pExa->CheckComposite = lx_check_composite;
1599f29dbc25Smrg    pExa->PrepareComposite = lx_prepare_composite;
1600f29dbc25Smrg    pExa->Composite = lx_do_composite;
1601f29dbc25Smrg    pExa->DoneComposite = lx_done;
1602f29dbc25Smrg    //pExa->UploadToScreen =  lx_upload_to_screen;
1603f29dbc25Smrg
160404007ebaSmrg#if EXA_VERSION_MAJOR > 2 || (EXA_VERSION_MAJOR == 2 && EXA_VERSION_MINOR >= 2)
1605f29dbc25Smrg    pExa->PixmapIsOffscreen = lx_exa_pixmap_is_offscreen;
1606f29dbc25Smrg#endif
1607f29dbc25Smrg
1608f29dbc25Smrg    //pExa->flags = EXA_OFFSCREEN_PIXMAPS;
1609f29dbc25Smrg
1610f29dbc25Smrg    return exaDriverInit(pScreen, pGeode->pExa);
1611f29dbc25Smrg}
1612