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