nv04_exa.c revision fda9279d
1/* 2 * Copyright 2003 NVIDIA, Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 23#include "nv_include.h" 24#include "nv_rop.h" 25 26#include "hwdefs/nv_object.xml.h" 27#include "hwdefs/nv_m2mf.xml.h" 28#include "hwdefs/nv01_2d.xml.h" 29#include "nv04_accel.h" 30 31static void 32NV04EXASetPattern(NVPtr pNv, CARD32 clr0, CARD32 clr1, CARD32 pat0, CARD32 pat1) 33{ 34 struct nouveau_pushbuf *push = pNv->pushbuf; 35 36 BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1); 37 PUSH_DATA (push, pNv->NvImagePattern->handle); 38 BEGIN_NV04(push, NV01_PATT(MONOCHROME_COLOR(0)), 4); 39 PUSH_DATA (push, clr0); 40 PUSH_DATA (push, clr1); 41 PUSH_DATA (push, pat0); 42 PUSH_DATA (push, pat1); 43} 44 45static Bool 46NV04EXASetROP(PixmapPtr ppix, int subc, int mthd, int alu, Pixel planemask) 47{ 48 ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen); 49 NVPtr pNv = NVPTR(pScrn); 50 struct nouveau_pushbuf *push = pNv->pushbuf; 51 52 planemask |= ~0 << ppix->drawable.bitsPerPixel; 53 if (planemask != ~0 || alu != GXcopy) { 54 if (ppix->drawable.bitsPerPixel == 32) 55 return FALSE; 56 if (planemask != ~0) { 57 NV04EXASetPattern(pNv, 0, planemask, ~0, ~0); 58 if (pNv->currentRop != (alu + 32)) { 59 BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1); 60 PUSH_DATA (push, pNv->NvRop->handle); 61 BEGIN_NV04(push, NV01_ROP(ROP), 1); 62 PUSH_DATA (push, NVROP[alu].copy_planemask); 63 pNv->currentRop = alu + 32; 64 } 65 } else 66 if (pNv->currentRop != alu) { 67 if(pNv->currentRop >= 16) 68 NV04EXASetPattern(pNv, ~0, ~0, ~0, ~0); 69 BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1); 70 PUSH_DATA (push, pNv->NvRop->handle); 71 BEGIN_NV04(push, NV01_ROP(ROP), 1); 72 PUSH_DATA (push, NVROP[alu].copy); 73 pNv->currentRop = alu; 74 } 75 76 BEGIN_NV04(push, subc, mthd, 1); 77 PUSH_DATA (push, 1); /* ROP_AND */ 78 } else { 79 BEGIN_NV04(push, subc, mthd, 1); 80 PUSH_DATA (push, 3); /* SRCCOPY */ 81 } 82 83 return TRUE; 84} 85 86Bool 87NV04EXAPrepareSolid(PixmapPtr ppix, int alu, Pixel planemask, Pixel fg) 88{ 89 ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen); 90 NVPtr pNv = NVPTR(pScrn); 91 struct nouveau_pushbuf *push = pNv->pushbuf; 92 struct nouveau_bo *bo = nouveau_pixmap_bo(ppix); 93 unsigned pitch = exaGetPixmapPitch(ppix); 94 unsigned surf_fmt, rect_fmt; 95 96 /* When SURFACE_FORMAT_A8R8G8B8 is used with GDI_RECTANGLE_TEXT, the 97 * alpha channel gets forced to 0xFF for some reason. We're using 98 * SURFACE_FORMAT_Y32 as a workaround 99 */ 100 if (!NVAccelGetCtxSurf2DFormatFromPixmap(ppix, (int*)&surf_fmt)) 101 return FALSE; 102 if (surf_fmt == NV04_SURFACE_2D_FORMAT_A8R8G8B8) 103 surf_fmt = NV04_SURFACE_2D_FORMAT_Y32; 104 105 rect_fmt = NV04_GDI_COLOR_FORMAT_A8R8G8B8; 106 if (ppix->drawable.bitsPerPixel == 16) { 107 if (ppix->drawable.depth == 16) 108 rect_fmt = NV04_GDI_COLOR_FORMAT_A16R5G6B5; 109 else 110 rect_fmt = NV04_GDI_COLOR_FORMAT_X16A1R5G5B5; 111 } 112 113 if (!PUSH_SPACE(push, 64)) 114 return FALSE; 115 PUSH_RESET(push); 116 117 if (!NV04EXASetROP(ppix, NV04_RECT(OPERATION), alu, planemask)) 118 return FALSE; 119 120 BEGIN_NV04(push, NV04_SF2D(FORMAT), 4); 121 PUSH_DATA (push, surf_fmt); 122 PUSH_DATA (push, (pitch << 16) | pitch); 123 PUSH_MTHDl(push, NV04_SF2D(OFFSET_SOURCE), bo, 0, 124 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 125 PUSH_MTHDl(push, NV04_SF2D(OFFSET_DESTIN), bo, 0, 126 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 127 BEGIN_NV04(push, NV04_RECT(COLOR_FORMAT), 1); 128 PUSH_DATA (push, rect_fmt); 129 130 nouveau_pushbuf_bufctx(push, pNv->bufctx); 131 if (nouveau_pushbuf_validate(push)) { 132 nouveau_pushbuf_bufctx(push, NULL); 133 return FALSE; 134 } 135 136 pNv->fg_colour = fg; 137 return TRUE; 138} 139 140void 141NV04EXASolid (PixmapPtr pPixmap, int x, int y, int x2, int y2) 142{ 143 ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen); 144 NVPtr pNv = NVPTR(pScrn); 145 struct nouveau_pushbuf *push = pNv->pushbuf; 146 int w = x2 - x; 147 int h = y2 - y; 148 149 if (!PUSH_SPACE(push, 5)) 150 return; 151 152 BEGIN_NV04(push, NV04_RECT(COLOR1_A), 1); 153 PUSH_DATA (push, pNv->fg_colour); 154 BEGIN_NV04(push, NV04_RECT(UNCLIPPED_RECTANGLE_POINT(0)), 2); 155 PUSH_DATA (push, (x << 16) | y); 156 PUSH_DATA (push, (w << 16) | h); 157 if ((w * h) >= 512) 158 PUSH_KICK(push); 159} 160 161void 162NV04EXADoneSolid (PixmapPtr pPixmap) 163{ 164 ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen); 165 nouveau_pushbuf_bufctx(NVPTR(pScrn)->pushbuf, NULL); 166} 167 168Bool 169NV04EXAPrepareCopy(PixmapPtr pspix, PixmapPtr pdpix, int dx, int dy, 170 int alu, Pixel planemask) 171{ 172 ScrnInfoPtr pScrn = xf86ScreenToScrn(pspix->drawable.pScreen); 173 NVPtr pNv = NVPTR(pScrn); 174 struct nouveau_pushbuf *push = pNv->pushbuf; 175 struct nouveau_bo *src_bo = nouveau_pixmap_bo(pspix); 176 struct nouveau_bo *dst_bo = nouveau_pixmap_bo(pdpix); 177 int surf_fmt; 178 179 if (pspix->drawable.bitsPerPixel != pdpix->drawable.bitsPerPixel) 180 return FALSE; 181 182 if (!NVAccelGetCtxSurf2DFormatFromPixmap(pdpix, &surf_fmt)) 183 return FALSE; 184 185 if (!PUSH_SPACE(push, 64)) 186 return FALSE; 187 PUSH_RESET(push); 188 189 if (!NV04EXASetROP(pdpix, NV01_BLIT(OPERATION), alu, planemask)) 190 return FALSE; 191 192 BEGIN_NV04(push, NV04_SF2D(FORMAT), 4); 193 PUSH_DATA (push, surf_fmt); 194 PUSH_DATA (push, (exaGetPixmapPitch(pdpix) << 16) | 195 exaGetPixmapPitch(pspix)); 196 PUSH_MTHDl(push, NV04_SF2D(OFFSET_SOURCE), src_bo, 0, 197 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); 198 PUSH_MTHDl(push, NV04_SF2D(OFFSET_DESTIN), dst_bo, 0, 199 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 200 201 nouveau_pushbuf_bufctx(push, pNv->bufctx); 202 if (nouveau_pushbuf_validate(push)) { 203 nouveau_pushbuf_bufctx(push, NULL); 204 return FALSE; 205 } 206 207 pNv->pspix = pspix; 208 pNv->pmpix = NULL; 209 pNv->pdpix = pdpix; 210 return TRUE; 211} 212 213void 214NV04EXACopy(PixmapPtr pdpix, int srcX, int srcY, int dstX, int dstY, 215 int width, int height) 216{ 217 ScrnInfoPtr pScrn = xf86ScreenToScrn(pdpix->drawable.pScreen); 218 NVPtr pNv = NVPTR(pScrn); 219 struct nouveau_pushbuf *push = pNv->pushbuf; 220 int split_dstY = NOUVEAU_ALIGN(dstY + 1, 64); 221 int split_height = split_dstY - dstY; 222 223 if (nouveau_pushbuf_space(push, 16, 2, 0)) 224 return; 225 226 if ((width * height) >= 200000 && pNv->pspix != pNv->pdpix && 227 (dstY > srcY || dstX > srcX) && split_height < height) { 228 /* 229 * KLUDGE - Split the destination rectangle in an 230 * upper misaligned half and a lower tile-aligned 231 * half, then get IMAGE_BLIT to blit the lower piece 232 * downwards (required for sync-to-vblank if the area 233 * to be blitted is large enough). The blob does a 234 * different (not nicer) trick to achieve the same 235 * effect. 236 */ 237 struct nouveau_bo *dst_bo = nouveau_pixmap_bo(pdpix); 238 unsigned dst_pitch = exaGetPixmapPitch(pdpix); 239 240 BEGIN_NV04(push, NV01_BLIT(POINT_IN), 3); 241 PUSH_DATA (push, (srcY << 16) | srcX); 242 PUSH_DATA (push, (dstY << 16) | dstX); 243 PUSH_DATA (push, (split_height << 16) | width); 244 BEGIN_NV04(push, NV04_SF2D(OFFSET_DESTIN), 1); 245 PUSH_RELOC(push, dst_bo, split_dstY * dst_pitch, 246 NOUVEAU_BO_LOW, 0, 0); 247 248 srcY += split_height; 249 height -= split_height; 250 dstY = 0; 251 pNv->pmpix = pdpix; 252 } 253 254 BEGIN_NV04(push, NV01_BLIT(POINT_IN), 3); 255 PUSH_DATA (push, (srcY << 16) | srcX); 256 PUSH_DATA (push, (dstY << 16) | dstX); 257 PUSH_DATA (push, (height << 16) | width); 258 259 if (pNv->pmpix) { 260 struct nouveau_bo *dst_bo = nouveau_pixmap_bo(pdpix); 261 262 BEGIN_NV04(push, NV04_SF2D(OFFSET_DESTIN), 1); 263 PUSH_RELOC(push, dst_bo, 0, NOUVEAU_BO_LOW, 0, 0); 264 pNv->pmpix = NULL; 265 } 266 267 if ((width * height) >= 512) 268 PUSH_KICK(push); 269} 270 271void 272NV04EXADoneCopy(PixmapPtr pdpix) 273{ 274 ScrnInfoPtr pScrn = xf86ScreenToScrn(pdpix->drawable.pScreen); 275 nouveau_pushbuf_bufctx(NVPTR(pScrn)->pushbuf, NULL); 276} 277 278Bool 279NV04EXAUploadIFC(ScrnInfoPtr pScrn, const char *src, int src_pitch, 280 PixmapPtr pdpix, int x, int y, int w, int h, int cpp) 281{ 282 NVPtr pNv = NVPTR(pScrn); 283 ScreenPtr pScreen = pdpix->drawable.pScreen; 284 struct nouveau_bo *bo = nouveau_pixmap_bo(pdpix); 285 struct nouveau_pushbuf *push = pNv->pushbuf; 286 int line_len = w * cpp; 287 int surf_fmt, ifc_fmt; 288 int iw, id, py, ph; 289 int padbytes; 290 Bool ret = FALSE; 291 292 if (pNv->Architecture >= NV_TESLA) 293 return FALSE; 294 295 if (h > 1024) 296 return FALSE; 297 298 if (line_len < 4) 299 return FALSE; 300 301 switch (cpp) { 302 case 2: ifc_fmt = 1; break; 303 case 4: ifc_fmt = 4; break; 304 default: 305 return FALSE; 306 } 307 308 if (!NVAccelGetCtxSurf2DFormatFromPixmap(pdpix, &surf_fmt)) 309 return FALSE; 310 311 /* Pad out input width to cover both COLORA() and COLORB() */ 312 iw = (line_len + 7) & ~7; 313 padbytes = iw - line_len; 314 id = iw / 4; /* line push size */ 315 iw /= cpp; 316 317 /* Don't support lines longer than max push size yet.. */ 318 if (id > 1792) 319 return FALSE; 320 321 if (!PUSH_SPACE(push, 16)) 322 return FALSE; 323 PUSH_RESET(push); 324 325 BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1); 326 PUSH_DATA (push, pNv->NvClipRectangle->handle); 327 BEGIN_NV04(push, NV01_CLIP(POINT), 2); 328 PUSH_DATA (push, (y << 16) | x); 329 PUSH_DATA (push, (h << 16) | w); 330 331 BEGIN_NV04(push, NV04_SF2D(FORMAT), 4); 332 PUSH_DATA (push, surf_fmt); 333 PUSH_DATA (push, (exaGetPixmapPitch(pdpix) << 16) | 334 exaGetPixmapPitch(pdpix)); 335 PUSH_MTHDl(push, NV04_SF2D(OFFSET_SOURCE), bo, 0, 336 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 337 PUSH_MTHDl(push, NV04_SF2D(OFFSET_DESTIN), bo, 0, 338 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 339 340 nouveau_pushbuf_bufctx(push, pNv->bufctx); 341 if (nouveau_pushbuf_validate(push)) 342 goto out; 343 344 py = y; 345 ph = h; 346 while (ph--) { 347 if (PUSH_AVAIL(push) < id + 1 || (py == y)) { 348 if (!PUSH_SPACE(push, id + 8)) 349 goto out; 350 BEGIN_NV04(push, NV01_IFC(OPERATION), 2); 351 PUSH_DATA (push, NV01_IFC_OPERATION_SRCCOPY); 352 PUSH_DATA (push, ifc_fmt); 353 BEGIN_NV04(push, NV01_IFC(POINT), 3); 354 PUSH_DATA (push, (py << 16) | x); 355 PUSH_DATA (push, (h << 16) | w); 356 PUSH_DATA (push, (h << 16) | iw); 357 } 358 359 /* send a line */ 360 if (ph > 0 || !padbytes) { 361 BEGIN_NV04(push, NV01_IFC(COLOR(0)), id); 362 PUSH_DATAp(push, src, id); 363 } else { 364 char padding[8]; 365 int aux = (padbytes + 7) >> 2; 366 memcpy(padding, src + (id - aux) * 4, padbytes); 367 BEGIN_NV04(push, NV01_IFC(COLOR(0)), id); 368 PUSH_DATAp(push, src, id - aux); 369 PUSH_DATAp(push, padding, aux); 370 } 371 372 src += src_pitch; 373 py++; 374 } 375 376 ret = TRUE; 377out: 378 nouveau_pushbuf_bufctx(push, NULL); 379 if (pdpix == pScreen->GetScreenPixmap(pScreen)) 380 PUSH_KICK(push); 381 return ret; 382} 383 384Bool 385NV04EXARectM2MF(NVPtr pNv, int w, int h, int cpp, 386 struct nouveau_bo *src, uint32_t src_off, int src_dom, 387 int src_pitch, int src_h, int src_x, int src_y, 388 struct nouveau_bo *dst, uint32_t dst_off, int dst_dom, 389 int dst_pitch, int dst_h, int dst_x, int dst_y) 390{ 391 struct nv04_fifo *fifo = pNv->channel->data; 392 struct nouveau_pushbuf *push = pNv->pushbuf; 393 struct nouveau_pushbuf_refn refs[] = { 394 { src, src_dom | NOUVEAU_BO_RD }, 395 { dst, dst_dom | NOUVEAU_BO_WR }, 396 }; 397 398 src_off += src_y * src_pitch + src_x * cpp; 399 dst_off += dst_y * dst_pitch + dst_x * cpp; 400 401 while (h) { 402 int line_count = h; 403 if (line_count > 2047) 404 line_count = 2047; 405 h -= line_count; 406 407 if (nouveau_pushbuf_space(push, 16, 4, 0) || 408 nouveau_pushbuf_refn (push, refs, 2)) 409 return FALSE; 410 411 BEGIN_NV04(push, NV03_M2MF(DMA_BUFFER_IN), 2); 412 PUSH_RELOC(push, src, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart); 413 PUSH_RELOC(push, dst, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart); 414 BEGIN_NV04(push, NV03_M2MF(OFFSET_IN), 8); 415 PUSH_RELOC(push, src, src_off, NOUVEAU_BO_LOW, 0, 0); 416 PUSH_RELOC(push, dst, dst_off, NOUVEAU_BO_LOW, 0, 0); 417 PUSH_DATA (push, src_pitch); 418 PUSH_DATA (push, dst_pitch); 419 PUSH_DATA (push, w * cpp); 420 PUSH_DATA (push, line_count); 421 PUSH_DATA (push, 0x00000101); 422 PUSH_DATA (push, 0x00000000); 423 BEGIN_NV04(push, NV04_GRAPH(M2MF, NOP), 1); 424 PUSH_DATA (push, 0x00000000); 425 BEGIN_NV04(push, NV03_M2MF(OFFSET_OUT), 1); 426 PUSH_DATA (push, 0x00000000); 427 428 src_off += src_pitch * line_count; 429 dst_off += dst_pitch * line_count; 430 } 431 432 return TRUE; 433} 434