nv_exa.c revision 2d0d2c2b
105c1003fSmacallan/*
205c1003fSmacallan * crude EXA support for geforce chips
305c1003fSmacallan *
405c1003fSmacallan * Copyright (C) 2018 Michael Lorenz
505c1003fSmacallan *
605c1003fSmacallan * Permission is hereby granted, free of charge, to any person obtaining a copy
705c1003fSmacallan * of this software and associated documentation files (the "Software"), to deal
805c1003fSmacallan * in the Software without restriction, including without limitation the rights
905c1003fSmacallan * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1005c1003fSmacallan * copies of the Software, and to permit persons to whom the Software is
1105c1003fSmacallan * furnished to do so, subject to the following conditions:
1205c1003fSmacallan *
1305c1003fSmacallan * The above copyright notice and this permission notice shall be included in
1405c1003fSmacallan * all copies or substantial portions of the Software.
1505c1003fSmacallan *
1605c1003fSmacallan * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1705c1003fSmacallan * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1805c1003fSmacallan * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1905c1003fSmacallan * MICHAEL LORENZ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
2005c1003fSmacallan * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2105c1003fSmacallan * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2205c1003fSmacallan */
2305c1003fSmacallan
242d0d2c2bSmacallan/* $NetBSD: nv_exa.c,v 1.3 2018/07/16 16:30:04 macallan Exp $ */
2505c1003fSmacallan
2605c1003fSmacallan#ifdef HAVE_CONFIG_H
2705c1003fSmacallan#include "config.h"
2805c1003fSmacallan#endif
2905c1003fSmacallan
3005c1003fSmacallan#include "nv_include.h"
3105c1003fSmacallan#include "miline.h"
3205c1003fSmacallan#include "nv_dma.h"
3305c1003fSmacallan#include "exa.h"
3405c1003fSmacallan
3505c1003fSmacallan//#define DEBUG
3605c1003fSmacallan
3705c1003fSmacallan#ifdef DEBUG
3805c1003fSmacallan#define ENTER xf86Msg(X_ERROR, "%s\n", __func__)
3905c1003fSmacallan#define LEAVE xf86Msg(X_ERROR, "%s done\n", __func__)
4005c1003fSmacallan#else
4105c1003fSmacallan#define ENTER
4205c1003fSmacallan#define LEAVE
4305c1003fSmacallan#endif
4405c1003fSmacallan
4505c1003fSmacallanstatic void
4605c1003fSmacallanNvWaitMarker(ScreenPtr pScreen, int Marker)
4705c1003fSmacallan{
4805c1003fSmacallan	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
4905c1003fSmacallan
5005c1003fSmacallan	ENTER;
5105c1003fSmacallan	NVSync(pScrn);
5205c1003fSmacallan	LEAVE;
5305c1003fSmacallan}
5405c1003fSmacallan
5505c1003fSmacallanstatic Bool
5605c1003fSmacallanNvPrepareCopy
5705c1003fSmacallan(
5805c1003fSmacallan    PixmapPtr pSrcPixmap,
5905c1003fSmacallan    PixmapPtr pDstPixmap,
6005c1003fSmacallan    int       xdir,
6105c1003fSmacallan    int       ydir,
6205c1003fSmacallan    int       rop,
6305c1003fSmacallan    Pixel     planemask
6405c1003fSmacallan)
6505c1003fSmacallan{
6605c1003fSmacallan	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
6705c1003fSmacallan	NVPtr pNv = NVPTR(pScrn);
6805c1003fSmacallan	int srcpitch, srcoff, dstpitch, dstoff;
6905c1003fSmacallan
7005c1003fSmacallan	ENTER;
7105c1003fSmacallan	if (pSrcPixmap->drawable.bitsPerPixel != 32)
7205c1003fSmacallan		xf86Msg(X_ERROR, "%s %d bpp\n", __func__, pSrcPixmap->drawable.bitsPerPixel);
7305c1003fSmacallan	planemask |= ~0 << pNv->CurrentLayout.depth;
7405c1003fSmacallan	NVSetRopSolid(pScrn, rop, planemask);
7505c1003fSmacallan	pNv->DMAKickoffCallback = NVDMAKickoffCallback;
7605c1003fSmacallan	dstpitch = exaGetPixmapPitch(pDstPixmap);
7705c1003fSmacallan	dstoff = exaGetPixmapOffset(pDstPixmap);
7805c1003fSmacallan	srcpitch = exaGetPixmapPitch(pSrcPixmap);
7905c1003fSmacallan	srcoff = exaGetPixmapOffset(pSrcPixmap);
8005c1003fSmacallan
8105c1003fSmacallan	NVDmaStart(pNv, SURFACE_PITCH, 3);
8205c1003fSmacallan	NVDmaNext (pNv, srcpitch | (dstpitch << 16));
8305c1003fSmacallan	NVDmaNext (pNv, srcoff);
8405c1003fSmacallan	NVDmaNext (pNv, dstoff);
8505c1003fSmacallan
8605c1003fSmacallan	LEAVE;
8705c1003fSmacallan	return TRUE;
8805c1003fSmacallan}
8905c1003fSmacallan
9005c1003fSmacallanstatic void
9105c1003fSmacallanNvCopy
9205c1003fSmacallan(
9305c1003fSmacallan    PixmapPtr pDstPixmap,
9405c1003fSmacallan    int       srcX,
9505c1003fSmacallan    int       srcY,
9605c1003fSmacallan    int       dstX,
9705c1003fSmacallan    int       dstY,
9805c1003fSmacallan    int       w,
9905c1003fSmacallan    int       h
10005c1003fSmacallan)
10105c1003fSmacallan{
10205c1003fSmacallan	ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
10305c1003fSmacallan	NVPtr pNv = NVPTR(pScrn);
10405c1003fSmacallan
10505c1003fSmacallan	NVDmaStart(pNv, BLIT_POINT_SRC, 3);
10605c1003fSmacallan	NVDmaNext (pNv, (srcY << 16) | srcX);
10705c1003fSmacallan	NVDmaNext (pNv, (dstY << 16) | dstX);
10805c1003fSmacallan	NVDmaNext (pNv, (h  << 16) | w);
10905c1003fSmacallan
11005c1003fSmacallan	if((w * h) >= 512)
11105c1003fSmacallan		NVDmaKickoff(pNv);
11205c1003fSmacallan
11305c1003fSmacallan	LEAVE;
11405c1003fSmacallan}
11505c1003fSmacallan
11605c1003fSmacallanstatic void
11705c1003fSmacallanNvDoneCopy(PixmapPtr pDstPixmap)
11805c1003fSmacallan{
11905c1003fSmacallan    ENTER;
12005c1003fSmacallan    LEAVE;
12105c1003fSmacallan}
12205c1003fSmacallan
12305c1003fSmacallanstatic Bool
12405c1003fSmacallanNvPrepareSolid(
12505c1003fSmacallan    PixmapPtr pPixmap,
12605c1003fSmacallan    int rop,
12705c1003fSmacallan    Pixel planemask,
12805c1003fSmacallan    Pixel color)
12905c1003fSmacallan{
13005c1003fSmacallan	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
13105c1003fSmacallan	NVPtr pNv = NVPTR(pScrn);
13205c1003fSmacallan	int pitch, off;
13305c1003fSmacallan
13405c1003fSmacallan	ENTER;
13505c1003fSmacallan	if (pPixmap->drawable.bitsPerPixel != 32)
13605c1003fSmacallan		xf86Msg(X_ERROR, "%s %d bpp\n", __func__, pPixmap->drawable.bitsPerPixel);
13705c1003fSmacallan	planemask |= ~0 << pNv->CurrentLayout.depth;
13805c1003fSmacallan
13905c1003fSmacallan
14005c1003fSmacallan	pitch = exaGetPixmapPitch(pPixmap);
14105c1003fSmacallan	off = exaGetPixmapOffset(pPixmap);
14205c1003fSmacallan
14305c1003fSmacallan	NVDmaStart(pNv, SURFACE_PITCH, 3);
14405c1003fSmacallan	NVDmaNext (pNv, pitch | (pitch << 16));
14505c1003fSmacallan	NVDmaNext (pNv, off);
14605c1003fSmacallan	NVDmaNext (pNv, off);
14705c1003fSmacallan
14805c1003fSmacallan	NVSetRopSolid(pScrn, rop, planemask);
14905c1003fSmacallan	pNv->DMAKickoffCallback = NVDMAKickoffCallback;
15005c1003fSmacallan	NVDmaStart(pNv, RECT_SOLID_COLOR, 1);
15105c1003fSmacallan	NVDmaNext (pNv, color);
15205c1003fSmacallan
15305c1003fSmacallan	LEAVE;
15405c1003fSmacallan	return TRUE;
15505c1003fSmacallan}
15605c1003fSmacallan
15705c1003fSmacallanstatic void
15805c1003fSmacallanNvSolid(
15905c1003fSmacallan    PixmapPtr pPixmap,
16005c1003fSmacallan    int x1,
16105c1003fSmacallan    int y1,
16205c1003fSmacallan    int x2,
16305c1003fSmacallan    int y2)
16405c1003fSmacallan{
16505c1003fSmacallan	ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
16605c1003fSmacallan	NVPtr pNv = NVPTR(pScrn);
16705c1003fSmacallan	int w = x2 - x1, h = y2 - y1;
16805c1003fSmacallan
16905c1003fSmacallan	ENTER;
17005c1003fSmacallan	NVDmaStart(pNv, RECT_SOLID_RECTS(0), 2);
17105c1003fSmacallan	NVDmaNext (pNv, (x1 << 16) | y1);
17205c1003fSmacallan	NVDmaNext (pNv, (w << 16) | h);
17305c1003fSmacallan
17405c1003fSmacallan	if((w * h) >= 512)
17505c1003fSmacallan		NVDmaKickoff(pNv);
17605c1003fSmacallan
17705c1003fSmacallan	LEAVE;
17805c1003fSmacallan}
17905c1003fSmacallan
18005c1003fSmacallan/*
18105c1003fSmacallan * Memcpy-based UTS.
18205c1003fSmacallan */
18305c1003fSmacallanstatic Bool
18405c1003fSmacallanNvUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h,
18505c1003fSmacallan    char *src, int src_pitch)
18605c1003fSmacallan{
18705c1003fSmacallan	ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
18805c1003fSmacallan	NVPtr pNv = NVPTR(pScrn);
18905c1003fSmacallan	unsigned char *dst = pNv->FbStart + exaGetPixmapOffset(pDst);
19005c1003fSmacallan	int dst_pitch = exaGetPixmapPitch(pDst);
19105c1003fSmacallan
19205c1003fSmacallan	int bpp    = pDst->drawable.bitsPerPixel;
19305c1003fSmacallan	int cpp    = (bpp + 7) >> 3;
19405c1003fSmacallan	int wBytes = w * cpp;
19505c1003fSmacallan
19605c1003fSmacallan	ENTER;
19705c1003fSmacallan	dst += (x * cpp) + (y * dst_pitch);
19805c1003fSmacallan
19905c1003fSmacallan	NVSync(pScrn);
20005c1003fSmacallan
20105c1003fSmacallan	while (h--) {
20205c1003fSmacallan		memcpy(dst, src, wBytes);
20305c1003fSmacallan		src += src_pitch;
20405c1003fSmacallan		dst += dst_pitch;
20505c1003fSmacallan	}
20605c1003fSmacallan	_NV_FENCE()
20705c1003fSmacallan	LEAVE;
20805c1003fSmacallan	return TRUE;
20905c1003fSmacallan}
21005c1003fSmacallan
21105c1003fSmacallan/*
21205c1003fSmacallan * Memcpy-based DFS.
21305c1003fSmacallan */
21405c1003fSmacallanstatic Bool
21505c1003fSmacallanNvDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h,
21605c1003fSmacallan    char *dst, int dst_pitch)
21705c1003fSmacallan{
21805c1003fSmacallan	ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
21905c1003fSmacallan	NVPtr pNv = NVPTR(pScrn);
22005c1003fSmacallan	unsigned char *src = pNv->FbStart + exaGetPixmapOffset(pSrc);
22105c1003fSmacallan	int src_pitch = exaGetPixmapPitch(pSrc);
22205c1003fSmacallan
22305c1003fSmacallan	int bpp    = pSrc->drawable.bitsPerPixel;
22405c1003fSmacallan	int cpp    = (bpp + 7) >> 3;
22505c1003fSmacallan	int wBytes = w * cpp;
22605c1003fSmacallan
22705c1003fSmacallan	ENTER;
22805c1003fSmacallan	src += (x * cpp) + (y * src_pitch);
22905c1003fSmacallan
23005c1003fSmacallan	NVSync(pScrn);
23105c1003fSmacallan
23205c1003fSmacallan	while (h--) {
23305c1003fSmacallan		memcpy(dst, src, wBytes);
23405c1003fSmacallan		src += src_pitch;
23505c1003fSmacallan		dst += dst_pitch;
23605c1003fSmacallan	}
23705c1003fSmacallan	LEAVE;
23805c1003fSmacallan	return TRUE;
23905c1003fSmacallan}
24005c1003fSmacallan
2412d0d2c2bSmacallanstatic Bool
2422d0d2c2bSmacallanNvPrepareAccess(PixmapPtr pPix, int index)
2432d0d2c2bSmacallan{
2442d0d2c2bSmacallan	ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
2452d0d2c2bSmacallan
2462d0d2c2bSmacallan	NVSync(pScrn);
2472d0d2c2bSmacallan	return TRUE;
2482d0d2c2bSmacallan}
2492d0d2c2bSmacallan
2502d0d2c2bSmacallanstatic void
2512d0d2c2bSmacallanNvFinishAccess(PixmapPtr pPix, int index)
2522d0d2c2bSmacallan{
2532d0d2c2bSmacallan}
2542d0d2c2bSmacallan
25505c1003fSmacallanBool
25605c1003fSmacallanNvInitExa(ScreenPtr pScreen)
25705c1003fSmacallan{
25805c1003fSmacallan	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
25905c1003fSmacallan	NVPtr pNv = NVPTR(pScrn);
26005c1003fSmacallan	ExaDriverPtr pExa;
26105c1003fSmacallan	int surfaceFormat, rectFormat;
26205c1003fSmacallan
26305c1003fSmacallan	pExa = exaDriverAlloc();
26405c1003fSmacallan	if (!pExa)
26505c1003fSmacallan		return FALSE;
26605c1003fSmacallan
26705c1003fSmacallan	pNv->pExa = pExa;
26805c1003fSmacallan
26905c1003fSmacallan	NVResetGraphics(pScrn);
27005c1003fSmacallan
27105c1003fSmacallan	pExa->exa_major = EXA_VERSION_MAJOR;
27205c1003fSmacallan	pExa->exa_minor = EXA_VERSION_MINOR;
27305c1003fSmacallan
27405c1003fSmacallan	pExa->memoryBase = pNv->FbStart;
27505c1003fSmacallan	pExa->memorySize = pNv->ScratchBufferStart & (~63);
27605c1003fSmacallan	pExa->offScreenBase = pScrn->virtualY *
27705c1003fSmacallan				pScrn->displayWidth * pScrn->bitsPerPixel >> 3;
27805c1003fSmacallan	pExa->pixmapOffsetAlign = 64;
27905c1003fSmacallan	pExa->pixmapPitchAlign = 64;
28005c1003fSmacallan
28105c1003fSmacallan	pExa->flags = EXA_OFFSCREEN_PIXMAPS |
28205c1003fSmacallan		      EXA_SUPPORTS_OFFSCREEN_OVERLAPS |
28305c1003fSmacallan		      EXA_MIXED_PIXMAPS;
28405c1003fSmacallan
28505c1003fSmacallan	pExa->maxX = 8192;
28605c1003fSmacallan	pExa->maxY = 8192;
28705c1003fSmacallan
28805c1003fSmacallan	pExa->WaitMarker = NvWaitMarker;
28905c1003fSmacallan	pExa->PrepareSolid = NvPrepareSolid;
29005c1003fSmacallan	pExa->Solid = NvSolid;
29105c1003fSmacallan	pExa->DoneSolid = NvDoneCopy;
29205c1003fSmacallan	pExa->PrepareCopy = NvPrepareCopy;
29305c1003fSmacallan	pExa->Copy = NvCopy;
29405c1003fSmacallan	pExa->DoneCopy = NvDoneCopy;
29505c1003fSmacallan
29605c1003fSmacallan	switch(pNv->CurrentLayout.depth) {
29705c1003fSmacallan	case 24:
29805c1003fSmacallan		surfaceFormat = SURFACE_FORMAT_DEPTH24;
29905c1003fSmacallan		rectFormat = RECT_FORMAT_DEPTH24;
30005c1003fSmacallan		break;
30105c1003fSmacallan	case 16:
30205c1003fSmacallan	case 15:
30305c1003fSmacallan		surfaceFormat = SURFACE_FORMAT_DEPTH16;
30405c1003fSmacallan		rectFormat = RECT_FORMAT_DEPTH16;
30505c1003fSmacallan		break;
30605c1003fSmacallan	default:
30705c1003fSmacallan		surfaceFormat = SURFACE_FORMAT_DEPTH8;
30805c1003fSmacallan		rectFormat = RECT_FORMAT_DEPTH8;
30905c1003fSmacallan		break;
31005c1003fSmacallan	}
31105c1003fSmacallan	NVDmaStart(pNv, SURFACE_FORMAT, 1);
31205c1003fSmacallan	NVDmaNext (pNv, surfaceFormat);
31305c1003fSmacallan	NVDmaStart(pNv, RECT_FORMAT, 1);
31405c1003fSmacallan	NVDmaNext (pNv, rectFormat);
31505c1003fSmacallan
31605c1003fSmacallan	pNv->currentRop = ~0;  /* set to something invalid */
31705c1003fSmacallan	NVSetRopSolid(pScrn, GXcopy, ~0);
31805c1003fSmacallan
31905c1003fSmacallan	NVDmaKickoff(pNv);
32005c1003fSmacallan
32105c1003fSmacallan	/* EXA hits more optimized paths when it does not have to fallback
32205c1003fSmacallan	 * because of missing UTS/DFS, hook memcpy-based UTS/DFS.
32305c1003fSmacallan	 */
32405c1003fSmacallan	pExa->UploadToScreen = NvUploadToScreen;
32505c1003fSmacallan	pExa->DownloadFromScreen = NvDownloadFromScreen;
3262d0d2c2bSmacallan	pExa->PrepareAccess = NvPrepareAccess;
3272d0d2c2bSmacallan	pExa->FinishAccess = NvFinishAccess;
3282d0d2c2bSmacallan
32905c1003fSmacallan	return exaDriverInit(pScreen, pExa);
33005c1003fSmacallan}
331