2 * Copyright 2007 Arthur Huillet
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
29 #include <X11/extensions/Xv.h>
32 #include "dixstruct.h"
35 #include "nv_include.h"
38 #define IMAGE_MAX_W 2046
39 #define IMAGE_MAX_H 2046
41 #define TEX_IMAGE_MAX_W 4096
42 #define TEX_IMAGE_MAX_H 4096
44 #define OFF_DELAY 500 /* milliseconds */
45 #define FREE_DELAY 5000
47 #define NUM_BLIT_PORTS 16
48 #define NUM_TEXTURE_PORTS 32
51 #define NVStopOverlay(X) (((pNv->Architecture == NV_ARCH_04) ? NV04StopOverlay(X) : NV10StopOverlay(X)))
53 /* Value taken by pPriv -> currentHostBuffer when we failed to allocate the two private buffers in TT memory, so that we can catch this case
54 and attempt no other allocation afterwards (performance reasons) */
55 #define NO_PRIV_HOST_BUFFER_AVAILABLE 9999
57 /* Xv DMA notifiers status tracing */
59 XV_DMA_NOTIFIER_NOALLOC=0, //notifier not allocated
60 XV_DMA_NOTIFIER_INUSE=1,
61 XV_DMA_NOTIFIER_FREE=2, //notifier allocated, ready for use
64 /* We have six notifiers available, they are not allocated at startup */
65 static int XvDMANotifierStatus[6]= { XV_DMA_NOTIFIER_NOALLOC , XV_DMA_NOTIFIER_NOALLOC , XV_DMA_NOTIFIER_NOALLOC ,
66 XV_DMA_NOTIFIER_NOALLOC , XV_DMA_NOTIFIER_NOALLOC , XV_DMA_NOTIFIER_NOALLOC };
67 static struct nouveau_notifier *XvDMANotifiers[6];
69 /* NVPutImage action flags */
77 IS_RGB=64, //I am not sure how long we will support it
80 #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
82 Atom xvBrightness, xvContrast, xvColorKey, xvSaturation,
83 xvHue, xvAutopaintColorKey, xvSetDefaults, xvDoubleBuffer,
84 xvITURBT709, xvSyncToVBlank, xvOnCRTCNb;
86 /* client libraries expect an encoding */
87 static XF86VideoEncodingRec DummyEncoding =
91 IMAGE_MAX_W, IMAGE_MAX_H,
95 static XF86VideoEncodingRec DummyEncodingTex =
99 TEX_IMAGE_MAX_W, TEX_IMAGE_MAX_H,
103 #define NUM_FORMATS_ALL 6
105 XF86VideoFormatRec NVFormats[NUM_FORMATS_ALL] =
107 {15, TrueColor}, {16, TrueColor}, {24, TrueColor},
108 {15, DirectColor}, {16, DirectColor}, {24, DirectColor}
111 #define NUM_NV04_OVERLAY_ATTRIBUTES 4
112 XF86AttributeRec NV04OverlayAttributes[NUM_NV04_OVERLAY_ATTRIBUTES] =
114 {XvSettable | XvGettable, -512, 511, "XV_BRIGHTNESS"},
115 {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
116 {XvSettable | XvGettable, 0, 1, "XV_AUTOPAINT_COLORKEY"},
117 {XvSettable , 0, 0, "XV_SET_DEFAULTS"},
121 #define NUM_NV10_OVERLAY_ATTRIBUTES 10
122 XF86AttributeRec NV10OverlayAttributes[NUM_NV10_OVERLAY_ATTRIBUTES] =
124 {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"},
125 {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
126 {XvSettable | XvGettable, 0, 1, "XV_AUTOPAINT_COLORKEY"},
127 {XvSettable , 0, 0, "XV_SET_DEFAULTS"},
128 {XvSettable | XvGettable, -512, 511, "XV_BRIGHTNESS"},
129 {XvSettable | XvGettable, 0, 8191, "XV_CONTRAST"},
130 {XvSettable | XvGettable, 0, 8191, "XV_SATURATION"},
131 {XvSettable | XvGettable, 0, 360, "XV_HUE"},
132 {XvSettable | XvGettable, 0, 1, "XV_ITURBT_709"},
133 {XvSettable | XvGettable, 0, 1, "XV_ON_CRTC_NB"},
136 #define NUM_BLIT_ATTRIBUTES 2
137 XF86AttributeRec NVBlitAttributes[NUM_BLIT_ATTRIBUTES] =
139 {XvSettable , 0, 0, "XV_SET_DEFAULTS"},
140 {XvSettable | XvGettable, 0, 1, "XV_SYNC_TO_VBLANK"}
143 #define NUM_TEXTURED_ATTRIBUTES 2
144 XF86AttributeRec NVTexturedAttributes[NUM_TEXTURED_ATTRIBUTES] =
146 {XvSettable , 0, 0, "XV_SET_DEFAULTS"},
147 {XvSettable | XvGettable, 0, 1, "XV_SYNC_TO_VBLANK"}
151 #define NUM_IMAGES_YUV 4
152 #define NUM_IMAGES_ALL 5
154 #define FOURCC_RGB 0x0000003
155 #define XVIMAGE_RGB \
160 { 0x03, 0x00, 0x00, 0x00, \
161 0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \
165 24, 0x00ff0000, 0x0000ff00, 0x000000ff, \
170 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \
174 static XF86ImageRec NVImages[NUM_IMAGES_ALL] =
184 nv_window_belongs_to_crtc(ScrnInfoPtr pScrn, int x, int y, int w, int h)
186 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
187 NVPtr pNv = NVPTR(pScrn);
194 if (!pNv->randr12_enable) {
196 * Without RandR 1.2, we'll just return which CRTCs
199 if (pNv->crtc_active[0])
201 else if (pNv->crtc_active[1])
207 for (i = 0; i < xf86_config->num_crtc; i++) {
208 crtc = xf86_config->crtc[i];
213 if ((x < (crtc->x + crtc->mode.HDisplay)) &&
214 (y < (crtc->y + crtc->mode.VDisplay)) &&
215 ((x + w) > crtc->x) &&
224 NVWaitVSync(ScrnInfoPtr pScrn, int crtc)
226 NVPtr pNv = NVPTR(pScrn);
228 BEGIN_RING(NvImageBlit, 0x0000012C, 1);
230 BEGIN_RING(NvImageBlit, 0x00000134, 1);
232 BEGIN_RING(NvImageBlit, 0x00000100, 1);
234 BEGIN_RING(NvImageBlit, 0x00000130, 1);
240 * set attributes of port "pPriv" to compiled-in (except for colorKey) defaults
241 * this function does not care about the kind of adapter the port is for
243 * @param pScrn screen to get the default colorKey from
244 * @param pPriv port to reset to defaults
247 NVSetPortDefaults (ScrnInfoPtr pScrn, NVPortPrivPtr pPriv)
249 NVPtr pNv = NVPTR(pScrn);
251 pPriv->brightness = 0;
252 pPriv->contrast = 4096;
253 pPriv->saturation = 4096;
255 pPriv->colorKey = pNv->videoKey;
256 pPriv->autopaintColorKey = TRUE;
257 pPriv->doubleBuffer = TRUE;
258 pPriv->iturbt_709 = FALSE;
259 pPriv->currentHostBuffer = 0;
263 * NVXvDMANotifierAlloc
264 * allocates a notifier from the table of 6 we have
266 * @return a notifier instance or NULL on error
268 static struct nouveau_notifier *
269 NVXvDMANotifierAlloc(ScrnInfoPtr pScrn)
271 NVPtr pNv = NVPTR(pScrn);
274 for (i = 0; i < 6; i++) {
275 if (XvDMANotifierStatus[i] == XV_DMA_NOTIFIER_INUSE)
278 if (XvDMANotifierStatus[i] == XV_DMA_NOTIFIER_FREE) {
279 XvDMANotifierStatus[i] = XV_DMA_NOTIFIER_INUSE;
280 return XvDMANotifiers[i];
283 if (XvDMANotifierStatus[i] == XV_DMA_NOTIFIER_NOALLOC) {
284 if (nouveau_notifier_alloc(pNv->chan,
285 NvDmaXvNotifier0 + i,
286 1, &XvDMANotifiers[i]))
288 XvDMANotifierStatus[i] = XV_DMA_NOTIFIER_INUSE;
289 return XvDMANotifiers[i];
297 * NVXvDMANotifierFree
298 * frees a notifier from the table of 6 we have
303 NVXvDMANotifierFree(ScrnInfoPtr pScrn, struct nouveau_notifier *target)
306 for ( i = 0; i < 6; i ++ )
308 if ( XvDMANotifiers[i] == target )
311 XvDMANotifierStatus[i] = XV_DMA_NOTIFIER_FREE;
315 * NVAllocateVideoMemory
316 * allocates video memory for a given port
318 * @param pScrn screen which requests the memory
319 * @param mem pointer to previously allocated memory for reallocation
320 * @param size size of requested memory segment
321 * @return pointer to the allocated memory
323 static struct nouveau_bo *
324 NVAllocateVideoMemory(ScrnInfoPtr pScrn, struct nouveau_bo *mem, int size)
326 NVPtr pNv = NVPTR(pScrn);
327 struct nouveau_bo *bo = NULL;
330 if(mem->size >= size)
332 nouveau_bo_del(&mem);
335 if (nouveau_bo_new(pNv->dev, NOUVEAU_BO_VRAM | NOUVEAU_BO_PIN, 0,
339 if (nouveau_bo_map(bo, NOUVEAU_BO_RDWR)) {
349 * allocates TT memory for a given port
351 * @param pScrn screen which requests the memory
352 * @param mem pointer to previously allocated memory for reallocation
353 * @param size size of requested memory segment
354 * @return pointer to the allocated memory
356 static struct nouveau_bo *
357 NVAllocateTTMemory(ScrnInfoPtr pScrn, struct nouveau_bo *mem, int size)
359 NVPtr pNv = NVPTR(pScrn);
360 struct nouveau_bo *bo = NULL;
363 if(mem->size >= size)
365 nouveau_bo_del(&mem);
368 if (nouveau_bo_new(pNv->dev, NOUVEAU_BO_GART | NOUVEAU_BO_PIN, 0,
372 if (nouveau_bo_map(bo, NOUVEAU_BO_RDWR)) {
382 * frees memory held by a given port
384 * @param pScrn screen whose port wants to free memory
385 * @param pPriv port to free memory of
388 NVFreePortMemory(ScrnInfoPtr pScrn, NVPortPrivPtr pPriv)
390 //xf86DrvMsg(0, X_INFO, "Freeing port memory - TTmem chunks %p %p, notifiers %p %p\n", pPriv->TT_mem_chunk[0], pPriv->TT_mem_chunk[1], pPriv->DMANotifier[0], pPriv->DMANotifier[1]);
392 if(pPriv->video_mem) {
393 nouveau_bo_del(&pPriv->video_mem);
394 pPriv->video_mem = NULL;
397 if ( pPriv->TT_mem_chunk[ 0 ] && pPriv->DMANotifier [ 0 ] )
399 nouveau_notifier_wait_status(pPriv->DMANotifier[0], 0, 0, 1000);
402 if ( pPriv->TT_mem_chunk[ 1 ] && pPriv->DMANotifier [ 1 ] )
404 nouveau_notifier_wait_status(pPriv->DMANotifier[1], 0, 0, 1000);
407 if(pPriv->TT_mem_chunk[0]) {
408 nouveau_bo_del(&pPriv->TT_mem_chunk[0]);
409 pPriv->TT_mem_chunk[0] = NULL;
412 if(pPriv->TT_mem_chunk[1]) {
413 nouveau_bo_del(&pPriv->TT_mem_chunk[1]);
414 pPriv->TT_mem_chunk[1] = NULL;
417 if(pPriv->DMANotifier[0]) {
418 NVXvDMANotifierFree(pScrn, pPriv->DMANotifier[0]);
419 pPriv->DMANotifier[0] = NULL;
422 if(pPriv->DMANotifier[1]) {
423 NVXvDMANotifierFree(pScrn, pPriv->DMANotifier[1]);
424 pPriv->DMANotifier[1] = NULL;
430 * NVFreeOverlayMemory
431 * frees memory held by the overlay port
433 * @param pScrn screen whose overlay port wants to free memory
436 NVFreeOverlayMemory(ScrnInfoPtr pScrn)
438 NVPtr pNv = NVPTR(pScrn);
439 NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
440 NVFreePortMemory(pScrn, pPriv);
442 /* "power cycle" the overlay */
443 nvWriteMC(pNv, 0x200, (nvReadMC(pNv, 0x200) & 0xEFFFFFFF));
444 nvWriteMC(pNv, 0x200, (nvReadMC(pNv, 0x200) | 0x10000000));
449 * frees memory held by the blit port
451 * @param pScrn screen whose blit port wants to free memory
454 NVFreeBlitMemory(ScrnInfoPtr pScrn)
456 NVPtr pNv = NVPTR(pScrn);
457 NVPortPrivPtr pPriv = GET_BLIT_PRIVATE(pNv);
458 NVFreePortMemory(pScrn, pPriv);
462 * NVVideoTimerCallback
463 * callback function which perform cleanup tasks (stop overlay, free memory).
465 * purpose and use is unknown
468 NVVideoTimerCallback(ScrnInfoPtr pScrn, Time currentTime)
470 NVPtr pNv = NVPTR(pScrn);
471 NVPortPrivPtr pOverPriv = NULL;
472 NVPortPrivPtr pBlitPriv = NULL;
473 Bool needCallback = FALSE;
478 if (pNv->overlayAdaptor) {
479 pOverPriv = GET_OVERLAY_PRIVATE(pNv);
480 if (!pOverPriv->videoStatus)
484 if (pNv->blitAdaptor) {
485 pBlitPriv = GET_BLIT_PRIVATE(pNv);
486 if (!pBlitPriv->videoStatus)
491 if (pOverPriv->videoTime < currentTime) {
492 if (pOverPriv->videoStatus & OFF_TIMER) {
493 NVStopOverlay(pScrn);
494 pOverPriv->videoStatus = FREE_TIMER;
495 pOverPriv->videoTime = currentTime + FREE_DELAY;
498 if (pOverPriv->videoStatus & FREE_TIMER) {
499 NVFreeOverlayMemory(pScrn);
500 pOverPriv->videoStatus = 0;
508 if (pBlitPriv->videoTime < currentTime) {
509 NVFreeBlitMemory(pScrn);
510 pBlitPriv->videoStatus = 0;
516 pNv->VideoTimerCallback = needCallback ? NVVideoTimerCallback : NULL;
519 #ifndef ExaOffscreenMarkUsed
520 extern void ExaOffscreenMarkUsed(PixmapPtr);
526 NVStopOverlayVideo(ScrnInfoPtr pScrn, pointer data, Bool Exit)
528 NVPtr pNv = NVPTR(pScrn);
529 NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
531 if(pPriv->grabbedByV4L) return;
533 REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
536 if (pPriv->videoStatus & CLIENT_VIDEO_ON)
537 NVStopOverlay(pScrn);
538 NVFreeOverlayMemory(pScrn);
539 pPriv->videoStatus = 0;
541 if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
542 pPriv->videoStatus = OFF_TIMER | CLIENT_VIDEO_ON;
543 pPriv->videoTime = currentTime.milliseconds + OFF_DELAY;
544 pNv->VideoTimerCallback = NVVideoTimerCallback;
551 * used by client applications to ask the driver:
552 * how would you actually scale a video of dimensions
553 * vid_w, vid_h, if i wanted you to scale it to dimensions
555 * function stores actual scaling size in pointers p_w, p_h.
558 * @param pScrn unused
559 * @param motion unused
560 * @param vid_w width of source video
561 * @param vid_h height of source video
562 * @param drw_w desired scaled width as requested by client
563 * @param drw_h desired scaled height as requested by client
564 * @param p_w actual scaled width as the driver is capable of
565 * @param p_h actual scaled height as the driver is capable of
569 NVQueryBestSize(ScrnInfoPtr pScrn, Bool motion,
570 short vid_w, short vid_h,
571 short drw_w, short drw_h,
572 unsigned int *p_w, unsigned int *p_h,
575 if(vid_w > (drw_w << 3))
577 if(vid_h > (drw_h << 3))
586 * used to convert YV12 to YUY2 for the blitter and NV04 overlay.
587 * The U and V samples generated are linearly interpolated on the vertical
588 * axis for better quality
590 * @param src1 source buffer of luma
591 * @param src2 source buffer of chroma1
592 * @param src3 source buffer of chroma2
593 * @param dst1 destination buffer
594 * @param srcPitch pitch of src1
595 * @param srcPitch2 pitch of src2, src3
596 * @param dstPitch pitch of dst1
597 * @param h number of lines to copy
598 * @param w length of lines to copy
600 static inline void NVCopyData420(unsigned char *src1, unsigned char *src2,
601 unsigned char *src3, unsigned char *dst1,
602 int srcPitch, int srcPitch2,
608 #define su(X) (((j & 1) && j < (h-1)) ? ((unsigned)((signed int)s2[X] + (signed int)(s2 + srcPitch2)[X]) / 2) : (s2[X]))
609 #define sv(X) (((j & 1) && j < (h-1)) ? ((unsigned)((signed int)s3[X] + (signed int)(s3 + srcPitch2)[X]) / 2) : (s3[X]))
615 for (j = 0; j < h; j++) {
617 s1 = src1; s2 = src2; s3 = src3;
621 #if X_BYTE_ORDER == X_BIG_ENDIAN
622 dst[0] = (s1[0] << 24) | (s1[1] << 8) | (sv(0) << 16) | su(0);
623 dst[1] = (s1[2] << 24) | (s1[3] << 8) | (sv(1) << 16) | su(1);
624 dst[2] = (s1[4] << 24) | (s1[5] << 8) | (sv(2) << 16) | su(2);
625 dst[3] = (s1[6] << 24) | (s1[7] << 8) | (sv(3) << 16) | su(3);
627 dst[0] = s1[0] | (s1[1] << 16) | (sv(0) << 8) | (su(0) << 24);
628 dst[1] = s1[2] | (s1[3] << 16) | (sv(1) << 8) | (su(1) << 24);
629 dst[2] = s1[4] | (s1[5] << 16) | (sv(2) << 8) | (su(2) << 24);
630 dst[3] = s1[6] | (s1[7] << 16) | (sv(3) << 8) | (su(3) << 24);
632 dst += 4; s2 += 4; s3 += 4; s1 += 8;
637 #if X_BYTE_ORDER == X_BIG_ENDIAN
638 dst[0] = (s1[0] << 24) | (s1[1] << 8) | (sv(0) << 16) | su(0);
640 dst[0] = s1[0] | (s1[1] << 16) | (sv(0) << 8) | (su(0) << 24);
656 * NVCopyNV12ColorPlanes
657 * Used to convert YV12 color planes to NV12 (interleaved UV) for the overlay
659 * @param src1 source buffer of chroma1
660 * @param dst1 destination buffer
661 * @param h number of lines to copy
662 * @param w length of lines to copy
663 * @param id source pixel format (YV12 or I420)
665 static inline void NVCopyNV12ColorPlanes(unsigned char *src1, unsigned char * src2, unsigned char *dst, int dstPitch, int srcPitch2,
675 for ( j = 0; j < h; j++ )
677 unsigned char * us = src1;
678 unsigned char * vs = src2;
679 unsigned int * vuvud = (unsigned int *) dst;
680 for ( i = 0; i < l; i++ )
682 #if X_BYTE_ORDER == X_BIG_ENDIAN
683 *vuvud++ = (vs[0]<<24) | (us[0]<<16) | (vs[1]<<8) | us[1];
685 *vuvud++ = vs[0] | (us[0]<<8) | (vs[1]<<16) | (us[1]<<24);
691 unsigned short *vud = (unsigned short *) vuvud;
692 *vud = vs[0] | (us[0]<<8);
702 static int NV_set_dimensions(ScrnInfoPtr pScrn, int action_flags, INT32 * xa, INT32 * xb, INT32 * ya, INT32 * yb,
703 short * src_x, short * src_y, short * src_w, short * src_h,
704 short * drw_x, short * drw_y, short * drw_w, short * drw_h,
705 int * left, int * top, int * right, int * bottom,
707 int * npixels, int * nlines,
708 RegionPtr clipBoxes, short width, short height
711 NVPtr pNv = NVPTR(pScrn);
714 if (action_flags & USE_OVERLAY)
716 switch ( pNv->Architecture )
719 /* NV0x overlay can't scale down. at all. */
720 if ( *drw_w < *src_w )
722 if ( *drw_h < *src_h )
726 /* according to DirectFB, NV3x can't scale down by a ratio > 2 */
727 if ( *drw_w < (*src_w) >> 1 )
729 if ( *drw_h < (*src_h) >> 1 )
732 default: /*NV10, NV20*/
733 /* NV1x overlay can't scale down by a ratio > 8 */
734 if (*drw_w < (*src_w) >> 3)
735 *drw_w = *src_w >> 3;
736 if (*drw_h < (*src_h >> 3))
737 *drw_h = *src_h >> 3;
743 *xb = *src_x + *src_w;
745 *yb = *src_y + *src_h;
748 dstBox->x2 = *drw_x + *drw_w;
750 dstBox->y2 = *drw_y + *drw_h;
752 if (!xf86XVClipVideoHelper(dstBox, xa, xb, ya, yb, clipBoxes,
756 if ( action_flags & USE_OVERLAY )
758 if ( ! pNv->randr12_enable )
760 dstBox->x1 -= pScrn->frameX0;
761 dstBox->x2 -= pScrn->frameX0;
762 dstBox->y1 -= pScrn->frameY0;
763 dstBox->y2 -= pScrn->frameY0;
767 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
768 NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
769 dstBox->x1 -= xf86_config->crtc[pPriv->overlayCRTC]->x;
770 dstBox->x2 -= xf86_config->crtc[pPriv->overlayCRTC]->x;
771 dstBox->y1 -= xf86_config->crtc[pPriv->overlayCRTC]->y;
772 dstBox->y2 -= xf86_config->crtc[pPriv->overlayCRTC]->y;
778 /* Convert fixed point to integer, as xf86XVClipVideoHelper probably turns its parameter into fixed point values */
780 if (*left < 0) *left = 0;
782 if (*top < 0) *top = 0;
783 *right = (*xb) >> 16;
784 if (*right > width) *right = width;
785 *bottom = (*yb) >> 16;
786 if (*bottom > height) *bottom = height;
788 if ( action_flags & IS_YV12 )
790 *left &= ~1; //even "left", even "top", even number of pixels per line and even number of lines
791 *npixels = ((*right + 1) & ~1) - *left;
793 *nlines = ((*bottom + 1) & ~1) - *top;
795 else if ( action_flags & IS_YUY2 )
797 *left &= ~1; //even "left"
798 *npixels = ((*right + 1) & ~1) - *left; //even number of pixels per line
799 *nlines = *bottom - *top;
802 else if (action_flags & IS_RGB )
804 *npixels = *right - *left;
805 *nlines = *bottom - *top;
812 static int NV_calculate_pitches_and_mem_size(int action_flags, int * srcPitch, int * srcPitch2, int * dstPitch,
813 int * s2offset, int * s3offset,
814 int * newFBSize, int * newTTSize,
815 int * line_len, int npixels, int nlines, int width, int height)
819 if ( action_flags & IS_YV12 )
821 *srcPitch = (width + 3) & ~3; /* of luma */
822 *s2offset = *srcPitch * height;
823 *srcPitch2 = ((width >> 1) + 3) & ~3; /*of chroma*/
824 *s3offset = (*srcPitch2 * (height >> 1)) + *s2offset;
825 *dstPitch = (npixels + 63) & ~63; /*luma and chroma pitch*/
827 *newFBSize = nlines * *dstPitch + (nlines >> 1) * *dstPitch;
828 *newTTSize = nlines * *dstPitch + (nlines >> 1) * *dstPitch;
830 else if ( action_flags & IS_YUY2 )
832 *srcPitch = width << 1; /* one luma, one chroma per pixel */
833 *dstPitch = ((npixels << 1) + 63) & ~63;
834 *line_len = npixels << 1;
835 *newFBSize = nlines * *dstPitch;
836 *newTTSize = nlines * *line_len;
838 else if ( action_flags & IS_RGB )
840 *srcPitch = width << 2; /* one R, one G, one B, one X per pixel */
841 *dstPitch = ((npixels << 2) + 63) & ~63;
842 *line_len = npixels << 2;
843 *newFBSize = nlines * *dstPitch;
844 *newTTSize = nlines * *dstPitch;
848 if ( action_flags & CONVERT_TO_YUY2 )
850 *dstPitch = ((npixels << 1) + 63) & ~63;
851 *line_len = npixels << 1;
852 *newFBSize = nlines * *dstPitch;
853 *newTTSize = nlines * *line_len;
856 if ( action_flags & SWAP_UV )
857 { //I420 swaps U and V
859 *s2offset = *s3offset;
863 if ( action_flags & USE_OVERLAY ) // overlay double buffering ...
864 (*newFBSize) <<= 1; // ... means double the amount of VRAM needed
871 * NV_set_action_flags
872 * This function computes the action flags from the input image,
873 * that is, it decides what NVPutImage and its helpers must do.
874 * This eases readability by avoiding lots of switch-case statements in the core NVPutImage
876 static void NV_set_action_flags(ScrnInfoPtr pScrn, DrawablePtr pDraw, NVPortPrivPtr pPriv, int id,
877 short drw_x, short drw_y, short drw_w, short drw_h, int * action_flags)
879 #define USING_OVERLAY (*action_flags & USE_OVERLAY)
880 #define USING_TEXTURE (*action_flags & USE_TEXTURE)
881 #define USING_BLITTER ((!(*action_flags & USE_OVERLAY)) && (!(*action_flags & USE_TEXTURE)))
883 NVPtr pNv = NVPTR(pScrn);
887 /* Pixel format-related bits */
888 if ( id == FOURCC_YUY2 || id == FOURCC_UYVY )
889 *action_flags |= IS_YUY2;
891 if ( id == FOURCC_YV12 || id == FOURCC_I420 )
892 *action_flags |= IS_YV12;
894 if ( id == FOURCC_RGB ) /*How long will we support it?*/
895 *action_flags |= IS_RGB;
897 if ( id == FOURCC_I420 ) /*I420 is YV12 with swapped UV*/
898 *action_flags |= SWAP_UV;
900 /* Desired adapter */
901 if ( !pPriv -> blitter && !pPriv -> texture )
902 *action_flags |= USE_OVERLAY;
904 if ( !pPriv -> blitter && pPriv->texture )
905 *action_flags |= USE_TEXTURE;
907 /* Adapter fallbacks (when the desired one can't be used)*/
909 PixmapPtr pPix = NVGetDrawablePixmap(pDraw);
911 if (!NVExaPixmapIsOnscreen(pPix))
913 *action_flags &= ~USE_OVERLAY;
918 if ( USING_OVERLAY && pNv->randr12_enable )
919 { /* We need to check the CRTC we're on */
920 char crtc = nv_window_belongs_to_crtc(pScrn, drw_x, drw_y, drw_w, drw_h);
922 /* We're on CRTC 0, or 1, or both.. */
923 if ( ( crtc & (1 << 0)) && (crtc & (1 << 1)) )
924 { /* The overlay cannot be used on two CRTCs at a time, so we need to fallback on the blitter */
925 *action_flags &= ~USE_OVERLAY;
927 else if ( (crtc & (1 << 0) ) )
928 { /* We need to put the overlay on CRTC0 - if it's not already here */
929 if ( pPriv->overlayCRTC == 1 )
931 NVWriteCRTC(pNv, 0, NV_CRTC_FSEL, NVReadCRTC(pNv, 0, NV_CRTC_FSEL) | NV_CRTC_FSEL_OVERLAY);
932 NVWriteCRTC(pNv, 1, NV_CRTC_FSEL, NVReadCRTC(pNv, 1, NV_CRTC_FSEL) & ~NV_CRTC_FSEL_OVERLAY);
933 pPriv->overlayCRTC = 0;
936 else if ( (crtc & (1 << 1) ) )
938 if ( pPriv->overlayCRTC == 0 )
940 NVWriteCRTC(pNv, 1, NV_CRTC_FSEL, NVReadCRTC(pNv, 1, NV_CRTC_FSEL) | NV_CRTC_FSEL_OVERLAY);
941 NVWriteCRTC(pNv, 0, NV_CRTC_FSEL, NVReadCRTC(pNv, 0, NV_CRTC_FSEL) & ~NV_CRTC_FSEL_OVERLAY);
942 pPriv->overlayCRTC = 1;
947 /* At this point the adapter we're going to use is _known_. You cannot change it now. */
948 /* Card/adapter format restrictions */
951 if ( id == FOURCC_YV12 || id == FOURCC_I420 )
952 { /*The blitter does not handle YV12 natively*/
953 *action_flags |= CONVERT_TO_YUY2;
957 if ( USING_OVERLAY && (pNv->Architecture == NV_ARCH_04 ))
958 if ( * action_flags & IS_YV12 ) /*NV04-05 don't support native YV12, only YUY2 and ITU-R BT.601*/
959 *action_flags |= CONVERT_TO_YUY2;
961 if ( USING_OVERLAY && (pNv->Architecture == NV_ARCH_10 || pNv->Architecture == NV_ARCH_20 ))
962 { /* No YV12 overlay on NV10, 11, 15, 20, NFORCE */
963 switch ( pNv->Chipset & 0xfff0 )
968 case CHIPSET_NFORCE: /*XXX: unsure about nforce*/
970 *action_flags |= CONVERT_TO_YUY2; break;
981 * PutImage is "the" important function of the Xv extension.
982 * a client (e.g. video player) calls this function for every
983 * image (of the video) to be displayed. this function then
984 * scales and displays the image.
986 * @param pScrn screen which hold the port where the image is put
987 * @param src_x source point in the source image to start displaying from
988 * @param src_y see above
989 * @param src_w width of the source image to display
990 * @param src_h see above
991 * @param drw_x screen point to display to
993 * @param drw_w width of the screen drawable
995 * @param id pixel format of image
996 * @param buf pointer to buffer containing the source image
997 * @param width total width of the source image we are passed
1000 * @param clipBoxes ??
1001 * @param data pointer to port
1002 * @param pDraw drawable pointer
1005 NVPutImage(ScrnInfoPtr pScrn, short src_x, short src_y,
1006 short drw_x, short drw_y,
1007 short src_w, short src_h,
1008 short drw_w, short drw_h,
1011 short width, short height,
1012 Bool Sync, /*FIXME: need to honor the Sync*/
1013 RegionPtr clipBoxes,
1018 NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
1019 NVPtr pNv = NVPTR(pScrn);
1020 INT32 xa = 0, xb = 0, ya = 0, yb = 0; //source box
1021 int newFBSize = 0, newTTSize = 0; //size to allocate in VRAM and in GART respectively
1022 int offset = 0, s2offset = 0, s3offset = 0; //card VRAM offset, source offsets for U and V planes
1023 int srcPitch = 0, srcPitch2 = 0, dstPitch = 0; //source pitch, source pitch of U and V planes in case of YV12, VRAM destination pitch
1024 int top = 0, left = 0, right = 0, bottom = 0, npixels = 0, nlines = 0; //position of the given source data (using src_*), number of pixels and lines we are interested in
1028 int line_len = 0; //length of a line, like npixels, but in bytes
1029 struct nouveau_bo *destination_buffer = NULL;
1030 unsigned char * video_mem_destination = NULL;
1031 int action_flags; //what shall we do?
1034 if (pPriv->grabbedByV4L)
1038 NV_set_action_flags(pScrn, pDraw, pPriv, id, drw_x, drw_y, drw_w, drw_h, &action_flags);
1040 if ( NV_set_dimensions(pScrn, action_flags, &xa, &xb, &ya, &yb,
1041 &src_x, &src_y, &src_w, &src_h,
1042 &drw_x, &drw_y, &drw_w, &drw_h,
1043 &left, &top, &right, &bottom, &dstBox,
1045 clipBoxes, width, height ) )
1051 if ( NV_calculate_pitches_and_mem_size(action_flags, &srcPitch, &srcPitch2, &dstPitch,
1052 &s2offset, &s3offset,
1053 & newFBSize, &newTTSize ,&line_len ,
1054 npixels, nlines, width, height) )
1056 return BadImplementation;
1059 /* There are some cases (tvtime with overscan for example) where the input image is larger (width/height) than
1060 the source rectangle for the overlay (src_w, src_h). In those cases, we try to do something optimal by uploading only
1061 the necessary data. */
1062 if ( action_flags & IS_YUY2 || action_flags & IS_RGB )
1064 buf += (top * srcPitch) + left;
1067 if ( action_flags & IS_YV12 )
1069 tmp = ((top >> 1) * srcPitch2) + (left >> 1);
1074 pPriv->video_mem = NVAllocateVideoMemory(pScrn, pPriv->video_mem,
1076 if (!pPriv->video_mem)
1079 offset = pPriv->video_mem->offset;
1081 /*The overlay supports hardware double buffering. We handle this here*/
1082 if (pPriv->doubleBuffer) {
1083 int mask = 1 << (pPriv->currentBuffer << 2);
1084 /* overwrite the newest buffer if there's not one free */
1085 if (nvReadVIDEO(pNv, NV_PVIDEO_BUFFER) & mask) {
1086 if (!pPriv->currentBuffer)
1087 offset += newFBSize >> 1;
1091 if (pPriv->currentBuffer)
1092 offset += newFBSize >> 1;
1095 /*Now we take a decision regarding the way we send the data to the card.
1096 Either we use double buffering of "private" TT memory
1097 Either we rely on X's GARTScratch
1098 Either we fallback on CPU copy
1101 /* Try to allocate host-side double buffers, unless we have already failed*/
1102 /* We take only nlines * line_len bytes - that is, only the pixel data we are interested in - because the stuff in the GART is
1103 written contiguously */
1104 if ( pPriv -> currentHostBuffer != NO_PRIV_HOST_BUFFER_AVAILABLE )
1106 pPriv->TT_mem_chunk[0] = NVAllocateTTMemory(pScrn, pPriv->TT_mem_chunk[0],
1108 if ( pPriv->TT_mem_chunk[0] )
1110 pPriv->TT_mem_chunk[1] = NVAllocateTTMemory(pScrn, pPriv->TT_mem_chunk[1],
1113 if ( ! pPriv->TT_mem_chunk[1] )
1115 nouveau_bo_del(&pPriv->TT_mem_chunk[0]);
1116 pPriv->TT_mem_chunk[0] = NULL;
1117 pPriv -> currentHostBuffer = NO_PRIV_HOST_BUFFER_AVAILABLE;
1118 //xf86DrvMsg(0, X_INFO, "Alloc 1 failed\n");
1123 pPriv -> currentHostBuffer = NO_PRIV_HOST_BUFFER_AVAILABLE;
1124 //xf86DrvMsg(0, X_INFO, "Alloc 0 failed\n");
1128 if ( pPriv->currentHostBuffer != NO_PRIV_HOST_BUFFER_AVAILABLE )
1129 { //if we have a private buffer
1130 destination_buffer = pPriv->TT_mem_chunk[pPriv->currentHostBuffer];
1131 //xf86DrvMsg(0, X_INFO, "Using private mem chunk #%d\n", pPriv->currentHostBuffer);
1133 /* We know where we are going to write, but we are not sure yet whether we can do it directly, because
1134 the card could be working on the buffer for the last-but-one frame. So we check if we have a notifier ready or not.
1135 If we do, then we must wait for it before overwriting the buffer.
1136 Else we need one, so we call the Xv notifier allocator.*/
1137 if ( pPriv->DMANotifier [ pPriv->currentHostBuffer ] )
1139 //xf86DrvMsg(0, X_INFO, "Waiting for notifier %p (%d)\n", pPriv->DMANotifier[pPriv->currentHostBuffer], pPriv->currentHostBuffer);
1140 if (nouveau_notifier_wait_status(pPriv->DMANotifier[pPriv->currentHostBuffer], 0, 0, 0))
1145 //xf86DrvMsg(0, X_INFO, "Allocating notifier...\n");
1146 pPriv->DMANotifier [ pPriv->currentHostBuffer ] = NVXvDMANotifierAlloc(pScrn);
1147 if (! pPriv->DMANotifier [ pPriv->currentHostBuffer ] )
1148 { /* In case we are out of notifiers (then our guy is watching 3 movies at a time!!), we fallback on global GART, and free the private buffers.
1149 I know that's a lot of code but I believe it's necessary to properly handle all the cases*/
1150 xf86DrvMsg(0, X_ERROR, "Ran out of Xv notifiers!\n");
1151 nouveau_bo_del(&pPriv->TT_mem_chunk[0]);
1152 pPriv->TT_mem_chunk[0] = NULL;
1153 nouveau_bo_del(&pPriv->TT_mem_chunk[1]);
1154 pPriv->TT_mem_chunk[1] = NULL;
1155 pPriv -> currentHostBuffer = NO_PRIV_HOST_BUFFER_AVAILABLE;
1157 //xf86DrvMsg(0, X_INFO, "Got notifier %p\n", pPriv->DMANotifier [ pPriv->currentHostBuffer ]);
1161 if ( pPriv -> currentHostBuffer == NO_PRIV_HOST_BUFFER_AVAILABLE )
1162 { //otherwise we fall back on DDX's GARTScratch
1163 destination_buffer = pNv->GART;
1164 //xf86DrvMsg(0, X_INFO, "Using global GART memory chunk\n");
1167 if ( !destination_buffer) //if we have no GART at all
1170 if(newTTSize <= destination_buffer->size)
1172 unsigned char *dst = destination_buffer->map;
1175 /* Upload to GART */
1176 if ( action_flags & IS_YV12)
1178 if ( action_flags & CONVERT_TO_YUY2 )
1180 NVCopyData420(buf + (top * srcPitch) + left,
1181 buf + s2offset, buf + s3offset,
1182 dst, srcPitch, srcPitch2,
1183 line_len, nlines, npixels);
1187 unsigned char * tbuf = buf + top * srcPitch + left;
1188 unsigned char * tdst = dst;
1189 //xf86DrvMsg(0, X_INFO, "srcPitch %d dstPitch %d srcPitch2 %d nlines %d npixels %d left %d top %d s2offset %d\n", srcPitch, dstPitch, srcPitch2, nlines, npixels, left, top, s2offset);
1191 for ( i=0; i < nlines; i++)
1193 memcpy(tdst, tbuf, line_len);
1197 dst += line_len * nlines;
1198 NVCopyNV12ColorPlanes(buf + s2offset, buf + s3offset, dst, line_len, srcPitch2, nlines, line_len);
1203 for ( i=0; i < nlines; i++)
1205 memcpy(dst, buf, line_len);
1212 BEGIN_RING(NvMemFormat,
1213 NV04_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2);
1214 OUT_RING (pNv->chan->gart->handle);
1215 OUT_RING (pNv->chan->vram->handle);
1218 if (action_flags & IS_YV12 && ! (action_flags & CONVERT_TO_YUY2) )
1219 { /*we start the color plane transfer separately*/
1220 BEGIN_RING(NvMemFormat,
1221 NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
1222 OUT_RING ((uint32_t)destination_buffer->offset + line_len * nlines);
1223 OUT_RING ((uint32_t)offset + dstPitch * nlines);
1224 OUT_RING (line_len);
1225 OUT_RING (dstPitch);
1226 OUT_RING (line_len);
1227 OUT_RING ((nlines >> 1));
1228 OUT_RING ((1<<8)|1);
1233 BEGIN_RING(NvMemFormat,
1234 NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
1235 OUT_RING ((uint32_t)destination_buffer->offset);
1236 OUT_RING ((uint32_t)offset);
1237 OUT_RING (line_len);
1238 OUT_RING (dstPitch);
1239 OUT_RING (line_len);
1241 OUT_RING ((1<<8)|1);
1244 if ( destination_buffer == pNv->GART )
1246 nouveau_notifier_reset(pNv->notify0, 0);
1249 nouveau_notifier_reset(pPriv->DMANotifier[pPriv->currentHostBuffer], 0);
1250 BEGIN_RING(NvMemFormat,
1251 NV04_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
1252 OUT_RING (pPriv->DMANotifier[pPriv->currentHostBuffer]->handle);
1256 BEGIN_RING(NvMemFormat, NV04_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
1259 BEGIN_RING(NvMemFormat, 0x100, 1);
1262 //Put back NvDmaNotifier0 for EXA
1263 BEGIN_RING(NvMemFormat,
1264 NV04_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
1265 OUT_RING (pNv->notify0->handle);
1269 if ( destination_buffer == pNv->GART )
1270 if (nouveau_notifier_wait_status(pNv->notify0, 0, 0, 0))
1273 else { //GART is too small, we fallback on CPU copy
1275 video_mem_destination = pPriv->video_mem->map + (offset - (uint32_t)pPriv->video_mem->offset);
1277 if ( action_flags & IS_YV12 )
1279 if ( action_flags & CONVERT_TO_YUY2 )
1281 NVCopyData420(buf + (top * srcPitch) + left,
1282 buf + s2offset, buf + s3offset,
1283 video_mem_destination, srcPitch, srcPitch2,
1284 dstPitch, nlines, npixels);
1287 unsigned char * tbuf = buf + left + top * srcPitch;
1288 for ( i=0; i < nlines; i++)
1290 int dwords = npixels << 1;
1291 while (dwords & ~0x03)
1293 *video_mem_destination = *tbuf;
1294 *(video_mem_destination + 1) = *(tbuf + 1);
1295 *(video_mem_destination + 2) = *(tbuf + 2);
1296 *(video_mem_destination + 3) = *(tbuf + 3);
1297 video_mem_destination += 4;
1304 *(video_mem_destination + 2) = *(tbuf + 2);
1306 *(video_mem_destination + 1) = *(tbuf + 1);
1308 *video_mem_destination = *tbuf;
1311 video_mem_destination += dstPitch - (npixels << 1);
1312 tbuf += srcPitch - (npixels << 1);
1315 NVCopyNV12ColorPlanes(buf + s2offset, buf + s3offset, video_mem_destination, dstPitch, srcPitch2, nlines, line_len);
1320 for ( i=0; i < nlines; i++)
1322 int dwords = npixels << 1;
1323 while (dwords & ~0x03)
1325 *video_mem_destination = *buf;
1326 *(video_mem_destination + 1) = *(buf + 1);
1327 *(video_mem_destination + 2) = *(buf + 2);
1328 *(video_mem_destination + 3) = *(buf + 3);
1329 video_mem_destination += 4;
1336 *(video_mem_destination + 2) = *(buf + 2);
1338 *(video_mem_destination + 1) = *(buf + 1);
1340 *video_mem_destination = *buf;
1343 video_mem_destination += dstPitch - (npixels << 1);
1344 buf += srcPitch - (npixels << 1);
1352 if ( pPriv->currentHostBuffer != NO_PRIV_HOST_BUFFER_AVAILABLE )
1353 pPriv->currentHostBuffer ^= 1;
1355 if ( action_flags & USE_OVERLAY )
1357 if ( pNv->Architecture == NV_ARCH_04 )
1358 NV04PutOverlayImage(pScrn, offset, id,
1362 src_w, src_h, drw_w, drw_h,
1365 NV10PutOverlayImage(pScrn, offset, ((action_flags & IS_YUY2) || (action_flags & CONVERT_TO_YUY2)) ? 0 : offset + nlines * dstPitch, id,
1369 src_w, src_h, drw_w, drw_h,
1371 pPriv->currentBuffer ^= 1;
1376 if (action_flags & USE_TEXTURE) { /* Texture adapter */
1377 int rval = BadImplementation;
1378 if (pNv->Architecture == NV_ARCH_30)
1379 rval = NV30PutTextureImage(pScrn, offset, offset + nlines * dstPitch, id,
1383 src_w, src_h, drw_w, drw_h,
1386 else if (pNv->Architecture == NV_ARCH_40)
1387 rval = NV40PutTextureImage(pScrn, offset, offset + nlines * dstPitch, id,
1391 src_w, src_h, drw_w, drw_h,
1394 if (rval != Success)
1396 } else { /* Blit adapter */
1397 NVPutBlitImage(pScrn, offset, id,
1401 src_w, src_h, drw_w, drw_h,
1410 * QueryImageAttributes
1413 * - size (memory required to store image),
1417 * depending on colorspace (id) and dimensions (w,h) of image
1421 * may be adjusted as needed
1423 * @param pScrn unused
1424 * @param id colorspace of image
1425 * @param w pointer to width of image
1426 * @param h pointer to height of image
1427 * @param pitches pitches[i] = length of a scanline in plane[i]
1428 * @param offsets offsets[i] = offset of plane i from the beginning of the image
1429 * @return size of the memory required for the XvImage queried
1432 NVQueryImageAttributes(ScrnInfoPtr pScrn, int id,
1433 unsigned short *w, unsigned short *h,
1434 int *pitches, int *offsets)
1438 if (*w > IMAGE_MAX_W)
1440 if (*h > IMAGE_MAX_H)
1443 *w = (*w + 1) & ~1; // width rounded up to an even number
1450 *h = (*h + 1) & ~1; // height rounded up to an even number
1451 size = (*w + 3) & ~3; // width rounded up to a multiple of 4
1453 pitches[0] = size; // width rounded up to a multiple of 4
1456 offsets[1] = size; // number of pixels in "rounded up" image
1457 tmp = ((*w >> 1) + 3) & ~3; // width/2 rounded up to a multiple of 4
1459 pitches[1] = pitches[2] = tmp; // width/2 rounded up to a multiple of 4
1460 tmp *= (*h >> 1); // 1/4*number of pixels in "rounded up" image
1461 size += tmp; // 5/4*number of pixels in "rounded up" image
1463 offsets[2] = size; // 5/4*number of pixels in "rounded up" image
1464 size += tmp; // = 3/2*number of pixels in "rounded up" image
1468 size = *w << 1; // 2*width
1470 pitches[0] = size; // 2*width
1471 size *= *h; // 2*width*height
1474 size = *w << 2; // 4*width (32 bit per pixel)
1476 pitches[0] = size; // 4*width
1477 size *= *h; // 4*width*height
1487 /***** Exported offscreen surface stuff ****/
1491 NVAllocSurface(ScrnInfoPtr pScrn, int id,
1492 unsigned short w, unsigned short h,
1493 XF86SurfacePtr surface)
1495 NVPtr pNv = NVPTR(pScrn);
1496 NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
1499 bpp = pScrn->bitsPerPixel >> 3;
1501 if (pPriv->grabbedByV4L)
1504 if ((w > IMAGE_MAX_W) || (h > IMAGE_MAX_H))
1508 pPriv->pitch = ((w << 1) + 63) & ~63;
1509 size = h * pPriv->pitch / bpp;
1511 pPriv->video_mem = NVAllocateVideoMemory(pScrn,
1514 if (!pPriv->video_mem)
1520 surface->height = h;
1521 surface->pScrn = pScrn;
1522 surface->pitches = &pPriv->pitch;
1523 surface->offsets = &pPriv->offset;
1524 surface->devPrivate.ptr = (pointer)pPriv;
1527 /* grab the video */
1528 NVStopOverlay(pScrn);
1529 pPriv->videoStatus = 0;
1530 REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
1531 pPriv->grabbedByV4L = TRUE;
1537 NVStopSurface(XF86SurfacePtr surface)
1539 NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
1541 if (pPriv->grabbedByV4L && pPriv->videoStatus) {
1542 NV10StopOverlay(surface->pScrn);
1543 pPriv->videoStatus = 0;
1550 NVFreeSurface(XF86SurfacePtr surface)
1552 NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
1554 if (pPriv->grabbedByV4L) {
1555 NVStopSurface(surface);
1556 NVFreeOverlayMemory(surface->pScrn);
1557 pPriv->grabbedByV4L = FALSE;
1564 NVGetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 *value)
1566 NVPtr pNv = NVPTR(pScrn);
1567 NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
1569 return NV10GetOverlayPortAttribute(pScrn, attribute,
1570 value, (pointer)pPriv);
1574 NVSetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value)
1576 NVPtr pNv = NVPTR(pScrn);
1577 NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
1579 return NV10SetOverlayPortAttribute(pScrn, attribute,
1580 value, (pointer)pPriv);
1584 NVDisplaySurface(XF86SurfacePtr surface,
1585 short src_x, short src_y,
1586 short drw_x, short drw_y,
1587 short src_w, short src_h,
1588 short drw_w, short drw_h,
1589 RegionPtr clipBoxes)
1591 ScrnInfoPtr pScrn = surface->pScrn;
1592 NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
1593 INT32 xa, xb, ya, yb;
1596 if (!pPriv->grabbedByV4L)
1599 if (src_w > (drw_w << 3))
1601 if (src_h > (drw_h << 3))
1611 dstBox.x2 = drw_x + drw_w;
1613 dstBox.y2 = drw_y + drw_h;
1615 if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, clipBoxes,
1616 surface->width, surface->height))
1619 dstBox.x1 -= pScrn->frameX0;
1620 dstBox.x2 -= pScrn->frameX0;
1621 dstBox.y1 -= pScrn->frameY0;
1622 dstBox.y2 -= pScrn->frameY0;
1624 pPriv->currentBuffer = 0;
1626 NV10PutOverlayImage(pScrn, surface->offsets[0], 0, surface->id,
1627 surface->pitches[0], &dstBox, xa, ya, xb, yb,
1628 surface->width, surface->height, src_w, src_h,
1629 drw_w, drw_h, clipBoxes);
1636 * this function does all the work setting up a blit port
1640 static XF86VideoAdaptorPtr
1641 NVSetupBlitVideo (ScreenPtr pScreen)
1643 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1644 NVPtr pNv = NVPTR(pScrn);
1645 XF86VideoAdaptorPtr adapt;
1646 NVPortPrivPtr pPriv;
1649 if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
1650 sizeof(NVPortPrivRec) +
1651 (sizeof(DevUnion) * NUM_BLIT_PORTS)))) {
1655 adapt->type = XvWindowMask | XvInputMask | XvImageMask;
1657 adapt->name = "NV Video Blitter";
1658 adapt->nEncodings = 1;
1659 adapt->pEncodings = &DummyEncoding;
1660 adapt->nFormats = NUM_FORMATS_ALL;
1661 adapt->pFormats = NVFormats;
1662 adapt->nPorts = NUM_BLIT_PORTS;
1663 adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
1665 pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[NUM_BLIT_PORTS]);
1666 for(i = 0; i < NUM_BLIT_PORTS; i++)
1667 adapt->pPortPrivates[i].ptr = (pointer)(pPriv);
1669 if(pNv->WaitVSyncPossible) {
1670 adapt->pAttributes = NVBlitAttributes;
1671 adapt->nAttributes = NUM_BLIT_ATTRIBUTES;
1673 adapt->pAttributes = NULL;
1674 adapt->nAttributes = 0;
1677 adapt->pImages = NVImages;
1678 adapt->nImages = NUM_IMAGES_ALL;
1679 adapt->PutVideo = NULL;
1680 adapt->PutStill = NULL;
1681 adapt->GetVideo = NULL;
1682 adapt->GetStill = NULL;
1683 adapt->StopVideo = NVStopBlitVideo;
1684 adapt->SetPortAttribute = NVSetBlitPortAttribute;
1685 adapt->GetPortAttribute = NVGetBlitPortAttribute;
1686 adapt->QueryBestSize = NVQueryBestSize;
1687 adapt->PutImage = NVPutImage;
1688 adapt->QueryImageAttributes = NVQueryImageAttributes;
1690 pPriv->videoStatus = 0;
1691 pPriv->grabbedByV4L = FALSE;
1692 pPriv->blitter = TRUE;
1693 pPriv->texture = FALSE;
1694 pPriv->bicubic = FALSE;
1695 pPriv->doubleBuffer = FALSE;
1696 pPriv->SyncToVBlank = pNv->WaitVSyncPossible;
1698 pNv->blitAdaptor = adapt;
1699 xvSyncToVBlank = MAKE_ATOM("XV_SYNC_TO_VBLANK");
1705 * NVSetupOverlayVideo
1706 * this function does all the work setting up an overlay port
1708 * @return overlay port
1710 static XF86VideoAdaptorPtr
1711 NVSetupOverlayVideoAdapter(ScreenPtr pScreen)
1713 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1714 NVPtr pNv = NVPTR(pScrn);
1715 XF86VideoAdaptorPtr adapt;
1716 NVPortPrivPtr pPriv;
1718 if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
1719 sizeof(NVPortPrivRec) +
1720 sizeof(DevUnion)))) {
1724 adapt->type = XvWindowMask | XvInputMask | XvImageMask;
1725 adapt->flags = VIDEO_OVERLAID_IMAGES|VIDEO_CLIP_TO_VIEWPORT;
1726 adapt->name = "NV Video Overlay";
1727 adapt->nEncodings = 1;
1728 adapt->pEncodings = &DummyEncoding;
1729 adapt->nFormats = NUM_FORMATS_ALL;
1730 adapt->pFormats = NVFormats;
1732 adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
1734 pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[1]);
1735 adapt->pPortPrivates[0].ptr = (pointer)(pPriv);
1737 adapt->pAttributes = (pNv->Architecture != NV_ARCH_04) ? NV10OverlayAttributes : NV04OverlayAttributes;
1738 adapt->nAttributes = (pNv->Architecture != NV_ARCH_04) ? NUM_NV10_OVERLAY_ATTRIBUTES : NUM_NV04_OVERLAY_ATTRIBUTES;
1739 adapt->pImages = NVImages;
1740 adapt->nImages = NUM_IMAGES_YUV;
1741 adapt->PutVideo = NULL;
1742 adapt->PutStill = NULL;
1743 adapt->GetVideo = NULL;
1744 adapt->GetStill = NULL;
1745 adapt->StopVideo = NVStopOverlayVideo;
1746 adapt->SetPortAttribute = (pNv->Architecture != NV_ARCH_04) ? NV10SetOverlayPortAttribute : NV04SetOverlayPortAttribute;
1747 adapt->GetPortAttribute = (pNv->Architecture != NV_ARCH_04) ? NV10GetOverlayPortAttribute : NV04GetOverlayPortAttribute;
1748 adapt->QueryBestSize = NVQueryBestSize;
1749 adapt->PutImage = NVPutImage;
1750 adapt->QueryImageAttributes = NVQueryImageAttributes;
1752 pPriv->videoStatus = 0;
1753 pPriv->currentBuffer = 0;
1754 pPriv->grabbedByV4L = FALSE;
1755 pPriv->blitter = FALSE;
1756 pPriv->texture = FALSE;
1757 pPriv->bicubic = FALSE;
1758 if ( pNv->Architecture == NV_ARCH_04 )
1759 pPriv->doubleBuffer = 0;
1761 NVSetPortDefaults (pScrn, pPriv);
1763 /* gotta uninit this someplace */
1764 REGION_NULL(pScreen, &pPriv->clip);
1766 pNv->overlayAdaptor = adapt;
1768 xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
1769 xvColorKey = MAKE_ATOM("XV_COLORKEY");
1770 xvAutopaintColorKey = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
1771 xvSetDefaults = MAKE_ATOM("XV_SET_DEFAULTS");
1773 if ( pNv->Architecture != NV_ARCH_04 )
1775 xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER");
1776 xvContrast = MAKE_ATOM("XV_CONTRAST");
1777 xvSaturation = MAKE_ATOM("XV_SATURATION");
1778 xvHue = MAKE_ATOM("XV_HUE");
1779 xvITURBT709 = MAKE_ATOM("XV_ITURBT_709");
1780 xvOnCRTCNb = MAKE_ATOM("XV_ON_CRTC_NB");
1781 NV10WriteOverlayParameters(pScrn);
1788 XF86OffscreenImageRec NVOffscreenImages[2] = {
1791 VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
1796 NVGetSurfaceAttribute,
1797 NVSetSurfaceAttribute,
1798 IMAGE_MAX_W, IMAGE_MAX_H,
1799 NUM_NV10_OVERLAY_ATTRIBUTES - 1,
1800 &NV10OverlayAttributes[1]
1804 VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
1809 NVGetSurfaceAttribute,
1810 NVSetSurfaceAttribute,
1811 IMAGE_MAX_W, IMAGE_MAX_H,
1812 NUM_NV10_OVERLAY_ATTRIBUTES - 1,
1813 &NV10OverlayAttributes[1]
1818 NVInitOffscreenImages (ScreenPtr pScreen)
1820 xf86XVRegisterOffscreenImages(pScreen, NVOffscreenImages, 2);
1824 * NVChipsetHasOverlay
1826 * newer chips don't support overlay anymore.
1827 * overlay feature is emulated via textures.
1830 * @return true, if chipset supports overlay
1833 NVChipsetHasOverlay(NVPtr pNv)
1835 switch (pNv->Architecture) {
1836 case NV_ARCH_04: /*NV04 has a different overlay than NV10+*/
1842 if ((pNv->Chipset & 0xfff0) == CHIPSET_NV40)
1853 * NVSetupOverlayVideo
1854 * check if chipset supports Overla
1855 * if so, setup overlay port
1857 * @return overlay port
1858 * @see NVChipsetHasOverlay(NVPtr pNv)
1859 * @see NV10SetupOverlayVideo(ScreenPtr pScreen)
1860 * @see NVInitOffscreenImages(ScreenPtr pScreen)
1862 static XF86VideoAdaptorPtr
1863 NVSetupOverlayVideo(ScreenPtr pScreen)
1865 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1866 XF86VideoAdaptorPtr overlayAdaptor = NULL;
1867 NVPtr pNv = NVPTR(pScrn);
1869 if (!NVChipsetHasOverlay(pNv))
1872 overlayAdaptor = NVSetupOverlayVideoAdapter(pScreen);
1873 if (overlayAdaptor && pNv->Architecture != NV_ARCH_04 )
1874 NVInitOffscreenImages(pScreen); //I am not sure what this call does.
1877 if (!noCompositeExtension) {
1878 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1879 "Xv: Composite is enabled, enabling overlay with smart blitter fallback\n");
1880 overlayAdaptor -> name = "NV Video Overlay with Composite";
1884 if (pNv->randr12_enable) {
1885 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1886 "Xv: Randr12 is enabled, using overlay with smart blitter fallback and automatic CRTC switching\n");
1890 return overlayAdaptor;
1894 * NV30 texture adapter.
1897 #define NUM_FORMAT_TEXTURED 2
1899 static XF86ImageRec NV30TexturedImages[NUM_FORMAT_TEXTURED] =
1906 * NV30SetupTexturedVideo
1907 * this function does all the work setting up textured video port
1909 * @return texture port
1911 static XF86VideoAdaptorPtr
1912 NV30SetupTexturedVideo (ScreenPtr pScreen, Bool bicubic)
1914 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1915 NVPtr pNv = NVPTR(pScrn);
1916 XF86VideoAdaptorPtr adapt;
1917 NVPortPrivPtr pPriv;
1920 if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
1921 sizeof(NVPortPrivRec) +
1922 (sizeof(DevUnion) * NUM_TEXTURE_PORTS)))) {
1926 adapt->type = XvWindowMask | XvInputMask | XvImageMask;
1929 adapt->name = "NV30 high quality adapter";
1931 adapt->name = "NV30 texture adapter";
1932 adapt->nEncodings = 1;
1933 adapt->pEncodings = &DummyEncodingTex;
1934 adapt->nFormats = NUM_FORMATS_ALL;
1935 adapt->pFormats = NVFormats;
1936 adapt->nPorts = NUM_TEXTURE_PORTS;
1937 adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
1939 pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[NUM_TEXTURE_PORTS]);
1940 for(i = 0; i < NUM_TEXTURE_PORTS; i++)
1941 adapt->pPortPrivates[i].ptr = (pointer)(pPriv);
1943 if(pNv->WaitVSyncPossible) {
1944 adapt->pAttributes = NVTexturedAttributes;
1945 adapt->nAttributes = NUM_TEXTURED_ATTRIBUTES;
1947 adapt->pAttributes = NULL;
1948 adapt->nAttributes = 0;
1951 adapt->pImages = NV30TexturedImages;
1952 adapt->nImages = NUM_FORMAT_TEXTURED;
1953 adapt->PutVideo = NULL;
1954 adapt->PutStill = NULL;
1955 adapt->GetVideo = NULL;
1956 adapt->GetStill = NULL;
1957 adapt->StopVideo = NV30StopTexturedVideo;
1958 adapt->SetPortAttribute = NV30SetTexturePortAttribute;
1959 adapt->GetPortAttribute = NV30GetTexturePortAttribute;
1960 adapt->QueryBestSize = NVQueryBestSize;
1961 adapt->PutImage = NVPutImage;
1962 adapt->QueryImageAttributes = NVQueryImageAttributes;
1964 pPriv->videoStatus = 0;
1965 pPriv->grabbedByV4L = FALSE;
1966 pPriv->blitter = FALSE;
1967 pPriv->texture = TRUE;
1968 pPriv->bicubic = bicubic;
1969 pPriv->doubleBuffer = FALSE;
1970 pPriv->SyncToVBlank = pNv->WaitVSyncPossible;
1973 pNv->textureAdaptor[1] = adapt;
1975 pNv->textureAdaptor[0] = adapt;
1981 * NV40 texture adapter.
1984 #define NUM_FORMAT_TEXTURED 2
1986 static XF86ImageRec NV40TexturedImages[NUM_FORMAT_TEXTURED] =
1993 * NV40SetupTexturedVideo
1994 * this function does all the work setting up textured video port
1996 * @return texture port
1998 static XF86VideoAdaptorPtr
1999 NV40SetupTexturedVideo (ScreenPtr pScreen, Bool bicubic)
2001 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
2002 NVPtr pNv = NVPTR(pScrn);
2003 XF86VideoAdaptorPtr adapt;
2004 NVPortPrivPtr pPriv;
2007 if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
2008 sizeof(NVPortPrivRec) +
2009 (sizeof(DevUnion) * NUM_TEXTURE_PORTS)))) {
2013 adapt->type = XvWindowMask | XvInputMask | XvImageMask;
2016 adapt->name = "NV40 high quality adapter";
2018 adapt->name = "NV40 texture adapter";
2019 adapt->nEncodings = 1;
2020 adapt->pEncodings = &DummyEncodingTex;
2021 adapt->nFormats = NUM_FORMATS_ALL;
2022 adapt->pFormats = NVFormats;
2023 adapt->nPorts = NUM_TEXTURE_PORTS;
2024 adapt->pPortPrivates = (DevUnion*)(&adapt[1]);
2026 pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[NUM_TEXTURE_PORTS]);
2027 for(i = 0; i < NUM_TEXTURE_PORTS; i++)
2028 adapt->pPortPrivates[i].ptr = (pointer)(pPriv);
2030 if(pNv->WaitVSyncPossible) {
2031 adapt->pAttributes = NVTexturedAttributes;
2032 adapt->nAttributes = NUM_TEXTURED_ATTRIBUTES;
2034 adapt->pAttributes = NULL;
2035 adapt->nAttributes = 0;
2038 adapt->pImages = NV40TexturedImages;
2039 adapt->nImages = NUM_FORMAT_TEXTURED;
2040 adapt->PutVideo = NULL;
2041 adapt->PutStill = NULL;
2042 adapt->GetVideo = NULL;
2043 adapt->GetStill = NULL;
2044 adapt->StopVideo = NV40StopTexturedVideo;
2045 adapt->SetPortAttribute = NV40SetTexturePortAttribute;
2046 adapt->GetPortAttribute = NV40GetTexturePortAttribute;
2047 adapt->QueryBestSize = NVQueryBestSize;
2048 adapt->PutImage = NVPutImage;
2049 adapt->QueryImageAttributes = NVQueryImageAttributes;
2051 pPriv->videoStatus = 0;
2052 pPriv->grabbedByV4L = FALSE;
2053 pPriv->blitter = FALSE;
2054 pPriv->texture = TRUE;
2055 pPriv->bicubic = bicubic;
2056 pPriv->doubleBuffer = FALSE;
2057 pPriv->SyncToVBlank = pNv->WaitVSyncPossible;
2060 pNv->textureAdaptor[1] = adapt;
2062 pNv->textureAdaptor[0] = adapt;
2069 * tries to initialize the various supported adapters
2070 * and add them to the list of ports on screen "pScreen".
2073 * @see NVSetupOverlayVideo(ScreenPtr pScreen)
2074 * @see NVSetupBlitVideo(ScreenPtr pScreen)
2076 void NVInitVideo (ScreenPtr pScreen)
2078 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
2079 NVPtr pNv = NVPTR(pScrn);
2080 XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
2081 XF86VideoAdaptorPtr overlayAdaptor = NULL;
2082 XF86VideoAdaptorPtr blitAdaptor = NULL;
2083 XF86VideoAdaptorPtr textureAdaptor[2] = {NULL, NULL};
2087 * Driving the blitter requires the DMA FIFO. Using the FIFO
2088 * without accel causes DMA errors. While the overlay might
2089 * might work without accel, we also disable it for now when
2090 * acceleration is disabled:
2092 if (pScrn->bitsPerPixel != 8 && pNv->Architecture < NV_ARCH_50 && !pNv->NoAccel) {
2093 overlayAdaptor = NVSetupOverlayVideo(pScreen);
2094 blitAdaptor = NVSetupBlitVideo(pScreen);
2095 if (pNv->Architecture == NV_ARCH_30) {
2096 textureAdaptor[0] = NV30SetupTexturedVideo(pScreen, FALSE);
2097 textureAdaptor[1] = NV30SetupTexturedVideo(pScreen, TRUE);
2099 if (pNv->Architecture == NV_ARCH_40) {
2100 textureAdaptor[0] = NV40SetupTexturedVideo(pScreen, FALSE);
2101 textureAdaptor[1] = NV40SetupTexturedVideo(pScreen, TRUE);
2105 num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
2106 if(blitAdaptor || overlayAdaptor) {
2107 int size = num_adaptors;
2109 if(overlayAdaptor) size++;
2110 if(blitAdaptor) size++;
2111 if(textureAdaptor[0]) size++;
2112 if(textureAdaptor[1]) size++;
2114 newAdaptors = xalloc(size * sizeof(XF86VideoAdaptorPtr *));
2117 memcpy(newAdaptors, adaptors, num_adaptors *
2118 sizeof(XF86VideoAdaptorPtr));
2121 if(overlayAdaptor) {
2122 newAdaptors[num_adaptors] = overlayAdaptor;
2126 if (textureAdaptor[0]) { /* bilinear */
2127 newAdaptors[num_adaptors] = textureAdaptor[0];
2131 if (textureAdaptor[1]) { /* bicubic */
2132 newAdaptors[num_adaptors] = textureAdaptor[1];
2137 newAdaptors[num_adaptors] = blitAdaptor;
2141 adaptors = newAdaptors;
2146 xf86XVScreenInit(pScreen, adaptors, num_adaptors);