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