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