cg6_exa.c revision 6d8d5fbf
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#include "cg6.h"
26#include "cg6_regs.h"
27
28
29static CARD32 Cg6BlitROP[] = {
30    ROP_BLIT(GX_ROP_CLEAR,  GX_ROP_CLEAR),	/* GXclear */
31    ROP_BLIT(GX_ROP_CLEAR,  GX_ROP_NOOP),	/* GXand */
32    ROP_BLIT(GX_ROP_CLEAR,  GX_ROP_INVERT),	/* GXandReverse */
33    ROP_BLIT(GX_ROP_CLEAR,  GX_ROP_SET),	/* GXcopy */
34    ROP_BLIT(GX_ROP_NOOP,   GX_ROP_CLEAR),	/* GXandInverted */
35    ROP_BLIT(GX_ROP_NOOP,   GX_ROP_NOOP),	/* GXnoop */
36    ROP_BLIT(GX_ROP_NOOP,   GX_ROP_INVERT),	/* GXxor */
37    ROP_BLIT(GX_ROP_NOOP,   GX_ROP_SET),	/* GXor */
38    ROP_BLIT(GX_ROP_INVERT, GX_ROP_CLEAR),	/* GXnor */
39    ROP_BLIT(GX_ROP_INVERT, GX_ROP_NOOP),	/* GXequiv */
40    ROP_BLIT(GX_ROP_INVERT, GX_ROP_INVERT),	/* GXinvert */
41    ROP_BLIT(GX_ROP_INVERT, GX_ROP_SET),	/* GXorReverse */
42    ROP_BLIT(GX_ROP_SET,    GX_ROP_CLEAR),	/* GXcopyInverted */
43    ROP_BLIT(GX_ROP_SET,    GX_ROP_NOOP),	/* GXorInverted */
44    ROP_BLIT(GX_ROP_SET,    GX_ROP_INVERT),	/* GXnand */
45    ROP_BLIT(GX_ROP_SET,    GX_ROP_SET),	/* GXset */
46};
47
48static CARD32 Cg6DrawROP[] = {
49    ROP_FILL(GX_ROP_CLEAR,  GX_ROP_CLEAR),	/* GXclear */
50    ROP_FILL(GX_ROP_CLEAR,  GX_ROP_NOOP),	/* GXand */
51    ROP_FILL(GX_ROP_CLEAR,  GX_ROP_INVERT),	/* GXandReverse */
52    ROP_FILL(GX_ROP_CLEAR,  GX_ROP_SET),	/* GXcopy */
53    ROP_FILL(GX_ROP_NOOP,   GX_ROP_CLEAR),	/* GXandInverted */
54    ROP_FILL(GX_ROP_NOOP,   GX_ROP_NOOP),	/* GXnoop */
55    ROP_FILL(GX_ROP_NOOP,   GX_ROP_INVERT),	/* GXxor */
56    ROP_FILL(GX_ROP_NOOP,   GX_ROP_SET),	/* GXor */
57    ROP_FILL(GX_ROP_INVERT, GX_ROP_CLEAR),	/* GXnor */
58    ROP_FILL(GX_ROP_INVERT, GX_ROP_NOOP),	/* GXequiv */
59    ROP_FILL(GX_ROP_INVERT, GX_ROP_INVERT),	/* GXinvert */
60    ROP_FILL(GX_ROP_INVERT, GX_ROP_SET),	/* GXorReverse */
61    ROP_FILL(GX_ROP_SET,    GX_ROP_CLEAR),	/* GXcopyInverted */
62    ROP_FILL(GX_ROP_SET,    GX_ROP_NOOP),	/* GXorInverted */
63    ROP_FILL(GX_ROP_SET,    GX_ROP_INVERT),	/* GXnand */
64    ROP_FILL(GX_ROP_SET,    GX_ROP_SET),	/* GXset */
65};
66
67#define runDraw(pCg6) { volatile CARD32 rubbish = pCg6->fbc->draw; }
68#define runBlit(pCg6) { volatile CARD32 rubbish = pCg6->fbc->blit; }
69
70/*
71 * XXX
72 * was GX_FULL, which apparently isn't enough on some (slower) CG6 like
73 * the one found on the SPARCstation LX mainboard
74 */
75#define waitReady(pCg6) while(pCg6->fbc->s & GX_INPROGRESS)
76
77void Cg6InitEngine(Cg6Ptr);
78
79static void
80Cg6WaitMarker(ScreenPtr pScreen, int Marker)
81{
82	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
83	Cg6Ptr p = GET_CG6_FROM_SCRN(pScrn);
84
85	waitReady(p);
86}
87
88static Bool
89Cg6PrepareCopy
90(
91    PixmapPtr pSrcPixmap,
92    PixmapPtr pDstPixmap,
93    int       xdir,
94    int       ydir,
95    int       alu,
96    Pixel     planemask
97)
98{
99    ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
100    Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn);
101
102    waitReady(pCg6);
103
104    pCg6->fbc->mode = GX_BLIT_SRC |
105		GX_MODE_COLOR8 |
106		GX_DRAW_RENDER |
107		GX_BWRITE0_ENABLE |
108		GX_BWRITE1_DISABLE |
109		GX_BREAD_0 |
110		GX_BDISP_0;
111
112    /* we probably don't need the following three */
113    pCg6->fbc->fg = 0xff;
114    pCg6->fbc->bg = 0x00;
115    pCg6->fbc->s = 0;
116
117    pCg6->srcoff = exaGetPixmapOffset(pSrcPixmap) / pCg6->width;
118    pCg6->fbc->alu = Cg6BlitROP[alu];
119    pCg6->fbc->pm = planemask;
120    return TRUE;
121}
122
123static void
124Cg6Copy
125(
126    PixmapPtr pDstPixmap,
127    int       xSrc,
128    int       ySrc,
129    int       xDst,
130    int       yDst,
131    int       w,
132    int       h
133)
134{
135    ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
136    Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn);
137    int doff;
138
139    doff = exaGetPixmapOffset(pDstPixmap) / pCg6->width;
140    waitReady(pCg6);
141    pCg6->fbc->x0 = xSrc;
142    pCg6->fbc->y0 = ySrc + pCg6->srcoff;
143    pCg6->fbc->x1 = xSrc + w - 1;
144    pCg6->fbc->y1 = ySrc + pCg6->srcoff + h - 1;
145    pCg6->fbc->x2 = xDst;
146    pCg6->fbc->y2 = yDst + doff;
147    pCg6->fbc->x3 = xDst + w - 1;
148    pCg6->fbc->y3 = yDst + doff + h - 1;
149    runBlit(pCg6);
150    exaMarkSync(pDstPixmap->drawable.pScreen);
151}
152
153static void
154Cg6DoneCopy(PixmapPtr pDstPixmap)
155{
156    ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
157    Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn);
158
159    waitReady(pCg6);
160}
161
162static Bool
163Cg6PrepareSolid(
164    PixmapPtr pPixmap,
165    int alu,
166    Pixel planemask,
167    Pixel fg)
168{
169    ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
170    Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn);
171    CARD32 c2;
172
173    pCg6->srcoff = exaGetPixmapOffset(pPixmap) / pCg6->width;
174
175    waitReady(pCg6);
176
177    pCg6->fbc->mode = GX_BLIT_SRC |
178		GX_MODE_COLOR8 |
179		GX_DRAW_RENDER |
180		GX_BWRITE0_ENABLE |
181		GX_BWRITE1_DISABLE |
182		GX_BREAD_0 |
183		GX_BDISP_0;
184    pCg6->fbc->fg = fg;
185    pCg6->fbc->s = 0;
186    pCg6->fbc->alu = Cg6DrawROP[alu];
187    pCg6->fbc->pm = planemask;
188    return TRUE;
189}
190
191static void
192Cg6Solid(
193    PixmapPtr pPixmap,
194    int x,
195    int y,
196    int x2,
197    int y2)
198{
199    ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
200    Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn);
201
202    waitReady(pCg6);
203    pCg6->fbc->arecty = y + pCg6->srcoff;
204    pCg6->fbc->arectx = x;
205    pCg6->fbc->rrecty = y2 - y - 1;
206    pCg6->fbc->rrectx = x2 - x - 1;
207    runDraw(pCg6);
208    exaMarkSync(pPixmap->drawable.pScreen);
209}
210
211/*
212 * Memcpy-based UTS.
213 * TODO: use host blit
214 */
215static Bool
216Cg6UploadToScreen(PixmapPtr pDst, int x, int y, int w, int h,
217    char *src, int src_pitch)
218{
219    ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
220    Cg6Ptr pCg6       = GET_CG6_FROM_SCRN(pScrn);
221    uint32_t *sline;
222    int    dst_pitch  = exaGetPixmapPitch(pDst);
223    int    dst_line   = y + exaGetPixmapOffset(pDst) / pCg6->width;
224    int    i, bits;
225    int    words = (w + 3) >> 2;
226
227    /* clip to the destination */
228    pCg6->fbc->clipmaxx = x + w - 1;
229    pCg6->fbc->clipminx = x;
230
231    /* see if the source is aligned, if not adjust */
232    bits = ((long)src) & 3;
233    if (bits != 0) {
234    	src -= bits;
235    	w += bits;
236	words = (w + 3) >> 2;
237	x -= bits;
238    }
239
240    /* we assume that source pitch is always a multiple of 4 */
241    if ((src_pitch & 3) != 0)
242    	xf86Msg(X_ERROR, "pitch %d\n", src_pitch);
243    waitReady(pCg6);
244
245    pCg6->fbc->mode = GX_BLIT_NOSRC |
246		GX_MODE_COLOR8 |
247		GX_DRAW_RENDER |
248		GX_BWRITE0_ENABLE |
249		GX_BWRITE1_DISABLE |
250		GX_BREAD_0 |
251		GX_BDISP_0;
252
253    pCg6->fbc->alu = Cg6BlitROP[GXcopy];
254    pCg6->fbc->pm = 0xffffffff;
255    pCg6->fbc->incx = 4;
256    pCg6->fbc->incy = 0;
257    while (h--) {
258        pCg6->fbc->x0 = x;
259        pCg6->fbc->x1 = x + 3;
260        pCg6->fbc->y0 = dst_line;
261        sline = (uint32_t *)src;
262        for (i = 0; i < words; i++) {
263        	pCg6->fbc->font = *sline;
264        	sline++;
265        }
266        src += src_pitch;
267        dst_line++;
268    }
269    pCg6->fbc->clipmaxx = 4096;
270    pCg6->fbc->clipminx = 0;
271    exaMarkSync(pDst->drawable.pScreen);
272    return TRUE;
273}
274
275/*
276 * Memcpy-based DFS.
277 */
278static Bool
279Cg6DownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h,
280    char *dst, int dst_pitch)
281{
282    ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
283    Cg6Ptr pCg6       = GET_CG6_FROM_SCRN(pScrn);
284    char  *src        = pCg6->fb + exaGetPixmapOffset(pSrc);
285    int    src_pitch  = exaGetPixmapPitch(pSrc);
286
287    src += x + (y * src_pitch);
288
289    while (h > 0) {
290        memcpy(dst, src, w);
291        src += src_pitch;
292        dst += dst_pitch;
293        h--;
294    }
295    return TRUE;
296}
297
298int
299CG6EXAInit(ScreenPtr pScreen)
300{
301    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
302    Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn);
303    ExaDriverPtr pExa;
304
305    Cg6InitEngine(pCg6);
306
307    pExa = exaDriverAlloc();
308    if (!pExa)
309	return FALSE;
310
311    pCg6->pExa = pExa;
312
313    pExa->exa_major = EXA_VERSION_MAJOR;
314    pExa->exa_minor = EXA_VERSION_MINOR;
315
316    pExa->memoryBase = pCg6->fb;
317
318    /* round to multiple of pixmap pitch */
319    pExa->memorySize = (pCg6->vidmem / pCg6->width) * pCg6->width;
320    pExa->offScreenBase = pCg6->width * pCg6->height;
321
322    /*
323     * our blitter can't deal with variable pitches
324     */
325    pExa->pixmapOffsetAlign = pCg6->width;
326    pExa->pixmapPitchAlign = pCg6->width;
327
328    pExa->flags = EXA_OFFSCREEN_PIXMAPS |
329		  EXA_MIXED_PIXMAPS;
330
331    pExa->maxX = 4096;
332    pExa->maxY = 4096;
333
334    pExa->WaitMarker = Cg6WaitMarker;
335
336    pExa->PrepareSolid = Cg6PrepareSolid;
337    pExa->Solid = Cg6Solid;
338    pExa->DoneSolid = Cg6DoneCopy;
339
340    pExa->PrepareCopy = Cg6PrepareCopy;
341    pExa->Copy = Cg6Copy;
342    pExa->DoneCopy = Cg6DoneCopy;
343
344    pExa->UploadToScreen = Cg6UploadToScreen;
345    pExa->DownloadFromScreen = Cg6DownloadFromScreen;
346
347    return exaDriverInit(pScreen, pExa);;
348}
349