1/* $NetBSD: pm3_exa.c,v 1.6 2017/01/13 20:54:48 macallan Exp $ */
2
3/*
4 * Copyright (c) 2016 Michael Lorenz
5 * All rights reserved.
6 */
7
8/* much of this is based on pm3_accel.c, therefore... */
9/*
10 * Copyright 2000-2001 by Sven Luther <luther@dpt-info.u-strasbg.fr>.
11 *
12 * Permission to use, copy, modify, distribute, and sell this software and its
13 * documentation for any purpose is hereby granted without fee, provided that
14 * the above copyright notice appear in all copies and that both that
15 * copyright notice and this permission notice appear in supporting
16 * documentation, and that the name of Sven Luther not be used in
17 * advertising or publicity pertaining to distribution of the software without
18 * specific, written prior permission. Sven Luther makes no representations
19 * about the suitability of this software for any purpose. It is provided
20 * "as is" without express or implied warranty.
21 *
22 * SVEN LUTHER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
23 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
24 * EVENT SHALL SVEN LUTHER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
25 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
26 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28 * PERFORMANCE OF THIS SOFTWARE.
29 *
30 * Authors:  Sven Luther, <luther@dpt-info.u-strasbg.fr>
31 *           Alan Hourihane, <alanh@fairlite.demon.co.uk>
32 *
33 * this work is sponsored by Appian Graphics.
34 *
35 * Permedia 3 accelerated options.
36 */
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#endif
41
42/* all driver need this */
43#include "xf86.h"
44#include "xf86_OSproc.h"
45#include "compiler.h"
46#include "exa.h"
47
48#include "glint_regs.h"
49#include "pm3_regs.h"
50#include "glint.h"
51
52/*#define PM3_DEBUG*/
53
54#ifdef PM3_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
62static void
63Pm3WaitMarker(ScreenPtr pScreen, int Marker)
64{
65	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
66
67	Permedia3Sync(pScrn);
68}
69
70static Bool
71Pm3PrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap,
72		int xdir, int ydir, int rop, Pixel planemask)
73{
74	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
75	GLINTPtr pGlint = GLINTPTR(pScrn);
76	int dstoff = exaGetPixmapOffset(pDstPixmap);
77	int dstpitch = exaGetPixmapPitch(pDstPixmap);
78	int srcoff = exaGetPixmapOffset(pSrcPixmap);
79	int srcpitch = exaGetPixmapPitch(pSrcPixmap);
80
81	ENTER;
82
83	pGlint->PM3_Render2D =
84		PM3Render2D_SpanOperation |
85		PM3Render2D_Operation_Normal;
86
87	pGlint->PM3_Config2D =
88		PM3Config2D_UserScissorEnable |
89		PM3Config2D_ForegroundROPEnable |
90		PM3Config2D_ForegroundROP(rop) |
91		PM3Config2D_FBWriteEnable;
92
93	if (xdir == 1) pGlint->PM3_Render2D |= PM3Render2D_XPositive;
94	if (ydir == 1) pGlint->PM3_Render2D |= PM3Render2D_YPositive;
95
96	if ((rop!=GXclear)&&(rop!=GXset)&&(rop!=GXnoop)&&(rop!=GXinvert)) {
97		pGlint->PM3_Render2D |= PM3Render2D_FBSourceReadEnable;
98		pGlint->PM3_Config2D |= PM3Config2D_Blocking;
99	}
100
101	if ((rop!=GXclear)&&(rop!=GXset)&&(rop!=GXcopy)&&(rop!=GXcopyInverted))
102		pGlint->PM3_Config2D |= PM3Config2D_FBDestReadEnable;
103
104	pGlint->srcoff = exaGetPixmapOffset(pSrcPixmap);
105
106	GLINT_WAIT(10);
107	GLINT_WRITE_REG(dstoff, PM3FBWriteBufferAddr0);
108	GLINT_WRITE_REG(dstpitch >> 2, PM3FBWriteBufferWidth0);
109	GLINT_WRITE_REG(dstoff, PM3FBDestReadBufferAddr0);
110	GLINT_WRITE_REG(dstpitch >> 2, PM3FBDestReadBufferWidth0);
111	GLINT_WRITE_REG(srcoff, PM3FBSourceReadBufferAddr);
112	GLINT_WRITE_REG(srcpitch >> 2, PM3FBSourceReadBufferWidth);
113	GLINT_WRITE_REG(PM3FBWriteMode_WriteEnable|
114		PM3FBWriteMode_OpaqueSpan|
115		PM3FBWriteMode_Enable0,
116		PM3FBWriteMode);
117	GLINT_WRITE_REG(
118		PM3FBDestReadMode_ReadEnable |
119		PM3FBDestReadMode_Enable0,
120		PM3FBDestReadMode);
121	PM3_PLANEMASK(planemask);
122	GLINT_WRITE_REG(pGlint->PM3_Config2D, PM3Config2D);
123	return TRUE;
124}
125
126static void
127Pm3Copy(PixmapPtr pDstPixmap,
128         int srcX, int srcY, int dstX, int dstY, int w, int h)
129{
130	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
131	GLINTPtr pGlint = GLINTPTR(pScrn);
132	/* Spans needs to be 32 bit aligned. */
133	int x_align = srcX & 0x1f;
134
135	ENTER;
136
137	GLINT_WAIT(5);
138	GLINT_WRITE_REG(((dstY & 0x0fff) << 16) | (dstX & 0x0fff), ScissorMinXY);
139	GLINT_WRITE_REG((((dstY + h) & 0x0fff) << 16) | ((dstX + w) & 0x0fff), ScissorMaxXY);
140	GLINT_WRITE_REG(
141		PM3RectanglePosition_XOffset(dstX - x_align) |
142		PM3RectanglePosition_YOffset(dstY),
143		PM3RectanglePosition);
144	GLINT_WRITE_REG(
145		PM3FBSourceReadBufferOffset_XOffset(srcX - dstX)|
146		PM3FBSourceReadBufferOffset_YOffset(srcY - dstY),
147		PM3FBSourceReadBufferOffset);
148	GLINT_WRITE_REG(pGlint->PM3_Render2D |
149		PM3Render2D_Width(w + x_align)|
150		PM3Render2D_Height(h),
151		PM3Render2D);
152	exaMarkSync(pDstPixmap->drawable.pScreen);
153}
154
155static void
156Pm3DoneCopy(PixmapPtr pPixmap)
157{
158	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
159	GLINTPtr pGlint = GLINTPTR(pScrn);
160
161	GLINT_WRITE_REG(0, ScissorMinXY);
162	GLINT_WRITE_REG(0x0fff0fff, ScissorMaxXY);
163}
164
165static Bool
166Pm3PrepareSolid(PixmapPtr pPixmap, int rop, Pixel planemask, Pixel color)
167{
168	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
169	GLINTPtr pGlint = GLINTPTR(pScrn);
170	int offset = exaGetPixmapOffset(pPixmap);
171	int pitch = exaGetPixmapPitch(pPixmap);
172
173	ENTER;
174
175	GLINT_WAIT(6);
176	GLINT_WRITE_REG(offset, PM3FBWriteBufferAddr0);
177	GLINT_WRITE_REG(pitch >> 2, PM3FBWriteBufferWidth0);
178	GLINT_WRITE_REG(offset, PM3FBDestReadBufferAddr0);
179	GLINT_WRITE_REG(pitch >> 2, PM3FBDestReadBufferWidth0);
180	GLINT_WRITE_REG(PM3FBWriteMode_WriteEnable|
181		PM3FBWriteMode_OpaqueSpan|
182		PM3FBWriteMode_Enable0,
183		PM3FBWriteMode);
184	GLINT_WRITE_REG(
185		PM3FBDestReadMode_ReadEnable |
186		PM3FBDestReadMode_Enable0,
187		PM3FBDestReadMode);
188	/* Prepare Common Render2D & Config2D data */
189	pGlint->PM3_Render2D =
190		PM3Render2D_XPositive |
191		PM3Render2D_YPositive |
192		PM3Render2D_Operation_Normal;
193	pGlint->PM3_Config2D =
194		PM3Config2D_UseConstantSource |
195		PM3Config2D_ForegroundROPEnable |
196		PM3Config2D_ForegroundROP(rop) |
197		PM3Config2D_FBWriteEnable;
198	GLINT_WAIT(3);
199	REPLICATE(color);
200
201	/* We can't do block fills properly at 32bpp, so we can stick the chip
202	 * into 16bpp and double the width and xcoord, but it seems that at
203	 * extremely high resolutions (above 1600) it doesn't fill.
204	 * so, we fall back to the slower span filling method.
205	 */
206#if 0
207	if ((rop == GXcopy) && (pScrn->bitsPerPixel == 32) &&
208	    (pScrn->displayWidth <= 1600)) {
209		pGlint->AccelInfoRec->SubsequentSolidFillRect =
210		    Permedia3SubsequentFillRectSolid32bpp;
211
212		if (pGlint->PM3_UsingSGRAM) {
213			GLINT_WRITE_REG(color, PM3FBBlockColor);
214		} else {
215			pGlint->PM3_Render2D |= PM3Render2D_SpanOperation;
216			GLINT_WRITE_REG(color, PM3ForegroundColor);
217		}
218	} else {
219	    	pGlint->AccelInfoRec->SubsequentSolidFillRect =
220			Permedia3SubsequentFillRectSolid;
221#endif
222	    	/* Can't do block fills at 8bpp either */
223	    	if ((rop == GXcopy) && (pScrn->bitsPerPixel == 16)) {
224			if (pGlint->PM3_UsingSGRAM) {
225				GLINT_WRITE_REG(color, PM3FBBlockColor);
226			} else {
227	        		pGlint->PM3_Render2D |= PM3Render2D_SpanOperation;
228				GLINT_WRITE_REG(color, PM3ForegroundColor);
229			}
230        	} else {
231			pGlint->PM3_Render2D |= PM3Render2D_SpanOperation;
232			GLINT_WRITE_REG(color, PM3ForegroundColor);
233    		}
234#if 0
235	}
236#endif
237	PM3_PLANEMASK(planemask);
238	if (((rop != GXclear) &&
239	     (rop != GXset) &&
240	     (rop != GXcopy) &&
241	     (rop != GXcopyInverted)) ||
242	    ((planemask != 0xffffffff) && !(pGlint->PM3_UsingSGRAM)))
243		pGlint->PM3_Config2D |= PM3Config2D_FBDestReadEnable;
244	GLINT_WRITE_REG(pGlint->PM3_Config2D, PM3Config2D);
245	return TRUE;
246}
247
248static void
249Pm3Solid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
250{
251	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
252	GLINTPtr pGlint = GLINTPTR(pScrn);
253	int w = x2 - x1, h = y2 - y1;
254
255	ENTER;
256
257	GLINT_WAIT(2);
258	GLINT_WRITE_REG(
259		PM3RectanglePosition_XOffset(x1) |
260		PM3RectanglePosition_YOffset(y1),
261		PM3RectanglePosition);
262	GLINT_WRITE_REG(pGlint->PM3_Render2D |
263		PM3Render2D_Width(w) | PM3Render2D_Height(h),
264		PM3Render2D);
265
266	exaMarkSync(pPixmap->drawable.pScreen);
267}
268
269/*
270 * Memcpy-based UTS.
271 */
272static Bool
273Pm3UploadToScreen(PixmapPtr pDst, int x, int y, int w, int h,
274    char *src, int src_pitch)
275{
276	ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
277	GLINTPtr pGlint    = GLINTPTR(pScrn);
278	unsigned char *dst = pGlint->FbBase + exaGetPixmapOffset(pDst);
279	int    dst_pitch   = exaGetPixmapPitch(pDst);
280
281	int bpp    = pDst->drawable.bitsPerPixel;
282	int cpp    = (bpp + 7) >> 3;
283	int wBytes = w * cpp;
284
285	ENTER;
286	dst += (x * cpp) + (y * dst_pitch);
287
288	Permedia3Sync(pScrn);
289
290	while (h--) {
291		memcpy(dst, src, wBytes);
292		src += src_pitch;
293		dst += dst_pitch;
294	}
295	return TRUE;
296}
297
298/*
299 * Memcpy-based DFS.
300 */
301static Bool
302Pm3DownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h,
303    char *dst, int dst_pitch)
304{
305 	ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
306	GLINTPtr pGlint    = GLINTPTR(pScrn);
307	unsigned char *src = pGlint->FbBase + exaGetPixmapOffset(pSrc);
308	int    src_pitch   = exaGetPixmapPitch(pSrc);
309
310	ENTER;
311	int bpp    = pSrc->drawable.bitsPerPixel;
312	int cpp    = (bpp + 7) >> 3;
313	int wBytes = w * cpp;
314
315	src += (x * cpp) + (y * src_pitch);
316
317	Permedia3Sync(pScrn);
318
319	while (h--) {
320		memcpy(dst, src, wBytes);
321		src += src_pitch;
322		dst += dst_pitch;
323	}
324
325	return TRUE;
326}
327
328Bool
329Pm3InitEXA(ScreenPtr pScreen)
330{
331	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
332	GLINTPtr pGlint = GLINTPTR(pScrn);
333	ExaDriverPtr pExa;
334	int stride;
335
336	ENTER;
337
338	pExa = exaDriverAlloc();
339	if (!pExa)
340		return FALSE;
341
342	pGlint->pExa = pExa;
343
344	pExa->exa_major = EXA_VERSION_MAJOR;
345	pExa->exa_minor = EXA_VERSION_MINOR;
346
347	pExa->memoryBase = pGlint->FbBase;
348	stride = pScrn->displayWidth * (pScrn->bitsPerPixel >> 3);
349	pExa->offScreenBase = stride * pScrn->virtualY;
350	pExa->memorySize = pGlint->FbMapSize;
351
352	pExa->pixmapOffsetAlign = 32;
353	pExa->pixmapPitchAlign = 32;
354
355	pExa->flags = EXA_OFFSCREEN_PIXMAPS;
356
357	pExa->maxX = 4095;
358	pExa->maxY = 4095;
359
360	pExa->WaitMarker = Pm3WaitMarker;
361
362	pExa->PrepareSolid = Pm3PrepareSolid;
363	pExa->Solid = Pm3Solid;
364	pExa->DoneSolid = Pm3DoneCopy;
365	pExa->PrepareCopy = Pm3PrepareCopy;
366	pExa->Copy = Pm3Copy;
367	pExa->DoneCopy = Pm3DoneCopy;
368
369	/* EXA hits more optimized paths when it does not have to fallback
370	 * because of missing UTS/DFS, hook memcpy-based UTS/DFS.
371	 */
372	pExa->UploadToScreen = Pm3UploadToScreen;
373	pExa->DownloadFromScreen = Pm3DownloadFromScreen;
374
375	Permedia3InitializeEngine(pScrn);
376
377	return exaDriverInit(pScreen, pExa);
378}
379