1/* $NetBSD: ffb_exa.c,v 1.5 2016/09/27 19:12:53 joerg Exp $ */
2/*
3 * Copyright (c) 2015 Michael Lorenz
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 *    - Redistributions of source code must retain the above copyright
11 *      notice, this list of conditions and the following disclaimer.
12 *    - Redistributions in binary form must reproduce the above
13 *      copyright notice, this list of conditions and the following
14 *      disclaimer in the documentation and/or other materials provided
15 *      with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *
30 */
31
32#include <sys/types.h>
33
34#ifdef HAVE_CONFIG_H
35#include "config.h"
36#endif
37
38#include "ffb_fifo.h"
39#include "ffb_rcache.h"
40#include "ffb.h"
41#include "ffb_regs.h"
42
43/* all driver need this */
44#include "xf86.h"
45#include "xf86_OSproc.h"
46#include "compiler.h"
47#include "exa.h"
48
49extern void VISmoveImageRL(unsigned char *, unsigned char *, long, long, long, long);
50extern void VISmoveImageLR(unsigned char *, unsigned char *, long, long, long, long);
51
52/*#define FFB_DEBUG*/
53
54#ifdef FFB_DEBUG
55#define ENTER xf86Msg(X_ERROR, "%s>\n", __func__);
56#define DPRINTF xf86Msg
57#else
58#define ENTER
59#define DPRINTF while (0) xf86Msg
60#endif
61
62#define arraysize(ary)        (sizeof(ary) / sizeof(ary[0]))
63
64int src_formats[] = {PICT_a8r8g8b8, PICT_x8r8g8b8,
65		     PICT_a8b8g8r8, PICT_x8b8g8r8, PICT_a8};
66int tex_formats[] = {PICT_a8r8g8b8, PICT_a8b8g8r8, PICT_a8};
67
68static void
69FFBWaitMarker(ScreenPtr pScreen, int Marker)
70{
71	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
72	FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn);
73	ffb_fbcPtr ffb = pFfb->regs;
74
75	FFBWait(pFfb, ffb);
76}
77
78static Bool
79FFBPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap,
80		int xdir, int ydir, int alu, Pixel planemask)
81{
82	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
83	FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn);
84	ffb_fbcPtr ffb = pFfb->regs;
85
86	ENTER;
87	pFfb->srcpitch = exaGetPixmapPitch(pSrcPixmap);
88	pFfb->srcoff = exaGetPixmapOffset(pSrcPixmap);
89	pFfb->xdir = xdir;
90	pFfb->ydir = ydir;
91	pFfb->rop = alu;
92	pFfb->planemask = planemask;
93	return TRUE;
94}
95
96static void
97FFBCopy(PixmapPtr pDstPixmap,
98         int srcX, int srcY, int dstX, int dstY, int w, int h)
99{
100	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
101	FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn);
102	ffb_fbcPtr ffb = pFfb->regs;
103	unsigned char *src, *dst, *sfb32;
104	int psz_shift = 2;
105	int sdkind;
106
107	ENTER;
108	if ((srcX == dstX) && (srcY != dstY) && (pFfb->rop == GXcopy)) {
109		/* we can use the vscroll command */
110		FFB_ATTR_VSCROLL_XAA(pFfb, pFfb->planemask);
111		FFBFifo(pFfb, 7);
112		ffb->drawop = FFB_DRAWOP_VSCROLL;
113		FFB_WRITE64(&ffb->by, srcY, srcX);
114                       FFB_WRITE64_2(&ffb->dy, dstY, dstX);
115                       FFB_WRITE64_3(&ffb->bh, h, w);
116		exaMarkSync(pDstPixmap->drawable.pScreen);
117		return;
118	}
119	FFB_ATTR_SFB_VAR_XAA(pFfb, pFfb->planemask, pFfb->rop);
120	if (pFfb->use_blkread_prefetch) {
121		FFBFifo(pFfb, 1);
122		if (pFfb->xdir < 0)
123			ffb->mer = FFB_MER_EDRA;
124		else
125			ffb->mer = FFB_MER_EIRA;
126	}
127	FFBWait(pFfb, ffb);
128	sfb32 = (unsigned char *) pFfb->sfb32;
129	src = sfb32 + (srcY * (2048 << psz_shift)) + (srcX << psz_shift);
130	dst = sfb32 + (dstY * (2048 << psz_shift)) + (dstX << psz_shift);
131	sdkind = (2048 << psz_shift);
132
133	if (pFfb->ydir < 0) {
134		src += ((h - 1) * (2048 << psz_shift));
135		dst += ((h - 1) * (2048 << psz_shift));
136		sdkind = -sdkind;
137	}
138	w <<= psz_shift;
139	if (pFfb->xdir < 0)
140		VISmoveImageRL(src, dst, w, h, sdkind, sdkind);
141	else
142		VISmoveImageLR(src, dst, w, h, sdkind, sdkind);
143	if (pFfb->use_blkread_prefetch) {
144		FFBFifo(pFfb, 1);
145		ffb->mer = FFB_MER_DRA;
146	}
147}
148
149static void
150FFBDoneCopy(PixmapPtr pDstPixmap)
151{
152}
153
154static Bool
155FFBPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg)
156{
157	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
158	FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn);
159	ffb_fbcPtr ffb = pFfb->regs;
160	unsigned int ppc, ppc_mask, fbc;
161
162	ENTER;
163	FFBWait(pFfb, ffb);
164	pFfb->planemask = planemask;
165	pFfb->rop = alu;
166
167	fbc = pFfb->fbc;
168	if (pFfb->ffb_res == ffb_res_high)
169		fbc |= FFB_FBC_WB_B;
170	ppc = FFB_PPC_ABE_DISABLE | FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST | FFB_PPC_XS_WID;
171	ppc_mask = FFB_PPC_ABE_MASK | FFB_PPC_APE_MASK | FFB_PPC_CS_MASK | FFB_PPC_XS_MASK;
172
173	FFB_ATTR_RAW(pFfb, ppc, ppc_mask, planemask,
174                    (FFB_ROP_EDIT_BIT | alu) | (FFB_ROP_NEW << 8),
175                    FFB_DRAWOP_RECTANGLE, fg, fbc, pFfb->wid);
176
177	return TRUE;
178}
179
180static void
181FFBSolid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
182{
183	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
184	FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn);
185	ffb_fbcPtr ffb = pFfb->regs;
186
187	ENTER;
188	FFBFifo(pFfb, 4);
189	FFB_WRITE64(&ffb->by, y1, x1);
190	FFB_WRITE64_2(&ffb->bh, y2 - y1, x2 - x1);
191	exaMarkSync(pPixmap->drawable.pScreen);
192}
193
194static Bool
195FFBUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h,
196    char *src, int src_pitch)
197{
198	ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
199	FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn);
200	unsigned char *dst, *sfb32;
201	int psz_shift = 2;
202	ffb_fbcPtr ffb = pFfb->regs;
203
204	ENTER;
205	FFB_ATTR_SFB_VAR_XAA(pFfb, 0xffffffff, GXcopy);
206	FFBWait(pFfb, ffb);
207
208	sfb32 = (unsigned char *) pFfb->sfb32;
209	dst = sfb32 + (y * (2048 << psz_shift)) + (x << psz_shift);
210	VISmoveImageLR(src, dst, w << psz_shift, h,
211		src_pitch, (2048 << psz_shift));
212	return TRUE;
213}
214
215static Bool
216FFBDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h,
217    char *dst, int dst_pitch)
218{
219	ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
220	FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn);
221	unsigned char *src, *sfb32;
222	int psz_shift = 2;
223	ffb_fbcPtr ffb = pFfb->regs;
224
225	ENTER;
226	FFB_ATTR_SFB_VAR_XAA(pFfb, 0xffffffff, GXcopy);
227	if (pFfb->use_blkread_prefetch) {
228		FFBFifo(pFfb, 1);
229		ffb->mer = FFB_MER_EIRA;
230	}
231	FFBWait(pFfb, ffb);
232
233	sfb32 = (unsigned char *) pFfb->sfb32;
234	src = sfb32 + (y * (2048 << psz_shift)) + (x << psz_shift);
235	VISmoveImageLR(src, dst, w << psz_shift, h,
236		(2048 << psz_shift), dst_pitch);
237	if (pFfb->use_blkread_prefetch) {
238		FFBFifo(pFfb, 1);
239		ffb->mer = FFB_MER_DRA;
240	}
241	return TRUE;
242}
243
244static Bool
245FFBCheckComposite(int op, PicturePtr pSrcPicture,
246                           PicturePtr pMaskPicture,
247                           PicturePtr pDstPicture)
248{
249	int i, ok = FALSE;
250
251	ENTER;
252
253	i = 0;
254	while ((i < arraysize(src_formats)) && (!ok)) {
255		ok =  (pSrcPicture->format == src_formats[i]);
256		i++;
257	}
258
259	if (!ok) {
260		xf86Msg(X_ERROR, "%s: unsupported src format %x\n",
261		    __func__, pSrcPicture->format);
262		return FALSE;
263	}
264
265	DPRINTF(X_ERROR, "src is %x, %d: %d %d\n", pSrcPicture->format, op,
266	    pSrcPicture->pDrawable->width, pSrcPicture->pDrawable->height);
267
268	if (pMaskPicture != NULL) {
269		DPRINTF(X_ERROR, "mask is %x %d %d\n", pMaskPicture->format,
270		    pMaskPicture->pDrawable->width,
271		    pMaskPicture->pDrawable->height);
272	}
273	return TRUE;
274}
275
276static Bool
277FFBPrepareComposite(int op, PicturePtr pSrcPicture,
278                             PicturePtr pMaskPicture,
279                             PicturePtr pDstPicture,
280                             PixmapPtr  pSrc,
281                             PixmapPtr  pMask,
282                             PixmapPtr  pDst)
283{
284	ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
285	FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn);
286
287	ENTER;
288
289	pFfb->no_source_pixmap = FALSE;
290	pFfb->source_is_solid = FALSE;
291
292	if (pSrcPicture->format == PICT_a1) {
293		xf86Msg(X_ERROR, "src mono, dst %x, op %d\n",
294		    pDstPicture->format, op);
295		if (pMaskPicture != NULL) {
296			xf86Msg(X_ERROR, "msk %x\n", pMaskPicture->format);
297		}
298	}
299	if (pSrcPicture->pSourcePict != NULL) {
300		if (pSrcPicture->pSourcePict->type == SourcePictTypeSolidFill) {
301			pFfb->fillcolour =
302			    pSrcPicture->pSourcePict->solidFill.color;
303			DPRINTF(X_ERROR, "%s: solid src %08"PRIx32"\n",
304			    __func__, (uint32_t)pFfb->fillcolour);
305			pFfb->no_source_pixmap = TRUE;
306			pFfb->source_is_solid = TRUE;
307		}
308	}
309	if ((pMaskPicture != NULL) && (pMaskPicture->pSourcePict != NULL)) {
310		if (pMaskPicture->pSourcePict->type ==
311		    SourcePictTypeSolidFill) {
312			pFfb->fillcolour =
313			   pMaskPicture->pSourcePict->solidFill.color;
314			xf86Msg(X_ERROR, "%s: solid mask %08"PRIx32"\n",
315			    __func__, (uint32_t)pFfb->fillcolour);
316		}
317	}
318	if (pMaskPicture != NULL) {
319		pFfb->mskoff = exaGetPixmapOffset(pMask);
320		pFfb->mskpitch = exaGetPixmapPitch(pMask);
321		pFfb->mskformat = pMaskPicture->format;
322	} else {
323		pFfb->mskoff = 0;
324		pFfb->mskpitch = 0;
325		pFfb->mskformat = 0;
326	}
327	if (pSrc != NULL) {
328		pFfb->source_is_solid =
329		   ((pSrc->drawable.width == 1) && (pSrc->drawable.height == 1));
330		pFfb->srcoff = exaGetPixmapOffset(pSrc);
331		pFfb->srcpitch = exaGetPixmapPitch(pSrc);
332		if (pFfb->source_is_solid) {
333			pFfb->fillcolour = *(uint32_t *)(pFfb->fb + pFfb->srcoff);
334		}
335	}
336	pFfb->srcformat = pSrcPicture->format;
337	pFfb->dstformat = pDstPicture->format;
338
339	if (pFfb->source_is_solid) {
340		uint32_t temp;
341
342		/* swap solid source as needed */
343		switch (pFfb->srcformat) {
344			case PICT_a8r8g8b8:
345			case PICT_x8r8g8b8:
346				temp = (pFfb->fillcolour & 0x000000ff) << 16;
347				temp |= (pFfb->fillcolour & 0x00ff0000) >> 16;
348				temp |= (pFfb->fillcolour & 0xff00ff00);
349				pFfb->fillcolour = temp;
350				break;
351		}
352	}
353	pFfb->op = op;
354	return TRUE;
355}
356
357static void
358FFBComposite(PixmapPtr pDst, int srcX, int srcY,
359                              int maskX, int maskY,
360                              int dstX, int dstY,
361                              int width, int height)
362{
363	ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
364	FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn);
365	exaMarkSync(pDst->drawable.pScreen);
366}
367
368static Bool
369FFBPrepareAccess(PixmapPtr pPix, int index)
370{
371	ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
372	FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn);
373	ffb_fbcPtr ffb = pFfb->regs;
374
375	ENTER;
376	FFB_ATTR_SFB_VAR_XAA(pFfb, 0xffffffff, GXcopy);
377	FFBWait(pFfb, ffb);
378
379	return TRUE;
380}
381
382static void
383FFBFinishAccess(PixmapPtr pPix, int index)
384{
385}
386
387Bool
388FFBInitEXA(ScreenPtr pScreen)
389{
390	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
391	FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn);
392	ffb_fbcPtr ffb = pFfb->regs;
393	ExaDriverPtr pExa;
394
395	pFfb->fbc = (FFB_FBC_WB_A | FFB_FBC_WM_COMBINED | FFB_FBC_RB_A |
396			 FFB_FBC_WE_FORCEON |
397			 FFB_FBC_SB_BOTH |
398			 FFB_FBC_ZE_OFF | FFB_FBC_YE_OFF |
399			 FFB_FBC_RGBE_MASK |
400			 FFB_FBC_XE_ON);
401	pFfb->wid = FFBWidAlloc(pFfb, TrueColor, 0, TRUE);
402	if (pFfb->wid == (unsigned int) -1)
403		return FALSE;
404
405	pFfb->ppc_cache = (FFB_PPC_FW_DISABLE |
406			   FFB_PPC_VCE_DISABLE | FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST |
407			   FFB_PPC_XS_WID | FFB_PPC_YS_CONST | FFB_PPC_ZS_CONST |
408			   FFB_PPC_DCE_DISABLE | FFB_PPC_ABE_DISABLE | FFB_PPC_TBE_OPAQUE);
409	pFfb->wid_cache = pFfb->wid;
410	pFfb->pmask_cache = ~0;
411	pFfb->rop_cache = (FFB_ROP_NEW | (FFB_ROP_NEW << 8));
412	pFfb->drawop_cache = FFB_DRAWOP_RECTANGLE;
413	pFfb->fg_cache = pFfb->bg_cache = 0;
414	pFfb->fontw_cache = 32;
415	pFfb->fontinc_cache = (1 << 16) | 0;
416	pFfb->fbc_cache = (FFB_FBC_WB_A | FFB_FBC_WM_COMBINED | FFB_FBC_RB_A |
417			   FFB_FBC_WE_FORCEON |
418			   FFB_FBC_SB_BOTH |
419			   FFB_FBC_ZE_OFF | FFB_FBC_YE_OFF |
420			   FFB_FBC_RGBE_OFF |
421			   FFB_FBC_XE_ON);
422
423	/* We will now clear the screen: we'll draw a rectangle covering all the
424	 * viewscreen, using a 'blackness' ROP.
425	 */
426	FFBFifo(pFfb, 22);
427	ffb->fbc = pFfb->fbc_cache;
428	ffb->ppc = pFfb->ppc_cache;
429	ffb->wid = pFfb->wid_cache;
430	ffb->xpmask = 0xff;
431	ffb->pmask = pFfb->pmask_cache;
432	ffb->rop = pFfb->rop_cache;
433	ffb->drawop = pFfb->drawop_cache;
434	ffb->fg = pFfb->fg_cache;
435	ffb->bg = pFfb->bg_cache;
436	ffb->fontw = pFfb->fontw_cache;
437	ffb->fontinc = pFfb->fontinc_cache;
438	ffb->xclip = FFB_XCLIP_TEST_ALWAYS;
439	ffb->cmp = 0x80808080;
440	ffb->matchab = 0x80808080;
441	ffb->magnab = 0x80808080;
442	ffb->blendc = (FFB_BLENDC_FORCE_ONE |
443		       FFB_BLENDC_DF_ONE_M_A |
444		       FFB_BLENDC_SF_A);
445	ffb->blendc1 = 0;
446	ffb->blendc2 = 0;
447	FFB_WRITE64(&ffb->by, 0, 0);
448	FFB_WRITE64_2(&ffb->bh, pFfb->psdp->height, pFfb->psdp->width);
449	FFBWait(pFfb, ffb);
450
451	FFB_ATTR_SFB_VAR_XAA(pFfb, 0xffffffff, GXcopy);
452	FFBWait(pFfb, ffb);
453
454	FFB_HardwareSetup(pFfb);
455	pExa = exaDriverAlloc();
456	if (!pExa)
457		return FALSE;
458
459	pFfb->pExa = pExa;
460
461	pExa->exa_major = EXA_VERSION_MAJOR;
462	pExa->exa_minor = EXA_VERSION_MINOR;
463
464
465	pExa->memoryBase = (char *)pFfb->sfb32;
466	/*
467	 * we don't have usable off-screen memory but EXA craps out if we don't
468	 * pretend that we do, so register a ridiculously small amount and
469	 * cross fingers
470	 */
471	pExa->memorySize = 8192 * pFfb->psdp->height + 4;
472	pExa->offScreenBase = pExa->memorySize - 4;
473
474	/* we want to use 64bit aligned accesses */
475	pExa->pixmapOffsetAlign = 8;
476	pExa->pixmapPitchAlign = 8;
477
478	pExa->flags = EXA_OFFSCREEN_PIXMAPS |
479		      /*EXA_SUPPORTS_OFFSCREEN_OVERLAPS |*/
480		      EXA_MIXED_PIXMAPS;
481
482	pExa->maxX = 2048;
483	pExa->maxY = 2048;
484
485	pExa->WaitMarker = FFBWaitMarker;
486
487	pExa->PrepareSolid = FFBPrepareSolid;
488	pExa->Solid = FFBSolid;
489	pExa->DoneSolid = FFBDoneCopy;
490
491	pExa->PrepareCopy = FFBPrepareCopy;
492	pExa->Copy = FFBCopy;
493	pExa->DoneCopy = FFBDoneCopy;
494
495	pExa->UploadToScreen = FFBUploadToScreen;
496	pExa->DownloadFromScreen = FFBDownloadFromScreen;
497
498	pExa->PrepareAccess = FFBPrepareAccess;
499	pExa->FinishAccess = FFBFinishAccess;
500
501if(0) {
502	pExa->CheckComposite = FFBCheckComposite;
503	pExa->PrepareComposite = FFBPrepareComposite;
504	pExa->Composite = FFBComposite;
505	pExa->DoneComposite = FFBDoneCopy;
506}
507	return exaDriverInit(pScreen, pExa);
508}
509