nv04_exa.c revision 16ee1e9a
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 if (ppix->drawable.bitsPerPixel < 32) 53 planemask |= ~0 << ppix->drawable.bitsPerPixel; 54 if (planemask != ~0 || alu != GXcopy) { 55 if (ppix->drawable.bitsPerPixel == 32) 56 return FALSE; 57 if (planemask != ~0) { 58 NV04EXASetPattern(pNv, 0, planemask, ~0, ~0); 59 if (pNv->currentRop != (alu + 32)) { 60 BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1); 61 PUSH_DATA (push, pNv->NvRop->handle); 62 BEGIN_NV04(push, NV01_ROP(ROP), 1); 63 PUSH_DATA (push, NVROP[alu].copy_planemask); 64 pNv->currentRop = alu + 32; 65 } 66 } else 67 if (pNv->currentRop != alu) { 68 if(pNv->currentRop >= 16) 69 NV04EXASetPattern(pNv, ~0, ~0, ~0, ~0); 70 BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1); 71 PUSH_DATA (push, pNv->NvRop->handle); 72 BEGIN_NV04(push, NV01_ROP(ROP), 1); 73 PUSH_DATA (push, NVROP[alu].copy); 74 pNv->currentRop = alu; 75 } 76 77 BEGIN_NV04(push, subc, mthd, 1); 78 PUSH_DATA (push, 1); /* ROP_AND */ 79 } else { 80 BEGIN_NV04(push, subc, mthd, 1); 81 PUSH_DATA (push, 3); /* SRCCOPY */ 82 } 83 84 return TRUE; 85} 86 87Bool 88NV04EXAPrepareSolid(PixmapPtr ppix, int alu, Pixel planemask, Pixel fg) 89{ 90 ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen); 91 NVPtr pNv = NVPTR(pScrn); 92 struct nouveau_pushbuf *push = pNv->pushbuf; 93 struct nouveau_bo *bo = nouveau_pixmap_bo(ppix); 94 unsigned pitch = exaGetPixmapPitch(ppix); 95 unsigned surf_fmt, rect_fmt; 96 97 /* When SURFACE_FORMAT_A8R8G8B8 is used with GDI_RECTANGLE_TEXT, the 98 * alpha channel gets forced to 0xFF for some reason. We're using 99 * SURFACE_FORMAT_Y32 as a workaround 100 */ 101 if (!NVAccelGetCtxSurf2DFormatFromPixmap(ppix, (int*)&surf_fmt)) 102 return FALSE; 103 if (surf_fmt == NV04_SURFACE_2D_FORMAT_A8R8G8B8) 104 surf_fmt = NV04_SURFACE_2D_FORMAT_Y32; 105 106 rect_fmt = NV04_GDI_COLOR_FORMAT_A8R8G8B8; 107 if (ppix->drawable.bitsPerPixel == 16) { 108 if (ppix->drawable.depth == 16) 109 rect_fmt = NV04_GDI_COLOR_FORMAT_A16R5G6B5; 110 else 111 rect_fmt = NV04_GDI_COLOR_FORMAT_X16A1R5G5B5; 112 } 113 114 if (!PUSH_SPACE(push, 64)) 115 return FALSE; 116 PUSH_RESET(push); 117 118 if (!NV04EXASetROP(ppix, NV04_RECT(OPERATION), alu, planemask)) 119 return FALSE; 120 121 BEGIN_NV04(push, NV04_SF2D(FORMAT), 4); 122 PUSH_DATA (push, surf_fmt); 123 PUSH_DATA (push, (pitch << 16) | pitch); 124 PUSH_MTHDl(push, NV04_SF2D(OFFSET_SOURCE), bo, 0, 125 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 126 PUSH_MTHDl(push, NV04_SF2D(OFFSET_DESTIN), bo, 0, 127 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 128 BEGIN_NV04(push, NV04_RECT(COLOR_FORMAT), 1); 129 PUSH_DATA (push, rect_fmt); 130 131 nouveau_pushbuf_bufctx(push, pNv->bufctx); 132 if (nouveau_pushbuf_validate(push)) { 133 nouveau_pushbuf_bufctx(push, NULL); 134 return FALSE; 135 } 136 137 pNv->fg_colour = fg; 138 return TRUE; 139} 140 141void 142NV04EXASolid (PixmapPtr pPixmap, int x, int y, int x2, int y2) 143{ 144 ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen); 145 NVPtr pNv = NVPTR(pScrn); 146 struct nouveau_pushbuf *push = pNv->pushbuf; 147 int w = x2 - x; 148 int h = y2 - y; 149 150 if (!PUSH_SPACE(push, 5)) 151 return; 152 153 BEGIN_NV04(push, NV04_RECT(COLOR1_A), 1); 154 PUSH_DATA (push, pNv->fg_colour); 155 BEGIN_NV04(push, NV04_RECT(UNCLIPPED_RECTANGLE_POINT(0)), 2); 156 PUSH_DATA (push, (x << 16) | y); 157 PUSH_DATA (push, (w << 16) | h); 158 if ((w * h) >= 512) 159 PUSH_KICK(push); 160} 161 162void 163NV04EXADoneSolid (PixmapPtr pPixmap) 164{ 165 ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen); 166 nouveau_pushbuf_bufctx(NVPTR(pScrn)->pushbuf, NULL); 167} 168 169Bool 170NV04EXAPrepareCopy(PixmapPtr pspix, PixmapPtr pdpix, int dx, int dy, 171 int alu, Pixel planemask) 172{ 173 ScrnInfoPtr pScrn = xf86ScreenToScrn(pspix->drawable.pScreen); 174 NVPtr pNv = NVPTR(pScrn); 175 struct nouveau_pushbuf *push = pNv->pushbuf; 176 struct nouveau_bo *src_bo = nouveau_pixmap_bo(pspix); 177 struct nouveau_bo *dst_bo = nouveau_pixmap_bo(pdpix); 178 int surf_fmt; 179 180 if (pspix->drawable.bitsPerPixel != pdpix->drawable.bitsPerPixel) 181 return FALSE; 182 183 if (!NVAccelGetCtxSurf2DFormatFromPixmap(pdpix, &surf_fmt)) 184 return FALSE; 185 186 if (!PUSH_SPACE(push, 64)) 187 return FALSE; 188 PUSH_RESET(push); 189 190 if (!NV04EXASetROP(pdpix, NV01_BLIT(OPERATION), alu, planemask)) 191 return FALSE; 192 193 BEGIN_NV04(push, NV04_SF2D(FORMAT), 4); 194 PUSH_DATA (push, surf_fmt); 195 PUSH_DATA (push, (exaGetPixmapPitch(pdpix) << 16) | 196 exaGetPixmapPitch(pspix)); 197 PUSH_MTHDl(push, NV04_SF2D(OFFSET_SOURCE), src_bo, 0, 198 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); 199 PUSH_MTHDl(push, NV04_SF2D(OFFSET_DESTIN), dst_bo, 0, 200 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 201 202 nouveau_pushbuf_bufctx(push, pNv->bufctx); 203 if (nouveau_pushbuf_validate(push)) { 204 nouveau_pushbuf_bufctx(push, NULL); 205 return FALSE; 206 } 207 208 pNv->pspix = pspix; 209 pNv->pmpix = NULL; 210 pNv->pdpix = pdpix; 211 return TRUE; 212} 213 214void 215NV04EXACopy(PixmapPtr pdpix, int srcX, int srcY, int dstX, int dstY, 216 int width, int height) 217{ 218 ScrnInfoPtr pScrn = xf86ScreenToScrn(pdpix->drawable.pScreen); 219 NVPtr pNv = NVPTR(pScrn); 220 struct nouveau_pushbuf *push = pNv->pushbuf; 221 int split_dstY = NOUVEAU_ALIGN(dstY + 1, 64); 222 int split_height = split_dstY - dstY; 223 224 if (nouveau_pushbuf_space(push, 16, 2, 0)) 225 return; 226 227 if ((width * height) >= 200000 && pNv->pspix != pNv->pdpix && 228 (dstY > srcY || dstX > srcX) && split_height < height) { 229 /* 230 * KLUDGE - Split the destination rectangle in an 231 * upper misaligned half and a lower tile-aligned 232 * half, then get IMAGE_BLIT to blit the lower piece 233 * downwards (required for sync-to-vblank if the area 234 * to be blitted is large enough). The blob does a 235 * different (not nicer) trick to achieve the same 236 * effect. 237 */ 238 struct nouveau_bo *dst_bo = nouveau_pixmap_bo(pdpix); 239 unsigned dst_pitch = exaGetPixmapPitch(pdpix); 240 241 BEGIN_NV04(push, NV01_BLIT(POINT_IN), 3); 242 PUSH_DATA (push, (srcY << 16) | srcX); 243 PUSH_DATA (push, (dstY << 16) | dstX); 244 PUSH_DATA (push, (split_height << 16) | width); 245 BEGIN_NV04(push, NV04_SF2D(OFFSET_DESTIN), 1); 246 PUSH_RELOC(push, dst_bo, split_dstY * dst_pitch, 247 NOUVEAU_BO_LOW, 0, 0); 248 249 srcY += split_height; 250 height -= split_height; 251 dstY = 0; 252 pNv->pmpix = pdpix; 253 } 254 255 BEGIN_NV04(push, NV01_BLIT(POINT_IN), 3); 256 PUSH_DATA (push, (srcY << 16) | srcX); 257 PUSH_DATA (push, (dstY << 16) | dstX); 258 PUSH_DATA (push, (height << 16) | width); 259 260 if (pNv->pmpix) { 261 struct nouveau_bo *dst_bo = nouveau_pixmap_bo(pdpix); 262 263 BEGIN_NV04(push, NV04_SF2D(OFFSET_DESTIN), 1); 264 PUSH_RELOC(push, dst_bo, 0, NOUVEAU_BO_LOW, 0, 0); 265 pNv->pmpix = NULL; 266 } 267 268 if ((width * height) >= 512) 269 PUSH_KICK(push); 270} 271 272void 273NV04EXADoneCopy(PixmapPtr pdpix) 274{ 275 ScrnInfoPtr pScrn = xf86ScreenToScrn(pdpix->drawable.pScreen); 276 nouveau_pushbuf_bufctx(NVPTR(pScrn)->pushbuf, NULL); 277} 278 279Bool 280NV04EXAUploadIFC(ScrnInfoPtr pScrn, const char *src, int src_pitch, 281 PixmapPtr pdpix, int x, int y, int w, int h, int cpp) 282{ 283 NVPtr pNv = NVPTR(pScrn); 284 ScreenPtr pScreen = pdpix->drawable.pScreen; 285 struct nouveau_bo *bo = nouveau_pixmap_bo(pdpix); 286 struct nouveau_pushbuf *push = pNv->pushbuf; 287 int line_len = w * cpp; 288 int surf_fmt, ifc_fmt; 289 int iw, id, py, ph; 290 int padbytes; 291 Bool ret = FALSE; 292 293 if (pNv->Architecture >= NV_TESLA) 294 return FALSE; 295 296 if (h > 1024) 297 return FALSE; 298 299 if (line_len < 4) 300 return FALSE; 301 302 switch (cpp) { 303 case 2: ifc_fmt = 1; break; 304 case 4: ifc_fmt = 4; break; 305 default: 306 return FALSE; 307 } 308 309 if (!NVAccelGetCtxSurf2DFormatFromPixmap(pdpix, &surf_fmt)) 310 return FALSE; 311 312 /* Pad out input width to cover both COLORA() and COLORB() */ 313 iw = (line_len + 7) & ~7; 314 padbytes = iw - line_len; 315 id = iw / 4; /* line push size */ 316 iw /= cpp; 317 318 /* Don't support lines longer than max push size yet.. */ 319 if (id > 1792) 320 return FALSE; 321 322 if (!PUSH_SPACE(push, 16)) 323 return FALSE; 324 PUSH_RESET(push); 325 326 BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1); 327 PUSH_DATA (push, pNv->NvClipRectangle->handle); 328 BEGIN_NV04(push, NV01_CLIP(POINT), 2); 329 PUSH_DATA (push, (y << 16) | x); 330 PUSH_DATA (push, (h << 16) | w); 331 332 BEGIN_NV04(push, NV04_SF2D(FORMAT), 4); 333 PUSH_DATA (push, surf_fmt); 334 PUSH_DATA (push, (exaGetPixmapPitch(pdpix) << 16) | 335 exaGetPixmapPitch(pdpix)); 336 PUSH_MTHDl(push, NV04_SF2D(OFFSET_SOURCE), bo, 0, 337 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 338 PUSH_MTHDl(push, NV04_SF2D(OFFSET_DESTIN), bo, 0, 339 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 340 341 nouveau_pushbuf_bufctx(push, pNv->bufctx); 342 if (nouveau_pushbuf_validate(push)) 343 goto out; 344 345 py = y; 346 ph = h; 347 while (ph--) { 348 if (PUSH_AVAIL(push) < id + 1 || (py == y)) { 349 if (!PUSH_SPACE(push, id + 8)) 350 goto out; 351 BEGIN_NV04(push, NV01_IFC(OPERATION), 2); 352 PUSH_DATA (push, NV01_IFC_OPERATION_SRCCOPY); 353 PUSH_DATA (push, ifc_fmt); 354 BEGIN_NV04(push, NV01_IFC(POINT), 3); 355 PUSH_DATA (push, (py << 16) | x); 356 PUSH_DATA (push, (h << 16) | w); 357 PUSH_DATA (push, (h << 16) | iw); 358 } 359 360 /* send a line */ 361 if (ph > 0 || !padbytes) { 362 BEGIN_NV04(push, NV01_IFC(COLOR(0)), id); 363 PUSH_DATAp(push, src, id); 364 } else { 365 char padding[8]; 366 int aux = (padbytes + 7) >> 2; 367 memcpy(padding, src + (id - aux) * 4, padbytes); 368 BEGIN_NV04(push, NV01_IFC(COLOR(0)), id); 369 PUSH_DATAp(push, src, id - aux); 370 PUSH_DATAp(push, padding, aux); 371 } 372 373 src += src_pitch; 374 py++; 375 } 376 377 ret = TRUE; 378out: 379 nouveau_pushbuf_bufctx(push, NULL); 380 if (pdpix == pScreen->GetScreenPixmap(pScreen)) 381 PUSH_KICK(push); 382 return ret; 383} 384 385Bool 386NV04EXARectM2MF(NVPtr pNv, int w, int h, int cpp, 387 struct nouveau_bo *src, uint32_t src_off, int src_dom, 388 int src_pitch, int src_h, int src_x, int src_y, 389 struct nouveau_bo *dst, uint32_t dst_off, int dst_dom, 390 int dst_pitch, int dst_h, int dst_x, int dst_y) 391{ 392 struct nv04_fifo *fifo = pNv->channel->data; 393 struct nouveau_pushbuf *push = pNv->pushbuf; 394 struct nouveau_pushbuf_refn refs[] = { 395 { src, src_dom | NOUVEAU_BO_RD }, 396 { dst, dst_dom | NOUVEAU_BO_WR }, 397 }; 398 399 src_off += src_y * src_pitch + src_x * cpp; 400 dst_off += dst_y * dst_pitch + dst_x * cpp; 401 402 while (h) { 403 int line_count = h; 404 if (line_count > 2047) 405 line_count = 2047; 406 h -= line_count; 407 408 if (nouveau_pushbuf_space(push, 16, 4, 0) || 409 nouveau_pushbuf_refn (push, refs, 2)) 410 return FALSE; 411 412 BEGIN_NV04(push, NV03_M2MF(DMA_BUFFER_IN), 2); 413 PUSH_RELOC(push, src, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart); 414 PUSH_RELOC(push, dst, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart); 415 BEGIN_NV04(push, NV03_M2MF(OFFSET_IN), 8); 416 PUSH_RELOC(push, src, src_off, NOUVEAU_BO_LOW, 0, 0); 417 PUSH_RELOC(push, dst, dst_off, NOUVEAU_BO_LOW, 0, 0); 418 PUSH_DATA (push, src_pitch); 419 PUSH_DATA (push, dst_pitch); 420 PUSH_DATA (push, w * cpp); 421 PUSH_DATA (push, line_count); 422 PUSH_DATA (push, 0x00000101); 423 PUSH_DATA (push, 0x00000000); 424 BEGIN_NV04(push, NV04_GRAPH(M2MF, NOP), 1); 425 PUSH_DATA (push, 0x00000000); 426 BEGIN_NV04(push, NV03_M2MF(OFFSET_OUT), 1); 427 PUSH_DATA (push, 0x00000000); 428 429 src_off += src_pitch * line_count; 430 dst_off += dst_pitch * line_count; 431 } 432 433 return TRUE; 434} 435