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