nv_exa.c revision 092d2b73
1/*
2 * crude EXA support for geforce chips
3 *
4 * Copyright (C) 2018 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
24/* $NetBSD: nv_exa.c,v 1.4 2018/07/26 21:29:16 macallan Exp $ */
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif
29
30#include "nv_include.h"
31#include "miline.h"
32#include "nv_dma.h"
33#include "exa.h"
34
35//#define DEBUG
36
37#ifdef DEBUG
38#define ENTER xf86Msg(X_ERROR, "%s\n", __func__)
39#define LEAVE xf86Msg(X_ERROR, "%s done\n", __func__)
40#else
41#define ENTER
42#define LEAVE
43#endif
44
45static void
46NvWaitMarker(ScreenPtr pScreen, int Marker)
47{
48	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
49
50	ENTER;
51	NVSync(pScrn);
52	LEAVE;
53}
54
55static Bool
56NvPrepareCopy
57(
58    PixmapPtr pSrcPixmap,
59    PixmapPtr pDstPixmap,
60    int       xdir,
61    int       ydir,
62    int       rop,
63    Pixel     planemask
64)
65{
66	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
67	NVPtr pNv = NVPTR(pScrn);
68	uint32_t dstpitch, dstoff, srcpitch, srcoff;
69
70	ENTER;
71	if (pSrcPixmap->drawable.bitsPerPixel != 32)
72		xf86Msg(X_ERROR, "%s %d bpp\n", __func__, pSrcPixmap->drawable.bitsPerPixel);
73	planemask |= ~0 << pNv->CurrentLayout.depth;
74	NVSetRopSolid(pScrn, rop, planemask);
75
76	dstpitch = exaGetPixmapPitch(pDstPixmap);
77	dstoff = exaGetPixmapOffset(pDstPixmap);
78	srcpitch = exaGetPixmapPitch(pSrcPixmap);
79	srcoff = exaGetPixmapOffset(pSrcPixmap);
80
81
82	NVDmaStart(pNv, SURFACE_FORMAT, 4);
83	NVDmaNext (pNv, pNv->surfaceFormat);
84	NVDmaNext (pNv, srcpitch | (dstpitch << 16));
85	NVDmaNext (pNv, srcoff);
86	NVDmaNext (pNv, dstoff);
87
88	pNv->DMAKickoffCallback = NVDMAKickoffCallback;
89
90	LEAVE;
91	return TRUE;
92}
93
94static void
95NvCopy
96(
97    PixmapPtr pDstPixmap,
98    int       srcX,
99    int       srcY,
100    int       dstX,
101    int       dstY,
102    int       w,
103    int       h
104)
105{
106	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
107	NVPtr pNv = NVPTR(pScrn);
108
109	ENTER;
110
111	NVDmaStart(pNv, BLIT_POINT_SRC, 3);
112	NVDmaNext (pNv, (srcY << 16) | srcX);
113	NVDmaNext (pNv, (dstY << 16) | dstX);
114	NVDmaNext (pNv, (h  << 16) | w);
115
116	if((w * h) >= 512)
117		NVDmaKickoff(pNv);
118
119	LEAVE;
120}
121
122static void
123NvDoneCopy(PixmapPtr pDstPixmap)
124{
125    ENTER;
126    LEAVE;
127}
128
129static Bool
130NvPrepareSolid(
131    PixmapPtr pPixmap,
132    int rop,
133    Pixel planemask,
134    Pixel color)
135{
136	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
137	NVPtr pNv = NVPTR(pScrn);
138	uint32_t pitch, off;
139
140	ENTER;
141	if (pPixmap->drawable.bitsPerPixel != 32)
142		xf86Msg(X_ERROR, "%s %d bpp\n", __func__, pPixmap->drawable.bitsPerPixel);
143	planemask |= ~0 << pNv->CurrentLayout.depth;
144
145	pitch = exaGetPixmapPitch(pPixmap);
146	off = exaGetPixmapOffset(pPixmap);
147
148	NVDmaStart(pNv, SURFACE_FORMAT, 4);
149	NVDmaNext (pNv, pNv->surfaceFormat);
150	NVDmaNext (pNv, pitch | (pitch << 16));
151	NVDmaNext (pNv, off);
152	NVDmaNext (pNv, off);
153
154	NVDmaStart(pNv, RECT_FORMAT, 1);
155	NVDmaNext (pNv, pNv->rectFormat);
156
157	NVSetRopSolid(pScrn, rop, planemask);
158
159	NVDmaStart(pNv, RECT_SOLID_COLOR, 1);
160	NVDmaNext (pNv, color);
161
162	pNv->DMAKickoffCallback = NVDMAKickoffCallback;
163
164	LEAVE;
165	return TRUE;
166}
167
168static void
169NvSolid(
170    PixmapPtr pPixmap,
171    int x1,
172    int y1,
173    int x2,
174    int y2)
175{
176	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
177	NVPtr pNv = NVPTR(pScrn);
178	int w = x2 - x1, h = y2 - y1;
179
180	ENTER;
181
182	NVDmaStart(pNv, RECT_SOLID_RECTS(0), 2);
183	NVDmaNext (pNv, (x1 << 16) | y1);
184	NVDmaNext (pNv, (w << 16) | h);
185
186	if((w * h) >= 512)
187		NVDmaKickoff(pNv);
188
189	LEAVE;
190}
191
192/*
193 * Memcpy-based UTS.
194 */
195static Bool
196NvUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h,
197    char *src, int src_pitch)
198{
199	ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
200	NVPtr pNv = NVPTR(pScrn);
201	unsigned char *dst = pNv->FbStart + exaGetPixmapOffset(pDst);
202	int dst_pitch = exaGetPixmapPitch(pDst);
203
204	int bpp    = pDst->drawable.bitsPerPixel;
205	int cpp    = (bpp + 7) >> 3;
206	int wBytes = w * cpp;
207
208	ENTER;
209	dst += (x * cpp) + (y * dst_pitch);
210
211	NVSync(pScrn);
212
213	while (h--) {
214		memcpy(dst, src, wBytes);
215		src += src_pitch;
216		dst += dst_pitch;
217	}
218
219	LEAVE;
220	return TRUE;
221}
222
223/*
224 * Memcpy-based DFS.
225 */
226static Bool
227NvDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h,
228    char *dst, int dst_pitch)
229{
230	ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
231	NVPtr pNv = NVPTR(pScrn);
232	unsigned char *src = pNv->FbStart + exaGetPixmapOffset(pSrc);
233	int src_pitch = exaGetPixmapPitch(pSrc);
234
235	int bpp    = pSrc->drawable.bitsPerPixel;
236	int cpp    = (bpp + 7) >> 3;
237	int wBytes = w * cpp;
238
239	ENTER;
240	src += (x * cpp) + (y * src_pitch);
241
242	NVSync(pScrn);
243
244	while (h--) {
245		memcpy(dst, src, wBytes);
246		src += src_pitch;
247		dst += dst_pitch;
248	}
249	LEAVE;
250	return TRUE;
251}
252
253static Bool
254NvPrepareAccess(PixmapPtr pPix, int index)
255{
256	ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
257
258	NVSync(pScrn);
259	return TRUE;
260}
261
262static void
263NvFinishAccess(PixmapPtr pPix, int index)
264{
265}
266
267Bool
268NvInitExa(ScreenPtr pScreen)
269{
270	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
271	NVPtr pNv = NVPTR(pScrn);
272	ExaDriverPtr pExa;
273	int surfaceFormat, rectFormat;
274
275	pExa = exaDriverAlloc();
276	if (!pExa)
277		return FALSE;
278
279	pNv->pExa = pExa;
280
281	NVResetGraphics(pScrn);
282
283	pExa->exa_major = EXA_VERSION_MAJOR;
284	pExa->exa_minor = EXA_VERSION_MINOR;
285
286	pExa->memoryBase = pNv->FbStart;
287	pExa->memorySize = pNv->ScratchBufferStart & (~255);
288	pExa->offScreenBase = (((pScrn->virtualY * pScrn->displayWidth *
289			       pScrn->bitsPerPixel >> 3) + 255) & (~255));
290	pExa->pixmapOffsetAlign = 256;
291	pExa->pixmapPitchAlign = 256;
292
293	pExa->flags = EXA_OFFSCREEN_PIXMAPS/* |
294		      EXA_MIXED_PIXMAPS*/;
295
296	pExa->maxX = 4096;
297	pExa->maxY = 4096;
298
299	pExa->WaitMarker = NvWaitMarker;
300	pExa->PrepareSolid = NvPrepareSolid;
301	pExa->Solid = NvSolid;
302	pExa->DoneSolid = NvDoneCopy;
303	pExa->PrepareCopy = NvPrepareCopy;
304	pExa->Copy = NvCopy;
305	pExa->DoneCopy = NvDoneCopy;
306
307	switch(pNv->CurrentLayout.depth) {
308	case 24:
309		pNv->surfaceFormat = SURFACE_FORMAT_DEPTH24;
310		pNv->rectFormat = RECT_FORMAT_DEPTH24;
311		break;
312	case 16:
313	case 15:
314		pNv->surfaceFormat = SURFACE_FORMAT_DEPTH16;
315		pNv->rectFormat = RECT_FORMAT_DEPTH16;
316		break;
317	default:
318		pNv->surfaceFormat = SURFACE_FORMAT_DEPTH8;
319		pNv->rectFormat = RECT_FORMAT_DEPTH8;
320		break;
321	}
322	NVDmaStart(pNv, SURFACE_FORMAT, 1);
323	NVDmaNext (pNv, pNv->surfaceFormat);
324	NVDmaStart(pNv, RECT_FORMAT, 1);
325	NVDmaNext (pNv, pNv->rectFormat);
326
327	pNv->currentRop = ~0;  /* set to something invalid */
328	NVSetRopSolid(pScrn, GXcopy, ~0);
329
330	NVDmaKickoff(pNv);
331
332	/* EXA hits more optimized paths when it does not have to fallback
333	 * because of missing UTS/DFS, hook memcpy-based UTS/DFS.
334	 */
335	pExa->UploadToScreen = NvUploadToScreen;
336	pExa->DownloadFromScreen = NvDownloadFromScreen;
337	pExa->PrepareAccess = NvPrepareAccess;
338	pExa->FinishAccess = NvFinishAccess;
339
340	return exaDriverInit(pScreen, pExa);
341}
342