2 * Copyright 2003 NVIDIA, Corporation
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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
23 #include "nv_include.h"
31 const int NVCopyROP[16] =
35 0x44, /* GXandReverse */
37 0x22, /* GXandInverted */
44 0xDD, /* GXorReverse */
45 0x33, /* GXcopyInverted */
46 0xBB, /* GXorInverted */
52 NVSetPattern(ScrnInfoPtr pScrn, CARD32 clr0, CARD32 clr1,
53 CARD32 pat0, CARD32 pat1)
55 NVPtr pNv = NVPTR(pScrn);
56 struct nouveau_channel *chan = pNv->chan;
57 struct nouveau_grobj *patt = pNv->NvImagePattern;
59 BEGIN_RING(chan, patt, NV04_IMAGE_PATTERN_MONOCHROME_COLOR0, 4);
60 OUT_RING (chan, clr0);
61 OUT_RING (chan, clr1);
62 OUT_RING (chan, pat0);
63 OUT_RING (chan, pat1);
67 NVSetROP(ScrnInfoPtr pScrn, CARD32 alu, CARD32 planemask)
69 NVPtr pNv = NVPTR(pScrn);
70 struct nouveau_channel *chan = pNv->chan;
71 struct nouveau_grobj *objrop = pNv->NvRop;
72 int rop = NVCopyROP[alu] & 0xf0;
74 if (planemask != ~0) {
75 NVSetPattern(pScrn, 0, planemask, ~0, ~0);
76 if (pNv->currentRop != (alu + 32)) {
77 BEGIN_RING(chan, objrop, NV03_CONTEXT_ROP_ROP, 1);
78 OUT_RING (chan, rop | 0x0a);
79 pNv->currentRop = alu + 32;
82 if (pNv->currentRop != alu) {
83 if(pNv->currentRop >= 16)
84 NVSetPattern(pScrn, ~0, ~0, ~0, ~0);
85 BEGIN_RING(chan, objrop, NV03_CONTEXT_ROP_ROP, 1);
86 OUT_RING (chan, rop | (rop >> 4));
87 pNv->currentRop = alu;
91 /* EXA acceleration hooks */
92 static void NVExaWaitMarker(ScreenPtr pScreen, int marker)
94 NVSync(xf86Screens[pScreen->myNum]);
97 static Bool NVExaPrepareSolid(PixmapPtr pPixmap,
102 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
103 NVPtr pNv = NVPTR(pScrn);
104 struct nouveau_channel *chan = pNv->chan;
105 struct nouveau_grobj *surf2d = pNv->NvContextSurfaces;
106 struct nouveau_grobj *rect = pNv->NvRectangle;
107 unsigned int fmt, pitch, color;
109 planemask |= ~0 << pPixmap->drawable.bitsPerPixel;
110 if (planemask != ~0 || alu != GXcopy) {
111 if (pPixmap->drawable.bitsPerPixel == 32)
113 BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
114 OUT_RING (chan, 1); /* ROP_AND */
115 NVSetROP(pScrn, alu, planemask);
117 BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
118 OUT_RING (chan, 3); /* SRCCOPY */
121 if (!NVAccelGetCtxSurf2DFormatFromPixmap(pPixmap, (int*)&fmt))
123 pitch = exaGetPixmapPitch(pPixmap);
125 if (pPixmap->drawable.bitsPerPixel == 16) {
126 /* convert to 32bpp */
127 uint32_t r = (fg&0x1F) * 255 / 31;
128 uint32_t g = ((fg&0x7E0) >> 5) * 255 / 63;
129 uint32_t b = ((fg&0xF100) >> 11) * 255 / 31;
130 color = b<<16 | g<<8 | r;
134 /* When SURFACE_FORMAT_A8R8G8B8 is used with GDI_RECTANGLE_TEXT, the
135 * alpha channel gets forced to 0xFF for some reason. We're using
136 * SURFACE_FORMAT_Y32 as a workaround
138 if (fmt == NV04_CONTEXT_SURFACES_2D_FORMAT_A8R8G8B8)
139 fmt = NV04_CONTEXT_SURFACES_2D_FORMAT_Y32;
141 BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
142 OUT_RING (chan, fmt);
143 OUT_RING (chan, (pitch << 16) | pitch);
144 OUT_PIXMAPl(chan, pPixmap, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
145 OUT_PIXMAPl(chan, pPixmap, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
147 BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT, 1);
148 OUT_RING (chan, NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8);
149 BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_COLOR1_A, 1);
150 OUT_RING (chan, color);
155 static void NVExaSolid (PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
157 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
158 NVPtr pNv = NVPTR(pScrn);
159 struct nouveau_channel *chan = pNv->chan;
160 struct nouveau_grobj *rect = pNv->NvRectangle;
164 BEGIN_RING(chan, rect,
165 NV04_GDI_RECTANGLE_TEXT_UNCLIPPED_RECTANGLE_POINT(0), 2);
166 OUT_RING (chan, (x1 << 16) | y1);
167 OUT_RING (chan, (width << 16) | height);
169 if((width * height) >= 512)
173 static void NVExaDoneSolid (PixmapPtr pPixmap)
177 static Bool NVExaPrepareCopy(PixmapPtr pSrcPixmap,
178 PixmapPtr pDstPixmap,
184 ScrnInfoPtr pScrn = xf86Screens[pSrcPixmap->drawable.pScreen->myNum];
185 NVPtr pNv = NVPTR(pScrn);
186 struct nouveau_channel *chan = pNv->chan;
187 struct nouveau_grobj *surf2d = pNv->NvContextSurfaces;
188 struct nouveau_grobj *blit = pNv->NvImageBlit;
191 if (pSrcPixmap->drawable.bitsPerPixel !=
192 pDstPixmap->drawable.bitsPerPixel)
195 planemask |= ~0 << pDstPixmap->drawable.bitsPerPixel;
196 if (planemask != ~0 || alu != GXcopy) {
197 if (pDstPixmap->drawable.bitsPerPixel == 32)
199 BEGIN_RING(chan, blit, NV04_IMAGE_BLIT_OPERATION, 1);
200 OUT_RING (chan, 1); /* ROP_AND */
201 NVSetROP(pScrn, alu, planemask);
203 BEGIN_RING(chan, blit, NV04_IMAGE_BLIT_OPERATION, 1);
204 OUT_RING (chan, 3); /* SRCCOPY */
207 if (!NVAccelGetCtxSurf2DFormatFromPixmap(pDstPixmap, &fmt))
210 BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
211 OUT_RING (chan, fmt);
212 OUT_RING (chan, (exaGetPixmapPitch(pDstPixmap) << 16) |
213 (exaGetPixmapPitch(pSrcPixmap)));
214 OUT_PIXMAPl(chan, pSrcPixmap, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
215 OUT_PIXMAPl(chan, pDstPixmap, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
220 static void NVExaCopy(PixmapPtr pDstPixmap,
228 ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
229 NVPtr pNv = NVPTR(pScrn);
230 struct nouveau_channel *chan = pNv->chan;
231 struct nouveau_grobj *blit = pNv->NvImageBlit;
233 BEGIN_RING(chan, blit, NV01_IMAGE_BLIT_POINT_IN, 3);
234 OUT_RING (chan, (srcY << 16) | srcX);
235 OUT_RING (chan, (dstY << 16) | dstX);
236 OUT_RING (chan, (height << 16) | width);
238 if((width * height) >= 512)
242 static void NVExaDoneCopy (PixmapPtr pDstPixmap) {}
244 static inline Bool NVAccelMemcpyRect(char *dst, const char *src, int height,
245 int dst_pitch, int src_pitch, int line_len)
247 if ((src_pitch == line_len) && (src_pitch == dst_pitch)) {
248 memcpy(dst, src, line_len*height);
251 memcpy(dst, src, line_len);
261 NVAccelDownloadM2MF(PixmapPtr pspix, int x, int y, int w, int h,
262 char *dst, unsigned dst_pitch)
264 ScrnInfoPtr pScrn = xf86Screens[pspix->drawable.pScreen->myNum];
265 NVPtr pNv = NVPTR(pScrn);
266 struct nouveau_channel *chan = pNv->chan;
267 struct nouveau_grobj *m2mf = pNv->NvMemFormat;
268 unsigned cpp = pspix->drawable.bitsPerPixel / 8;
269 unsigned line_len = w * cpp;
270 unsigned src_pitch = 0, src_offset = 0, linear = 0;
272 BEGIN_RING(chan, m2mf, 0x184, 2);
273 OUT_PIXMAPo(chan, pspix,
274 NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
275 OUT_RELOCo(chan, pNv->GART, NOUVEAU_BO_GART | NOUVEAU_BO_WR);
277 if (pNv->Architecture < NV_ARCH_50 ||
278 exaGetPixmapOffset(pspix) < pNv->EXADriverPtr->offScreenBase) {
280 src_pitch = exaGetPixmapPitch(pspix);
281 src_offset = (y * src_pitch) + (x * cpp);
284 if (pNv->Architecture >= NV_ARCH_50) {
286 BEGIN_RING(chan, m2mf, 0x0200, 1);
289 BEGIN_RING(chan, m2mf, 0x0200, 6);
292 OUT_RING (chan, pspix->drawable.width * cpp);
293 OUT_RING (chan, pspix->drawable.height);
298 BEGIN_RING(chan, m2mf, 0x021c, 1);
303 char *src = pNv->GART->map;
306 if (h * line_len <= pNv->GART->size) {
309 line_count = pNv->GART->size / line_len;
315 if (line_count > 2047)
318 if (pNv->Architecture >= NV_ARCH_50) {
320 BEGIN_RING(chan, m2mf, 0x0218, 1);
321 OUT_RING (chan, (y << 16) | (x * cpp));
324 BEGIN_RING(chan, m2mf, 0x238, 2);
325 OUT_PIXMAPh(chan, pspix, src_offset, NOUVEAU_BO_GART |
326 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
327 OUT_RELOCh(chan, pNv->GART, 0, NOUVEAU_BO_GART |
331 BEGIN_RING(chan, m2mf,
332 NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
333 OUT_PIXMAPl(chan, pspix, src_offset, NOUVEAU_BO_GART |
334 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
335 OUT_RELOCl(chan, pNv->GART, 0, NOUVEAU_BO_GART | NOUVEAU_BO_WR);
336 OUT_RING (chan, src_pitch);
337 OUT_RING (chan, line_len);
338 OUT_RING (chan, line_len);
339 OUT_RING (chan, line_count);
340 OUT_RING (chan, (1<<8)|1);
343 nouveau_notifier_reset(pNv->notify0, 0);
344 BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
346 BEGIN_RING(chan, m2mf, 0x100, 1);
349 if (nouveau_notifier_wait_status(pNv->notify0, 0, 0, 2000))
352 if (dst_pitch == line_len) {
353 memcpy(dst, src, dst_pitch * line_count);
354 dst += dst_pitch * line_count;
356 for (i = 0; i < line_count; i++) {
357 memcpy(dst, src, line_len);
364 src_offset += line_count * src_pitch;
373 NVExaPixmapMap(PixmapPtr pPix)
376 #if NOUVEAU_EXA_PIXMAPS
377 struct nouveau_pixmap *nvpix;
379 nvpix = exaGetPixmapDriverPrivate(pPix);
380 if (!nvpix || !nvpix->bo)
383 map = nvpix->bo->map;
385 ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
386 NVPtr pNv = NVPTR(pScrn);
387 map = pNv->FB->map + exaGetPixmapOffset(pPix);
388 #endif /* NOUVEAU_EXA_PIXMAPS */
392 static Bool NVDownloadFromScreen(PixmapPtr pSrc,
395 char *dst, int dst_pitch)
397 ScrnInfoPtr pScrn = xf86Screens[pSrc->drawable.pScreen->myNum];
398 NVPtr pNv = NVPTR(pScrn);
399 int src_pitch, cpp, offset;
402 src_pitch = exaGetPixmapPitch(pSrc);
403 cpp = pSrc->drawable.bitsPerPixel >> 3;
404 offset = (y * src_pitch) + (x * cpp);
407 if (NVAccelDownloadM2MF(pSrc, x, y, w, h, dst, dst_pitch))
411 src = NVExaPixmapMap(pSrc);
415 exaWaitSync(pSrc->drawable.pScreen);
416 if (NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp))
423 NVAccelUploadIFC(ScrnInfoPtr pScrn, const char *src, int src_pitch,
424 PixmapPtr pDst, int x, int y, int w, int h, int cpp)
426 NVPtr pNv = NVPTR(pScrn);
427 struct nouveau_channel *chan = pNv->chan;
428 struct nouveau_grobj *surf2d = pNv->NvContextSurfaces;
429 struct nouveau_grobj *clip = pNv->NvClipRectangle;
430 struct nouveau_grobj *ifc = pNv->NvImageFromCpu;
431 int line_len = w * cpp;
432 int iw, id, surf_fmt, ifc_fmt;
435 if (pNv->Architecture >= NV_ARCH_50)
445 case 2: ifc_fmt = 1; break;
446 case 4: ifc_fmt = 4; break;
451 if (!NVAccelGetCtxSurf2DFormatFromPixmap(pDst, &surf_fmt))
454 BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
455 OUT_RING (chan, surf_fmt);
456 OUT_RING (chan, (exaGetPixmapPitch(pDst) << 16) | exaGetPixmapPitch(pDst));
457 OUT_PIXMAPl(chan, pDst, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
458 OUT_PIXMAPl(chan, pDst, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
460 /* Pad out input width to cover both COLORA() and COLORB() */
461 iw = (line_len + 7) & ~7;
462 padbytes = iw - line_len;
463 id = iw / 4; /* line push size */
466 /* Don't support lines longer than max push size yet.. */
470 BEGIN_RING(chan, clip, NV01_CONTEXT_CLIP_RECTANGLE_POINT, 2);
471 OUT_RING (chan, 0x0);
472 OUT_RING (chan, 0x7FFF7FFF);
474 BEGIN_RING(chan, ifc, NV01_IMAGE_FROM_CPU_OPERATION, 2);
475 OUT_RING (chan, NV01_IMAGE_FROM_CPU_OPERATION_SRCCOPY);
476 OUT_RING (chan, ifc_fmt);
477 BEGIN_RING(chan, ifc, NV01_IMAGE_FROM_CPU_POINT, 3);
478 OUT_RING (chan, (y << 16) | x); /* dst point */
479 OUT_RING (chan, (h << 16) | w); /* width/height out */
480 OUT_RING (chan, (h << 16) | iw); /* width/height in */
486 BEGIN_RING(chan, ifc, NV01_IMAGE_FROM_CPU_COLOR(0), id);
487 OUT_RINGp (chan, src, id);
493 int aux = (padbytes + 7) >> 2;
494 BEGIN_RING(chan, ifc, NV01_IMAGE_FROM_CPU_COLOR(0), id);
495 OUT_RINGp (chan, src, id - aux);
496 memcpy(padding, src + (id - aux) * 4, padbytes);
497 OUT_RINGp (chan, padding, aux);
504 NVAccelUploadM2MF(PixmapPtr pdpix, int x, int y, int w, int h,
505 const char *src, int src_pitch)
507 ScrnInfoPtr pScrn = xf86Screens[pdpix->drawable.pScreen->myNum];
508 NVPtr pNv = NVPTR(pScrn);
509 struct nouveau_channel *chan = pNv->chan;
510 struct nouveau_grobj *m2mf = pNv->NvMemFormat;
511 unsigned cpp = pdpix->drawable.bitsPerPixel / 8;
512 unsigned line_len = w * cpp;
513 unsigned dst_pitch = 0, dst_offset = 0, linear = 0;
515 BEGIN_RING(chan, m2mf, 0x184, 2);
516 OUT_RELOCo(chan, pNv->GART, NOUVEAU_BO_GART | NOUVEAU_BO_RD);
517 OUT_PIXMAPo(chan, pdpix,
518 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_WR);
520 if (pNv->Architecture < NV_ARCH_50 ||
521 exaGetPixmapOffset(pdpix) < pNv->EXADriverPtr->offScreenBase) {
523 dst_pitch = exaGetPixmapPitch(pdpix);
524 dst_offset = (y * dst_pitch) + (x * cpp);
527 if (pNv->Architecture >= NV_ARCH_50) {
528 BEGIN_RING(chan, m2mf, 0x0200, 1);
532 BEGIN_RING(chan, m2mf, 0x021c, 1);
535 BEGIN_RING(chan, m2mf, 0x021c, 6);
538 OUT_RING (chan, pdpix->drawable.width * cpp);
539 OUT_RING (chan, pdpix->drawable.height);
546 char *dst = pNv->GART->map;
549 /* Determine max amount of data we can DMA at once */
550 if (h * line_len <= pNv->GART->size) {
553 line_count = pNv->GART->size / line_len;
559 if (line_count > 2047)
563 if (src_pitch == line_len) {
564 memcpy(dst, src, src_pitch * line_count);
565 src += src_pitch * line_count;
567 for (i = 0; i < line_count; i++) {
568 memcpy(dst, src, line_len);
574 if (pNv->Architecture >= NV_ARCH_50) {
576 BEGIN_RING(chan, m2mf, 0x0234, 1);
577 OUT_RING (chan, (y << 16) | (x * cpp));
580 BEGIN_RING(chan, m2mf, 0x0238, 2);
581 OUT_RELOCh(chan, pNv->GART, 0, NOUVEAU_BO_GART |
583 OUT_PIXMAPh(chan, pdpix, dst_offset, NOUVEAU_BO_VRAM |
584 NOUVEAU_BO_GART | NOUVEAU_BO_WR);
588 BEGIN_RING(chan, m2mf,
589 NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
590 OUT_RELOCl(chan, pNv->GART, 0, NOUVEAU_BO_GART | NOUVEAU_BO_RD);
591 OUT_PIXMAPl(chan, pdpix, dst_offset, NOUVEAU_BO_VRAM |
592 NOUVEAU_BO_GART | NOUVEAU_BO_WR);
593 OUT_RING (chan, line_len);
594 OUT_RING (chan, dst_pitch);
595 OUT_RING (chan, line_len);
596 OUT_RING (chan, line_count);
597 OUT_RING (chan, (1<<8)|1);
600 nouveau_notifier_reset(pNv->notify0, 0);
601 BEGIN_RING(chan, m2mf, NV04_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
603 BEGIN_RING(chan, m2mf, 0x100, 1);
606 if (nouveau_notifier_wait_status(pNv->notify0, 0, 0, 2000))
610 dst_offset += line_count * dst_pitch;
618 static Bool NVUploadToScreen(PixmapPtr pDst,
619 int x, int y, int w, int h,
620 char *src, int src_pitch)
622 ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
623 NVPtr pNv = NVPTR(pScrn);
627 dst_pitch = exaGetPixmapPitch(pDst);
628 cpp = pDst->drawable.bitsPerPixel >> 3;
630 /* try hostdata transfer */
631 if (w * h * cpp < 16*1024) /* heuristic */
633 if (pNv->Architecture < NV_ARCH_50) {
634 if (NVAccelUploadIFC(pScrn, src, src_pitch, pDst,
636 exaMarkSync(pDst->drawable.pScreen);
640 if (NV50EXAUploadSIFC(src, src_pitch, pDst,
642 exaMarkSync(pDst->drawable.pScreen);
648 /* try gart-based transfer */
650 if (NVAccelUploadM2MF(pDst, x, y, w, h, src, src_pitch))
654 /* fallback to memcpy-based transfer */
655 dst = NVExaPixmapMap(pDst);
658 dst += (y * dst_pitch) + (x * cpp);
659 exaWaitSync(pDst->drawable.pScreen);
660 if (NVAccelMemcpyRect(dst, src, h, dst_pitch, src_pitch, w*cpp))
666 #if NOUVEAU_EXA_PIXMAPS
668 NVExaPrepareAccess(PixmapPtr pPix, int index)
670 ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
671 NVPtr pNv = NVPTR(pScrn);
672 struct nouveau_pixmap *nvpix;
675 nvpix = exaGetPixmapDriverPrivate(pPix);
676 if (!nvpix || !nvpix->bo)
679 /*XXX: ho hum.. sync if needed */
684 if (nouveau_bo_map(nvpix->bo, NOUVEAU_BO_RDWR))
686 pPix->devPrivate.ptr = nvpix->bo->map;
687 nvpix->mapped = TRUE;
692 NVExaFinishAccess(PixmapPtr pPix, int index)
694 ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
695 NVPtr pNv = NVPTR(pScrn);
696 struct nouveau_pixmap *nvpix;
699 nvpix = exaGetPixmapDriverPrivate(pPix);
700 if (!nvpix || !nvpix->bo || !nvpix->mapped)
703 nouveau_bo_unmap(nvpix->bo);
704 pPix->devPrivate.ptr = NULL;
705 nvpix->mapped = FALSE;
709 NVExaPixmapIsOffscreen(PixmapPtr pPix)
711 ScrnInfoPtr pScrn = xf86Screens[pPix->drawable.pScreen->myNum];
712 NVPtr pNv = NVPTR(pScrn);
713 struct nouveau_pixmap *nvpix;
716 nvpix = exaGetPixmapDriverPrivate(pPix);
717 if (!nvpix || !nvpix->bo)
724 NVExaCreatePixmap(ScreenPtr pScreen, int size, int align)
726 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
727 NVPtr pNv = NVPTR(pScrn);
728 struct nouveau_pixmap *nvpix;
730 nvpix = xcalloc(1, sizeof(struct nouveau_pixmap));
735 if (nouveau_bo_new(pNv->dev, NOUVEAU_BO_VRAM, 0, size,
746 NVExaDestroyPixmap(ScreenPtr pScreen, void *driverPriv)
748 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
749 NVPtr pNv = NVPTR(pScrn);
750 struct nouveau_pixmap *nvpix = driverPriv;
755 /*XXX: only if pending relocs reference this buffer..*/
758 nouveau_bo_del(&nvpix->bo);
763 NVExaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, int depth,
764 int bitsPerPixel, int devKind, pointer pPixData)
766 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
767 NVPtr pNv = NVPTR(pScrn);
768 struct nouveau_pixmap *nvpix;
770 if (pPixData == pNv->FB->map) {
771 nvpix = exaGetPixmapDriverPrivate(pPixmap);
775 if (nouveau_bo_ref(pNv->dev, pNv->FB->handle, &nvpix->bo))
778 miModifyPixmapHeader(pPixmap, width, height, depth,
779 bitsPerPixel, devKind, NULL);
787 #if !NOUVEAU_EXA_PIXMAPS
789 nouveau_exa_pixmap_is_offscreen(PixmapPtr pPixmap)
791 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
792 NVPtr pNv = NVPTR(pScrn);
793 void *addr = (void *)pPixmap->devPrivate.ptr;
795 if (addr >= pNv->FB->map && addr < (pNv->FB->map + pNv->FB->size))
798 if (pNv->shadow[0] && (addr >= pNv->shadow[0]->map && addr < (pNv->shadow[0]->map + pNv->shadow[0]->size)))
801 if (pNv->shadow[1] && (addr >= pNv->shadow[1]->map && addr < (pNv->shadow[1]->map + pNv->shadow[1]->size)))
807 #endif /* !NOUVEAU_EXA_PIXMAPS */
810 NVExaPixmapIsOnscreen(PixmapPtr pPixmap)
812 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
813 NVPtr pNv = NVPTR(pScrn);
815 #if NOUVEAU_EXA_PIXMAPS
816 struct nouveau_pixmap *nvpix;
817 nvpix = exaGetPixmapDriverPrivate(pPixmap);
819 if (nvpix && nvpix->bo == pNv->FB)
823 unsigned long offset = exaGetPixmapOffset(pPixmap);
825 if (offset < pNv->EXADriverPtr->offScreenBase)
827 #endif /* NOUVEAU_EXA_PIXMAPS */
833 NVExaInit(ScreenPtr pScreen)
835 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
836 NVPtr pNv = NVPTR(pScrn);
838 if(!(pNv->EXADriverPtr = (ExaDriverPtr) xnfcalloc(sizeof(ExaDriverRec), 1))) {
843 pNv->EXADriverPtr->exa_major = EXA_VERSION_MAJOR;
844 pNv->EXADriverPtr->exa_minor = EXA_VERSION_MINOR;
845 pNv->EXADriverPtr->flags = EXA_OFFSCREEN_PIXMAPS;
847 if (pNv->Architecture < NV_ARCH_50) {
848 pNv->EXADriverPtr->pixmapOffsetAlign = 256;
850 /* Workaround some corruption issues caused by exa's
851 * offscreen memory allocation no understanding G8x/G9x
852 * memory layout. This is terrible, but it should
853 * prevent all but the most unlikely cases from occuring.
855 * See http://nouveau.freedesktop.org/wiki/NV50Support for
856 * a far better fix until the ng branch is ready to be used.
858 pNv->EXADriverPtr->pixmapOffsetAlign = 65536;
859 pNv->EXADriverPtr->flags |= EXA_OFFSCREEN_ALIGN_POT;
861 pNv->EXADriverPtr->pixmapPitchAlign = 64;
863 #if NOUVEAU_EXA_PIXMAPS
864 if (NOUVEAU_EXA_PIXMAPS) {
865 pNv->EXADriverPtr->flags |= EXA_HANDLES_PIXMAPS;
866 pNv->EXADriverPtr->PrepareAccess = NVExaPrepareAccess;
867 pNv->EXADriverPtr->FinishAccess = NVExaFinishAccess;
868 pNv->EXADriverPtr->PixmapIsOffscreen = NVExaPixmapIsOffscreen;
869 pNv->EXADriverPtr->CreatePixmap = NVExaCreatePixmap;
870 pNv->EXADriverPtr->DestroyPixmap = NVExaDestroyPixmap;
871 pNv->EXADriverPtr->ModifyPixmapHeader = NVExaModifyPixmapHeader;
875 pNv->EXADriverPtr->memoryBase = pNv->FB->map;
876 pNv->EXADriverPtr->offScreenBase = NOUVEAU_ALIGN(pScrn->virtualX, 64) * NOUVEAU_ALIGN(pScrn->virtualY,64)
877 * (pScrn->bitsPerPixel / 8);
878 pNv->EXADriverPtr->memorySize = pNv->FB->size;
881 if (pNv->Architecture >= NV_ARCH_50) {
882 struct nouveau_device_priv *nvdev = nouveau_device(pNv->dev);
883 struct nouveau_bo_priv *nvbo = nouveau_bo(pNv->FB);
884 struct drm_nouveau_mem_tile t;
886 t.offset = nvbo->drm.offset;
887 t.flags = nvbo->drm.flags | NOUVEAU_MEM_TILE;
888 t.delta = pNv->EXADriverPtr->offScreenBase;
889 t.size = pNv->EXADriverPtr->memorySize -
890 pNv->EXADriverPtr->offScreenBase;
891 drmCommandWrite(nvdev->fd, DRM_NOUVEAU_MEM_TILE, &t, sizeof(t));
893 pNv->EXADriverPtr->maxX = 8192;
894 pNv->EXADriverPtr->maxY = 8192;
896 if (pNv->Architecture >= NV_ARCH_20) {
897 pNv->EXADriverPtr->maxX = 4096;
898 pNv->EXADriverPtr->maxY = 4096;
900 pNv->EXADriverPtr->maxX = 2048;
901 pNv->EXADriverPtr->maxY = 2048;
904 pNv->EXADriverPtr->WaitMarker = NVExaWaitMarker;
906 /* Install default hooks */
907 pNv->EXADriverPtr->DownloadFromScreen = NVDownloadFromScreen;
908 pNv->EXADriverPtr->UploadToScreen = NVUploadToScreen;
910 if (pNv->Architecture < NV_ARCH_50) {
911 pNv->EXADriverPtr->PrepareCopy = NVExaPrepareCopy;
912 pNv->EXADriverPtr->Copy = NVExaCopy;
913 pNv->EXADriverPtr->DoneCopy = NVExaDoneCopy;
915 pNv->EXADriverPtr->PrepareSolid = NVExaPrepareSolid;
916 pNv->EXADriverPtr->Solid = NVExaSolid;
917 pNv->EXADriverPtr->DoneSolid = NVExaDoneSolid;
919 pNv->EXADriverPtr->PrepareCopy = NV50EXAPrepareCopy;
920 pNv->EXADriverPtr->Copy = NV50EXACopy;
921 pNv->EXADriverPtr->DoneCopy = NV50EXADoneCopy;
923 pNv->EXADriverPtr->PrepareSolid = NV50EXAPrepareSolid;
924 pNv->EXADriverPtr->Solid = NV50EXASolid;
925 pNv->EXADriverPtr->DoneSolid = NV50EXADoneSolid;
928 switch (pNv->Architecture) {
931 pNv->EXADriverPtr->CheckComposite = NV10CheckComposite;
932 pNv->EXADriverPtr->PrepareComposite = NV10PrepareComposite;
933 pNv->EXADriverPtr->Composite = NV10Composite;
934 pNv->EXADriverPtr->DoneComposite = NV10DoneComposite;
937 pNv->EXADriverPtr->CheckComposite = NV30EXACheckComposite;
938 pNv->EXADriverPtr->PrepareComposite = NV30EXAPrepareComposite;
939 pNv->EXADriverPtr->Composite = NV30EXAComposite;
940 pNv->EXADriverPtr->DoneComposite = NV30EXADoneComposite;
943 pNv->EXADriverPtr->CheckComposite = NV40EXACheckComposite;
944 pNv->EXADriverPtr->PrepareComposite = NV40EXAPrepareComposite;
945 pNv->EXADriverPtr->Composite = NV40EXAComposite;
946 pNv->EXADriverPtr->DoneComposite = NV40EXADoneComposite;
949 pNv->EXADriverPtr->CheckComposite = NV50EXACheckComposite;
950 pNv->EXADriverPtr->PrepareComposite = NV50EXAPrepareComposite;
951 pNv->EXADriverPtr->Composite = NV50EXAComposite;
952 pNv->EXADriverPtr->DoneComposite = NV50EXADoneComposite;
958 if (!exaDriverInit(pScreen, pNv->EXADriverPtr))
961 /* EXA init catches this, but only for xserver >= 1.4 */
962 if (pNv->VRAMPhysicalSize / 2 < NOUVEAU_ALIGN(pScrn->virtualX, 64) * NOUVEAU_ALIGN(pScrn->virtualY, 64) * (pScrn->bitsPerPixel >> 3)) {
963 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "The virtual screen size's resolution is too big for the video RAM framebuffer at this colour depth.\n");