cg6_exa.c revision 65d21144
1/*
2 * Sun GX and Turbo GX EXA support
3 *
4 * Copyright (C) 2015 Michael Lorenz
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * MICHAEL LORENZ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/suncg6/cg6_accel.c $ */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include "cg6.h"
30#include "cg6_regs.h"
31
32
33static CARD32 Cg6BlitROP[] = {
34    ROP_BLIT(GX_ROP_CLEAR,  GX_ROP_CLEAR),	/* GXclear */
35    ROP_BLIT(GX_ROP_CLEAR,  GX_ROP_NOOP),	/* GXand */
36    ROP_BLIT(GX_ROP_CLEAR,  GX_ROP_INVERT),	/* GXandReverse */
37    ROP_BLIT(GX_ROP_CLEAR,  GX_ROP_SET),	/* GXcopy */
38    ROP_BLIT(GX_ROP_NOOP,   GX_ROP_CLEAR),	/* GXandInverted */
39    ROP_BLIT(GX_ROP_NOOP,   GX_ROP_NOOP),	/* GXnoop */
40    ROP_BLIT(GX_ROP_NOOP,   GX_ROP_INVERT),	/* GXxor */
41    ROP_BLIT(GX_ROP_NOOP,   GX_ROP_SET),	/* GXor */
42    ROP_BLIT(GX_ROP_INVERT, GX_ROP_CLEAR),	/* GXnor */
43    ROP_BLIT(GX_ROP_INVERT, GX_ROP_NOOP),	/* GXequiv */
44    ROP_BLIT(GX_ROP_INVERT, GX_ROP_INVERT),	/* GXinvert */
45    ROP_BLIT(GX_ROP_INVERT, GX_ROP_SET),	/* GXorReverse */
46    ROP_BLIT(GX_ROP_SET,    GX_ROP_CLEAR),	/* GXcopyInverted */
47    ROP_BLIT(GX_ROP_SET,    GX_ROP_NOOP),	/* GXorInverted */
48    ROP_BLIT(GX_ROP_SET,    GX_ROP_INVERT),	/* GXnand */
49    ROP_BLIT(GX_ROP_SET,    GX_ROP_SET),	/* GXset */
50};
51
52static CARD32 Cg6DrawROP[] = {
53    ROP_FILL(GX_ROP_CLEAR,  GX_ROP_CLEAR),	/* GXclear */
54    ROP_FILL(GX_ROP_CLEAR,  GX_ROP_NOOP),	/* GXand */
55    ROP_FILL(GX_ROP_CLEAR,  GX_ROP_INVERT),	/* GXandReverse */
56    ROP_FILL(GX_ROP_CLEAR,  GX_ROP_SET),	/* GXcopy */
57    ROP_FILL(GX_ROP_NOOP,   GX_ROP_CLEAR),	/* GXandInverted */
58    ROP_FILL(GX_ROP_NOOP,   GX_ROP_NOOP),	/* GXnoop */
59    ROP_FILL(GX_ROP_NOOP,   GX_ROP_INVERT),	/* GXxor */
60    ROP_FILL(GX_ROP_NOOP,   GX_ROP_SET),	/* GXor */
61    ROP_FILL(GX_ROP_INVERT, GX_ROP_CLEAR),	/* GXnor */
62    ROP_FILL(GX_ROP_INVERT, GX_ROP_NOOP),	/* GXequiv */
63    ROP_FILL(GX_ROP_INVERT, GX_ROP_INVERT),	/* GXinvert */
64    ROP_FILL(GX_ROP_INVERT, GX_ROP_SET),	/* GXorReverse */
65    ROP_FILL(GX_ROP_SET,    GX_ROP_CLEAR),	/* GXcopyInverted */
66    ROP_FILL(GX_ROP_SET,    GX_ROP_NOOP),	/* GXorInverted */
67    ROP_FILL(GX_ROP_SET,    GX_ROP_INVERT),	/* GXnand */
68    ROP_FILL(GX_ROP_SET,    GX_ROP_SET),	/* GXset */
69};
70
71#define runDraw(pCg6) { volatile CARD32 rubbish = pCg6->fbc->draw; }
72#define runBlit(pCg6) { volatile CARD32 rubbish = pCg6->fbc->blit; }
73
74/*
75 * XXX
76 * was GX_FULL, which apparently isn't enough on some (slower) CG6 like
77 * the one found on the SPARCstation LX mainboard
78 */
79#define waitReady(pCg6) while(pCg6->fbc->s & GX_INPROGRESS)
80
81void Cg6InitEngine(Cg6Ptr);
82
83static void
84Cg6WaitMarker(ScreenPtr pScreen, int Marker)
85{
86	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
87	Cg6Ptr p = GET_CG6_FROM_SCRN(pScrn);
88
89	waitReady(p);
90}
91
92static Bool
93Cg6PrepareCopy
94(
95    PixmapPtr pSrcPixmap,
96    PixmapPtr pDstPixmap,
97    int       xdir,
98    int       ydir,
99    int       alu,
100    Pixel     planemask
101)
102{
103    ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
104    Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn);
105
106    waitReady(pCg6);
107
108    pCg6->fbc->mode = GX_BLIT_SRC |
109		GX_MODE_COLOR8 |
110		GX_DRAW_RENDER |
111		GX_BWRITE0_ENABLE |
112		GX_BWRITE1_DISABLE |
113		GX_BREAD_0 |
114		GX_BDISP_0;
115
116    /* we probably don't need the following three */
117    pCg6->fbc->fg = 0xff;
118    pCg6->fbc->bg = 0x00;
119    pCg6->fbc->s = 0;
120
121    pCg6->srcoff = exaGetPixmapOffset(pSrcPixmap) / pCg6->width;
122    pCg6->fbc->alu = Cg6BlitROP[alu];
123    pCg6->fbc->pm = planemask;
124    return TRUE;
125}
126
127static void
128Cg6Copy
129(
130    PixmapPtr pDstPixmap,
131    int       xSrc,
132    int       ySrc,
133    int       xDst,
134    int       yDst,
135    int       w,
136    int       h
137)
138{
139    ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
140    Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn);
141    int doff;
142
143    doff = exaGetPixmapOffset(pDstPixmap) / pCg6->width;
144    waitReady(pCg6);
145    pCg6->fbc->x0 = xSrc;
146    pCg6->fbc->y0 = ySrc + pCg6->srcoff;
147    pCg6->fbc->x1 = xSrc + w - 1;
148    pCg6->fbc->y1 = ySrc + pCg6->srcoff + h - 1;
149    pCg6->fbc->x2 = xDst;
150    pCg6->fbc->y2 = yDst + doff;
151    pCg6->fbc->x3 = xDst + w - 1;
152    pCg6->fbc->y3 = yDst + doff + h - 1;
153    runBlit(pCg6);
154    exaMarkSync(pDstPixmap->drawable.pScreen);
155}
156
157static void
158Cg6DoneCopy(PixmapPtr pDstPixmap)
159{
160    ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
161    Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn);
162
163    waitReady(pCg6);
164}
165
166static Bool
167Cg6PrepareSolid(
168    PixmapPtr pPixmap,
169    int alu,
170    Pixel planemask,
171    Pixel fg)
172{
173    ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
174    Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn);
175    CARD32 c2;
176
177    pCg6->srcoff = exaGetPixmapOffset(pPixmap) / pCg6->width;
178
179    waitReady(pCg6);
180
181    pCg6->fbc->mode = GX_BLIT_SRC |
182		GX_MODE_COLOR8 |
183		GX_DRAW_RENDER |
184		GX_BWRITE0_ENABLE |
185		GX_BWRITE1_DISABLE |
186		GX_BREAD_0 |
187		GX_BDISP_0;
188    pCg6->fbc->fg = fg;
189    pCg6->fbc->s = 0;
190    pCg6->fbc->alu = Cg6DrawROP[alu];
191    pCg6->fbc->pm = planemask;
192    return TRUE;
193}
194
195static void
196Cg6Solid(
197    PixmapPtr pPixmap,
198    int x,
199    int y,
200    int x2,
201    int y2)
202{
203    ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
204    Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn);
205
206    waitReady(pCg6);
207    pCg6->fbc->arecty = y + pCg6->srcoff;
208    pCg6->fbc->arectx = x;
209    pCg6->fbc->rrecty = y2 - y - 1;
210    pCg6->fbc->rrectx = x2 - x - 1;
211    runDraw(pCg6);
212    exaMarkSync(pPixmap->drawable.pScreen);
213}
214
215/*
216 * Memcpy-based UTS.
217 * TODO: use host blit
218 */
219static Bool
220Cg6UploadToScreen(PixmapPtr pDst, int x, int y, int w, int h,
221    char *src, int src_pitch)
222{
223    ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
224    Cg6Ptr pCg6       = GET_CG6_FROM_SCRN(pScrn);
225    uint32_t *sline;
226    int    dst_pitch  = exaGetPixmapPitch(pDst);
227    int    dst_line   = y + exaGetPixmapOffset(pDst) / pCg6->width;
228    int    i, bits;
229    int    words = (w + 3) >> 2;
230
231    /* clip to the destination */
232    pCg6->fbc->clipmaxx = x + w - 1;
233    pCg6->fbc->clipminx = x;
234
235    /* see if the source is aligned, if not adjust */
236    bits = ((long)src) & 3;
237    if (bits != 0) {
238    	src -= bits;
239    	w += bits;
240	words = (w + 3) >> 2;
241	x -= bits;
242    }
243
244    /* we assume that source pitch is always a multiple of 4 */
245    if ((src_pitch & 3) != 0)
246    	xf86Msg(X_ERROR, "pitch %d\n", src_pitch);
247    waitReady(pCg6);
248
249    pCg6->fbc->mode = GX_BLIT_NOSRC |
250		GX_MODE_COLOR8 |
251		GX_DRAW_RENDER |
252		GX_BWRITE0_ENABLE |
253		GX_BWRITE1_DISABLE |
254		GX_BREAD_0 |
255		GX_BDISP_0;
256
257    pCg6->fbc->alu = Cg6BlitROP[GXcopy];
258    pCg6->fbc->pm = 0xffffffff;
259    pCg6->fbc->incx = 4;
260    pCg6->fbc->incy = 0;
261    while (h--) {
262        pCg6->fbc->x0 = x;
263        pCg6->fbc->x1 = x + 3;
264        pCg6->fbc->y0 = dst_line;
265        sline = (uint32_t *)src;
266        for (i = 0; i < words; i++) {
267        	pCg6->fbc->font = *sline;
268        	sline++;
269        }
270        src += src_pitch;
271        dst_line++;
272    }
273    pCg6->fbc->clipmaxx = 4096;
274    pCg6->fbc->clipminx = 0;
275    exaMarkSync(pDst->drawable.pScreen);
276    return TRUE;
277}
278
279/*
280 * Memcpy-based DFS.
281 */
282static Bool
283Cg6DownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h,
284    char *dst, int dst_pitch)
285{
286    ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
287    Cg6Ptr pCg6       = GET_CG6_FROM_SCRN(pScrn);
288    char  *src        = pCg6->fb + exaGetPixmapOffset(pSrc);
289    int    src_pitch  = exaGetPixmapPitch(pSrc);
290
291    src += x + (y * src_pitch);
292
293    while (h > 0) {
294        memcpy(dst, src, w);
295        src += src_pitch;
296        dst += dst_pitch;
297        h--;
298    }
299    return TRUE;
300}
301
302int
303CG6EXAInit(ScreenPtr pScreen)
304{
305    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
306    Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn);
307    ExaDriverPtr pExa;
308
309    Cg6InitEngine(pCg6);
310
311    pExa = exaDriverAlloc();
312    if (!pExa)
313	return FALSE;
314
315    pCg6->pExa = pExa;
316
317    pExa->exa_major = EXA_VERSION_MAJOR;
318    pExa->exa_minor = EXA_VERSION_MINOR;
319
320    pExa->memoryBase = pCg6->fb;
321
322    /* round to multiple of pixmap pitch */
323    pExa->memorySize = (pCg6->vidmem / pCg6->width) * pCg6->width;
324    pExa->offScreenBase = pCg6->width * pCg6->height;
325
326    /*
327     * our blitter can't deal with variable pitches
328     */
329    pExa->pixmapOffsetAlign = pCg6->width;
330    pExa->pixmapPitchAlign = pCg6->width;
331
332    pExa->flags = EXA_OFFSCREEN_PIXMAPS |
333		  EXA_MIXED_PIXMAPS;
334
335    pExa->maxX = 4096;
336    pExa->maxY = 4096;
337
338    pExa->WaitMarker = Cg6WaitMarker;
339
340    pExa->PrepareSolid = Cg6PrepareSolid;
341    pExa->Solid = Cg6Solid;
342    pExa->DoneSolid = Cg6DoneCopy;
343
344    pExa->PrepareCopy = Cg6PrepareCopy;
345    pExa->Copy = Cg6Copy;
346    pExa->DoneCopy = Cg6DoneCopy;
347
348    pExa->UploadToScreen = Cg6UploadToScreen;
349    pExa->DownloadFromScreen = Cg6DownloadFromScreen;
350
351    return exaDriverInit(pScreen, pExa);;
352}
353