nv_exa.c revision 14032a88
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.6 2021/08/22 23:11:58 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
142	if (pPixmap->drawable.bitsPerPixel != 32) {
143#ifdef DEBUG
144		xf86Msg(X_ERROR, "%s %d bpp\n", __func__, pPixmap->drawable.bitsPerPixel);
145#endif
146		return FALSE;
147	}
148	planemask |= ~0 << pNv->CurrentLayout.depth;
149	off = exaGetPixmapOffset(pPixmap);
150
151	/*
152	 * XXX
153	 * on my 6800 Ultra the drawing engine stalls when drawing at least
154	 * rectangles into off-screen memory. Draw them by software until I
155	 * figure out what's going on
156	 */
157	if (off != 0) return FALSE;
158	NVSetRopSolid(pScrn, rop, planemask);
159
160	pitch = exaGetPixmapPitch(pPixmap);
161
162	NVDmaStart(pNv, SURFACE_FORMAT, 4);
163	NVDmaNext (pNv, pNv->surfaceFormat);
164	NVDmaNext (pNv, pitch | (pitch << 16));
165	NVDmaNext (pNv, off);
166	NVDmaNext (pNv, off);
167
168	NVDmaStart(pNv, RECT_FORMAT, 1);
169	NVDmaNext (pNv, pNv->rectFormat);
170
171	NVDmaStart(pNv, RECT_SOLID_COLOR, 1);
172	NVDmaNext (pNv, color);
173
174	pNv->DMAKickoffCallback = NVDMAKickoffCallback;
175
176	LEAVE;
177	return TRUE;
178}
179
180static void
181NvSolid(
182    PixmapPtr pPixmap,
183    int x1,
184    int y1,
185    int x2,
186    int y2)
187{
188	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
189	NVPtr pNv = NVPTR(pScrn);
190	int w = x2 - x1, h = y2 - y1;
191
192	ENTER;
193
194	NVDmaStart(pNv, RECT_SOLID_RECTS(0), 2);
195	NVDmaNext (pNv, (x1 << 16) | y1);
196	NVDmaNext (pNv, (w << 16) | h);
197
198	if((w * h) >= 512)
199		NVDmaKickoff(pNv);
200
201	LEAVE;
202}
203
204/*
205 * Memcpy-based UTS.
206 */
207static Bool
208NvUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h,
209    char *src, int src_pitch)
210{
211	ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
212	NVPtr pNv = NVPTR(pScrn);
213	unsigned char *dst = pNv->FbStart + exaGetPixmapOffset(pDst);
214	int dst_pitch = exaGetPixmapPitch(pDst);
215
216	int bpp    = pDst->drawable.bitsPerPixel;
217	int cpp    = (bpp + 7) >> 3;
218	int wBytes = w * cpp;
219
220	ENTER;
221	dst += (x * cpp) + (y * dst_pitch);
222
223	NVSync(pScrn);
224
225	while (h--) {
226		memcpy(dst, src, wBytes);
227		src += src_pitch;
228		dst += dst_pitch;
229	}
230
231	LEAVE;
232	return TRUE;
233}
234
235/*
236 * Memcpy-based DFS.
237 */
238static Bool
239NvDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h,
240    char *dst, int dst_pitch)
241{
242	ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
243	NVPtr pNv = NVPTR(pScrn);
244	unsigned char *src = pNv->FbStart + exaGetPixmapOffset(pSrc);
245	int src_pitch = exaGetPixmapPitch(pSrc);
246
247	int bpp    = pSrc->drawable.bitsPerPixel;
248	int cpp    = (bpp + 7) >> 3;
249	int wBytes = w * cpp;
250
251	ENTER;
252	src += (x * cpp) + (y * src_pitch);
253
254	NVSync(pScrn);
255
256	while (h--) {
257		memcpy(dst, src, wBytes);
258		src += src_pitch;
259		dst += dst_pitch;
260	}
261	LEAVE;
262	return TRUE;
263}
264
265static Bool
266NvPrepareAccess(PixmapPtr pPix, int index)
267{
268	ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
269
270	NVSync(pScrn);
271	return TRUE;
272}
273
274static void
275NvFinishAccess(PixmapPtr pPix, int index)
276{
277}
278
279Bool
280NvInitExa(ScreenPtr pScreen)
281{
282	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
283	NVPtr pNv = NVPTR(pScrn);
284	ExaDriverPtr pExa;
285
286	pExa = exaDriverAlloc();
287	if (!pExa)
288		return FALSE;
289
290	pNv->pExa = pExa;
291
292	NVResetGraphics(pScrn);
293
294	pExa->exa_major = EXA_VERSION_MAJOR;
295	pExa->exa_minor = EXA_VERSION_MINOR;
296
297	pExa->memoryBase = pNv->FbStart;
298	pExa->memorySize = pNv->ScratchBufferStart & (~255);
299	pExa->offScreenBase = (((pScrn->virtualY * pScrn->displayWidth *
300			       pScrn->bitsPerPixel >> 3) + 255) & (~255));
301	pExa->pixmapOffsetAlign = 256;
302	pExa->pixmapPitchAlign = 256;
303
304	pExa->flags = EXA_OFFSCREEN_PIXMAPS |
305		      EXA_MIXED_PIXMAPS;
306
307	pExa->maxX = 4096;
308	pExa->maxY = 4096;
309
310	pExa->WaitMarker = NvWaitMarker;
311	pExa->PrepareSolid = NvPrepareSolid;
312	pExa->Solid = NvSolid;
313	pExa->DoneSolid = NvDoneCopy;
314	pExa->PrepareCopy = NvPrepareCopy;
315	pExa->Copy = NvCopy;
316	pExa->DoneCopy = NvDoneCopy;
317
318	switch(pNv->CurrentLayout.depth) {
319	case 24:
320		pNv->surfaceFormat = SURFACE_FORMAT_DEPTH24;
321		pNv->rectFormat = RECT_FORMAT_DEPTH24;
322		break;
323	case 16:
324	case 15:
325		pNv->surfaceFormat = SURFACE_FORMAT_DEPTH16;
326		pNv->rectFormat = RECT_FORMAT_DEPTH16;
327		break;
328	default:
329		pNv->surfaceFormat = SURFACE_FORMAT_DEPTH8;
330		pNv->rectFormat = RECT_FORMAT_DEPTH8;
331		break;
332	}
333	NVDmaStart(pNv, SURFACE_FORMAT, 1);
334	NVDmaNext (pNv, pNv->surfaceFormat);
335	NVDmaStart(pNv, RECT_FORMAT, 1);
336	NVDmaNext (pNv, pNv->rectFormat);
337
338	NVDmaStart(pNv, PATTERN_COLOR_0, 4);
339	NVDmaNext (pNv, 0xffffffff);
340	NVDmaNext (pNv, 0xffffffff);
341	NVDmaNext (pNv, 0xffffffff);
342	NVDmaNext (pNv, 0xffffffff);
343
344	pNv->currentRop = ~0;  /* set to something invalid */
345	NVSetRopSolid(pScrn, GXcopy, ~0);
346
347	NVDmaKickoff(pNv);
348
349	/* EXA hits more optimized paths when it does not have to fallback
350	 * because of missing UTS/DFS, hook memcpy-based UTS/DFS.
351	 */
352	pExa->UploadToScreen = NvUploadToScreen;
353	pExa->DownloadFromScreen = NvDownloadFromScreen;
354	pExa->PrepareAccess = NvPrepareAccess;
355	pExa->FinishAccess = NvFinishAccess;
356
357	return exaDriverInit(pScreen, pExa);
358}
359