summaryrefslogtreecommitdiff
path: root/src/sna/sna_video.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sna/sna_video.c')
-rw-r--r--src/sna/sna_video.c737
1 files changed, 737 insertions, 0 deletions
diff --git a/src/sna/sna_video.c b/src/sna/sna_video.c
new file mode 100644
index 00000000..b6cbda22
--- /dev/null
+++ b/src/sna/sna_video.c
@@ -0,0 +1,737 @@
+/***************************************************************************
+
+ Copyright 2000 Intel Corporation. All Rights Reserved.
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sub license, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice (including the
+ next paragraph) shall be included in all copies or substantial portions
+ of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+ THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **************************************************************************/
+
+/*
+ * i830_video.c: i830/i845 Xv driver.
+ *
+ * Copyright © 2002 by Alan Hourihane and David Dawes
+ *
+ * Authors:
+ * Alan Hourihane <alanh@tungstengraphics.com>
+ * David Dawes <dawes@xfree86.org>
+ *
+ * Derived from i810 Xv driver:
+ *
+ * Authors of i810 code:
+ * Jonathan Bian <jonathan.bian@intel.com>
+ * Offscreen Images:
+ * Matt Sottek <matthew.j.sottek@intel.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <inttypes.h>
+#include <math.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/mman.h>
+
+#include "sna.h"
+#include "sna_reg.h"
+#include "sna_video.h"
+
+#include <xf86xv.h>
+#include <X11/extensions/Xv.h>
+
+#ifdef SNA_XVMC
+#define _SNA_XVMC_SERVER_
+#include "sna_video_hwmc.h"
+#else
+static inline Bool sna_video_xvmc_setup(struct sna *sna,
+ ScreenPtr ptr,
+ XF86VideoAdaptorPtr target)
+{
+ return FALSE;
+}
+#endif
+
+#if DEBUG_VIDEO_TEXTURED
+#undef DBG
+#define DBG(x) ErrorF x
+#endif
+
+void sna_video_free_buffers(struct sna *sna, struct sna_video *video)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(video->old_buf); i++) {
+ if (video->old_buf[i]) {
+ kgem_bo_destroy(&sna->kgem, video->old_buf[i]);
+ video->old_buf[i] = NULL;
+ }
+ }
+
+ if (video->buf) {
+ kgem_bo_destroy(&sna->kgem, video->buf);
+ video->buf = NULL;
+ }
+}
+
+void sna_video_frame_fini(struct sna *sna,
+ struct sna_video *video,
+ struct sna_video_frame *frame)
+{
+ struct kgem_bo *bo;
+
+ if (!frame->bo->reusable) {
+ kgem_bo_destroy(&sna->kgem, frame->bo);
+ return;
+ }
+
+ bo = video->old_buf[1];
+ video->old_buf[1] = video->old_buf[0];
+ video->old_buf[0] = video->buf;
+ video->buf = bo;
+}
+
+Bool
+sna_video_clip_helper(ScrnInfoPtr scrn,
+ struct sna_video *video,
+ xf86CrtcPtr * crtc_ret,
+ BoxPtr dst,
+ short src_x, short src_y,
+ short drw_x, short drw_y,
+ short src_w, short src_h,
+ short drw_w, short drw_h,
+ int id,
+ int *top, int* left, int* npixels, int *nlines,
+ RegionPtr reg, INT32 width, INT32 height)
+{
+ Bool ret;
+ RegionRec crtc_region_local;
+ RegionPtr crtc_region = reg;
+ BoxRec crtc_box;
+ INT32 x1, x2, y1, y2;
+ xf86CrtcPtr crtc;
+
+ x1 = src_x;
+ x2 = src_x + src_w;
+ y1 = src_y;
+ y2 = src_y + src_h;
+
+ dst->x1 = drw_x;
+ dst->x2 = drw_x + drw_w;
+ dst->y1 = drw_y;
+ dst->y2 = drw_y + drw_h;
+
+ /*
+ * For overlay video, compute the relevant CRTC and
+ * clip video to that
+ */
+ crtc = sna_covering_crtc(scrn, dst, video->desired_crtc,
+ &crtc_box);
+
+ /* For textured video, we don't actually want to clip at all. */
+ if (crtc && !video->textured) {
+ RegionInit(&crtc_region_local, &crtc_box, 1);
+ crtc_region = &crtc_region_local;
+ RegionIntersect(crtc_region, crtc_region, reg);
+ }
+ *crtc_ret = crtc;
+
+ ret = xf86XVClipVideoHelper(dst, &x1, &x2, &y1, &y2,
+ crtc_region, width, height);
+ if (crtc_region != reg)
+ RegionUninit(&crtc_region_local);
+
+ *top = y1 >> 16;
+ *left = (x1 >> 16) & ~1;
+ *npixels = ALIGN(((x2 + 0xffff) >> 16), 2) - *left;
+ if (is_planar_fourcc(id)) {
+ *top &= ~1;
+ *nlines = ALIGN(((y2 + 0xffff) >> 16), 2) - *top;
+ } else
+ *nlines = ((y2 + 0xffff) >> 16) - *top;
+
+ return ret;
+}
+
+void
+sna_video_frame_init(struct sna *sna,
+ struct sna_video *video,
+ int id, short width, short height,
+ struct sna_video_frame *frame)
+{
+ int align;
+
+ frame->id = id;
+ frame->width = width;
+ frame->height = height;
+
+ /* Only needs to be DWORD-aligned for textured on i915, but overlay has
+ * stricter requirements.
+ */
+ if (video->textured) {
+ align = 4;
+ } else {
+ if (sna->kgem.gen >= 40)
+ /* Actually the alignment is 64 bytes, too. But the
+ * stride must be at least 512 bytes. Take the easy fix
+ * and align on 512 bytes unconditionally. */
+ align = 512;
+ else if (IS_I830(sna) || IS_845G(sna))
+ /* Harsh, errata on these chipsets limit the stride
+ * to be a multiple of 256 bytes.
+ */
+ align = 256;
+ else
+ align = 64;
+ }
+
+#if SNA_XVMC
+ /* for i915 xvmc, hw requires 1kb aligned surfaces */
+ if (id == FOURCC_XVMC && sna->kgem.gen < 40)
+ align = 1024;
+#endif
+
+
+ /* Determine the desired destination pitch (representing the chroma's pitch,
+ * in the planar case.
+ */
+ if (is_planar_fourcc(id)) {
+ if (video->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
+ frame->pitch[0] = ALIGN((height / 2), align);
+ frame->pitch[1] = ALIGN(height, align);
+ frame->size = frame->pitch[0] * width * 3;
+ } else {
+ frame->pitch[0] = ALIGN((width / 2), align);
+ frame->pitch[1] = ALIGN(width, align);
+ frame->size = frame->pitch[0] * height * 3;
+ }
+ } else {
+ if (video->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
+ frame->pitch[0] = ALIGN((height << 1), align);
+ frame->size = frame->pitch[0] * width;
+ } else {
+ frame->pitch[0] = ALIGN((width << 1), align);
+ frame->size = frame->pitch[0] * height;
+ }
+ frame->pitch[1] = 0;
+ }
+
+ frame->YBufOffset = 0;
+
+ if (video->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
+ frame->UBufOffset =
+ frame->YBufOffset + frame->pitch[1] * width;
+ frame->VBufOffset =
+ frame->UBufOffset + frame->pitch[0] * width / 2;
+ } else {
+ frame->UBufOffset =
+ frame->YBufOffset + frame->pitch[1] * height;
+ frame->VBufOffset =
+ frame->UBufOffset + frame->pitch[0] * height / 2;
+ }
+}
+
+static struct kgem_bo *
+sna_video_buffer(struct sna *sna,
+ struct sna_video *video,
+ struct sna_video_frame *frame)
+{
+ /* Free the current buffer if we're going to have to reallocate */
+ if (video->buf && video->buf->size < frame->size)
+ sna_video_free_buffers(sna, video);
+
+ if (video->buf == NULL)
+ video->buf = kgem_create_linear(&sna->kgem, frame->size);
+
+ return video->buf;
+}
+
+static void sna_memcpy_plane(unsigned char *dst, unsigned char *src,
+ int height, int width,
+ int dstPitch, int srcPitch, Rotation rotation)
+{
+ int i, j = 0;
+ unsigned char *s;
+
+ switch (rotation) {
+ case RR_Rotate_0:
+ /* optimise for the case of no clipping */
+ if (srcPitch == dstPitch && srcPitch == width)
+ memcpy(dst, src, srcPitch * height);
+ else
+ for (i = 0; i < height; i++) {
+ memcpy(dst, src, width);
+ src += srcPitch;
+ dst += dstPitch;
+ }
+ break;
+ case RR_Rotate_90:
+ for (i = 0; i < height; i++) {
+ s = src;
+ for (j = 0; j < width; j++) {
+ dst[(i) + ((width - j - 1) * dstPitch)] = *s++;
+ }
+ src += srcPitch;
+ }
+ break;
+ case RR_Rotate_180:
+ for (i = 0; i < height; i++) {
+ s = src;
+ for (j = 0; j < width; j++) {
+ dst[(width - j - 1) +
+ ((height - i - 1) * dstPitch)] = *s++;
+ }
+ src += srcPitch;
+ }
+ break;
+ case RR_Rotate_270:
+ for (i = 0; i < height; i++) {
+ s = src;
+ for (j = 0; j < width; j++) {
+ dst[(height - i - 1) + (j * dstPitch)] = *s++;
+ }
+ src += srcPitch;
+ }
+ break;
+ }
+}
+
+static void
+sna_copy_planar_data(struct sna *sna,
+ struct sna_video *video,
+ struct sna_video_frame *frame,
+ unsigned char *buf,
+ unsigned char *dst,
+ int srcPitch, int srcPitch2,
+ int srcH, int top, int left)
+{
+ unsigned char *src1, *src2, *src3, *dst1, *dst2, *dst3;
+
+ /* Copy Y data */
+ src1 = buf + (top * srcPitch) + left;
+
+ dst1 = dst + frame->YBufOffset;
+
+ sna_memcpy_plane(dst1, src1,
+ frame->height, frame->width,
+ frame->pitch[1], srcPitch,
+ video->rotation);
+
+ /* Copy V data for YV12, or U data for I420 */
+ src2 = buf + /* start of YUV data */
+ (srcH * srcPitch) + /* move over Luma plane */
+ ((top >> 1) * srcPitch2) + /* move down from by top lines */
+ (left >> 1); /* move left by left pixels */
+
+ if (frame->id == FOURCC_I420)
+ dst2 = dst + frame->UBufOffset;
+ else
+ dst2 = dst + frame->VBufOffset;
+
+ sna_memcpy_plane(dst2, src2,
+ frame->height / 2, frame->width / 2,
+ frame->pitch[0], srcPitch2,
+ video->rotation);
+
+ /* Copy U data for YV12, or V data for I420 */
+ src3 = buf + /* start of YUV data */
+ (srcH * srcPitch) + /* move over Luma plane */
+ ((srcH >> 1) * srcPitch2) + /* move over Chroma plane */
+ ((top >> 1) * srcPitch2) + /* move down from by top lines */
+ (left >> 1); /* move left by left pixels */
+ if (frame->id == FOURCC_I420)
+ dst3 = dst + frame->VBufOffset;
+ else
+ dst3 = dst + frame->UBufOffset;
+
+ sna_memcpy_plane(dst3, src3,
+ frame->height / 2, frame->width / 2,
+ frame->pitch[0], srcPitch2,
+ video->rotation);
+}
+
+static void
+sna_copy_packed_data(struct sna *sna,
+ struct sna_video *video,
+ struct sna_video_frame *frame,
+ unsigned char *buf,
+ unsigned char *dst,
+ int srcPitch,
+ int top, int left)
+{
+ unsigned char *src;
+ unsigned char *s;
+ int i, j;
+
+ src = buf + (top * srcPitch) + (left << 1);
+
+ dst += frame->YBufOffset;
+
+ switch (video->rotation) {
+ case RR_Rotate_0:
+ frame->width <<= 1;
+ for (i = 0; i < frame->height; i++) {
+ memcpy(dst, src, frame->width);
+ src += srcPitch;
+ dst += frame->pitch[0];
+ }
+ break;
+ case RR_Rotate_90:
+ frame->height <<= 1;
+ for (i = 0; i < frame->height; i += 2) {
+ s = src;
+ for (j = 0; j < frame->width; j++) {
+ /* Copy Y */
+ dst[(i + 0) + ((frame->width - j - 1) * frame->pitch[0])] = *s++;
+ (void)*s++;
+ }
+ src += srcPitch;
+ }
+ frame->height >>= 1;
+ src = buf + (top * srcPitch) + (left << 1);
+ for (i = 0; i < frame->height; i += 2) {
+ for (j = 0; j < frame->width; j += 2) {
+ /* Copy U */
+ dst[((i * 2) + 1) + ((frame->width - j - 1) * frame->pitch[0])] =
+ src[(j * 2) + 1 + (i * srcPitch)];
+ dst[((i * 2) + 1) + ((frame->width - j - 2) * frame->pitch[0])] =
+ src[(j * 2) + 1 + ((i + 1) * srcPitch)];
+ /* Copy V */
+ dst[((i * 2) + 3) + ((frame->width - j - 1) * frame->pitch[0])] =
+ src[(j * 2) + 3 + (i * srcPitch)];
+ dst[((i * 2) + 3) + ((frame->width - j - 2) * frame->pitch[0])] =
+ src[(j * 2) + 3 + ((i + 1) * srcPitch)];
+ }
+ }
+ break;
+ case RR_Rotate_180:
+ frame->width <<= 1;
+ for (i = 0; i < frame->height; i++) {
+ s = src;
+ for (j = 0; j < frame->width; j += 4) {
+ dst[(frame->width - j - 4) + ((frame->height - i - 1) * frame->pitch[0])] =
+ *s++;
+ dst[(frame->width - j - 3) + ((frame->height - i - 1) * frame->pitch[0])] =
+ *s++;
+ dst[(frame->width - j - 2) + ((frame->height - i - 1) * frame->pitch[0])] =
+ *s++;
+ dst[(frame->width - j - 1) + ((frame->height - i - 1) * frame->pitch[0])] =
+ *s++;
+ }
+ src += srcPitch;
+ }
+ break;
+ case RR_Rotate_270:
+ frame->height <<= 1;
+ for (i = 0; i < frame->height; i += 2) {
+ s = src;
+ for (j = 0; j < frame->width; j++) {
+ /* Copy Y */
+ dst[(frame->height - i - 2) + (j * frame->pitch[0])] = *s++;
+ (void)*s++;
+ }
+ src += srcPitch;
+ }
+ frame->height >>= 1;
+ src = buf + (top * srcPitch) + (left << 1);
+ for (i = 0; i < frame->height; i += 2) {
+ for (j = 0; j < frame->width; j += 2) {
+ /* Copy U */
+ dst[(((frame->height - i) * 2) - 3) + (j * frame->pitch[0])] =
+ src[(j * 2) + 1 + (i * srcPitch)];
+ dst[(((frame->height - i) * 2) - 3) +
+ ((j + 1) * frame->pitch[0])] =
+ src[(j * 2) + 1 + ((i + 1) * srcPitch)];
+ /* Copy V */
+ dst[(((frame->height - i) * 2) - 1) + (j * frame->pitch[0])] =
+ src[(j * 2) + 3 + (i * srcPitch)];
+ dst[(((frame->height - i) * 2) - 1) +
+ ((j + 1) * frame->pitch[0])] =
+ src[(j * 2) + 3 + ((i + 1) * srcPitch)];
+ }
+ }
+ break;
+ }
+}
+
+Bool
+sna_video_copy_data(struct sna *sna,
+ struct sna_video *video,
+ struct sna_video_frame *frame,
+ int top, int left,
+ int npixels, int nlines,
+ unsigned char *buf)
+{
+ unsigned char *dst;
+
+ frame->bo = sna_video_buffer(sna, video, frame);
+ if (frame->bo == NULL)
+ return FALSE;
+
+ /* copy data */
+ dst = kgem_bo_map(&sna->kgem, frame->bo, PROT_READ | PROT_WRITE);
+ if (dst == NULL)
+ return FALSE;
+
+ if (is_planar_fourcc(frame->id)) {
+ int srcPitch = ALIGN(frame->width, 0x4);
+ int srcPitch2 = ALIGN((frame->width >> 1), 0x4);
+
+ sna_copy_planar_data(sna, video, frame,
+ buf, dst,
+ srcPitch, srcPitch2,
+ nlines, top, left);
+ } else {
+ int srcPitch = frame->width << 1;
+
+ sna_copy_packed_data(sna, video, frame,
+ buf, dst,
+ srcPitch,
+ top, left);
+ }
+
+ munmap(dst, video->buf->size);
+ return TRUE;
+}
+
+static void sna_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
+{
+ if (crtc->enabled) {
+ crtc_box->x1 = crtc->x;
+ crtc_box->x2 =
+ crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation);
+ crtc_box->y1 = crtc->y;
+ crtc_box->y2 =
+ crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation);
+ } else
+ crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
+}
+
+static void sna_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
+{
+ dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1;
+ dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2;
+ dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1;
+ dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2;
+ if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2)
+ dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
+}
+
+static int sna_box_area(BoxPtr box)
+{
+ return (int)(box->x2 - box->x1) * (int)(box->y2 - box->y1);
+}
+
+/*
+ * Return the crtc covering 'box'. If two crtcs cover a portion of
+ * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc
+ * with greater coverage
+ */
+
+xf86CrtcPtr
+sna_covering_crtc(ScrnInfoPtr scrn,
+ BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ xf86CrtcPtr crtc, best_crtc;
+ int coverage, best_coverage;
+ int c;
+ BoxRec crtc_box, cover_box;
+
+ DBG(("%s for box=(%d, %d), (%d, %d)\n",
+ __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
+
+ best_crtc = NULL;
+ best_coverage = 0;
+ crtc_box_ret->x1 = 0;
+ crtc_box_ret->x2 = 0;
+ crtc_box_ret->y1 = 0;
+ crtc_box_ret->y2 = 0;
+ for (c = 0; c < xf86_config->num_crtc; c++) {
+ crtc = xf86_config->crtc[c];
+
+ /* If the CRTC is off, treat it as not covering */
+ if (!sna_crtc_on(crtc)) {
+ DBG(("%s: crtc %d off, skipping\n", __FUNCTION__, c));
+ continue;
+ }
+
+ sna_crtc_box(crtc, &crtc_box);
+ sna_box_intersect(&cover_box, &crtc_box, box);
+ coverage = sna_box_area(&cover_box);
+ if (coverage && crtc == desired) {
+ DBG(("%s: box is on desired crtc [%p]\n",
+ __FUNCTION__, crtc));
+ *crtc_box_ret = crtc_box;
+ return crtc;
+ }
+ if (coverage > best_coverage) {
+ *crtc_box_ret = crtc_box;
+ best_crtc = crtc;
+ best_coverage = coverage;
+ }
+ }
+ DBG(("%s: best crtc = %p\n", __FUNCTION__, best_crtc));
+ return best_crtc;
+}
+
+bool
+sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
+ xf86CrtcPtr crtc, RegionPtr clip)
+{
+ pixman_box16_t box, crtc_box;
+ int pipe, event;
+ Bool full_height;
+ int y1, y2;
+ uint32_t *b;
+
+ /* XXX no wait for scanline support on SNB? */
+ if (sna->kgem.gen >= 60)
+ return false;
+
+ if (!pixmap_is_scanout(pixmap))
+ return false;
+
+ if (crtc == NULL) {
+ if (clip) {
+ crtc_box = *REGION_EXTENTS(NULL, clip);
+ } else {
+ crtc_box.x1 = 0; /* XXX drawable offsets? */
+ crtc_box.y1 = 0;
+ crtc_box.x2 = pixmap->drawable.width;
+ crtc_box.y2 = pixmap->drawable.height;
+ }
+ crtc = sna_covering_crtc(sna->scrn, &crtc_box, NULL, &crtc_box);
+ }
+
+ if (crtc == NULL)
+ return false;
+
+ if (clip) {
+ box = *REGION_EXTENTS(unused, clip);
+
+ if (crtc->transform_in_use)
+ pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &box);
+
+ /* We could presume the clip was correctly computed... */
+ sna_crtc_box(crtc, &crtc_box);
+ sna_box_intersect(&box, &crtc_box, &box);
+
+ /*
+ * Make sure we don't wait for a scanline that will
+ * never occur
+ */
+ y1 = (crtc_box.y1 <= box.y1) ? box.y1 - crtc_box.y1 : 0;
+ y2 = (box.y2 <= crtc_box.y2) ?
+ box.y2 - crtc_box.y1 : crtc_box.y2 - crtc_box.y1;
+ if (y2 <= y1)
+ return false;
+
+ full_height = FALSE;
+ if (y1 == 0 && y2 == (crtc_box.y2 - crtc_box.y1))
+ full_height = TRUE;
+ } else {
+ sna_crtc_box(crtc, &crtc_box);
+ y1 = crtc_box.y1;
+ y2 = crtc_box.y2;
+ full_height = TRUE;
+ }
+
+ /*
+ * Pre-965 doesn't have SVBLANK, so we need a bit
+ * of extra time for the blitter to start up and
+ * do its job for a full height blit
+ */
+ if (sna_crtc_to_pipe(crtc) == 0) {
+ pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEA;
+ event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
+ if (full_height)
+ event = MI_WAIT_FOR_PIPEA_SVBLANK;
+ } else {
+ pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEB;
+ event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW;
+ if (full_height)
+ event = MI_WAIT_FOR_PIPEB_SVBLANK;
+ }
+
+ if (crtc->mode.Flags & V_INTERLACE) {
+ /* DSL count field lines */
+ y1 /= 2;
+ y2 /= 2;
+ }
+
+ b = kgem_get_batch(&sna->kgem, 5);
+ /* The documentation says that the LOAD_SCAN_LINES command
+ * always comes in pairs. Don't ask me why. */
+ b[0] = MI_LOAD_SCAN_LINES_INCL | pipe;
+ b[1] = (y1 << 16) | (y2-1);
+ b[2] = MI_LOAD_SCAN_LINES_INCL | pipe;
+ b[3] = (y1 << 16) | (y2-1);
+ b[4] = MI_WAIT_FOR_EVENT | event;
+ kgem_advance_batch(&sna->kgem, 5);
+ return true;
+}
+
+void sna_video_init(struct sna *sna, ScreenPtr screen)
+{
+ XF86VideoAdaptorPtr *adaptors, *newAdaptors;
+ XF86VideoAdaptorPtr textured, overlay;
+ int num_adaptors;
+ int prefer_overlay =
+ xf86ReturnOptValBool(sna->Options, OPTION_PREFER_OVERLAY, FALSE);
+
+ num_adaptors = xf86XVListGenericAdaptors(sna->scrn, &adaptors);
+ newAdaptors =
+ malloc((num_adaptors + 2) * sizeof(XF86VideoAdaptorPtr *));
+ if (newAdaptors == NULL)
+ return;
+
+ memcpy(newAdaptors, adaptors,
+ num_adaptors * sizeof(XF86VideoAdaptorPtr));
+ adaptors = newAdaptors;
+
+ /* Set up textured video if we can do it at this depth and we are on
+ * supported hardware.
+ */
+ textured = sna_video_textured_setup(sna, screen);
+ overlay = sna_video_overlay_setup(sna, screen);
+
+ if (overlay && prefer_overlay)
+ adaptors[num_adaptors++] = overlay;
+
+ if (textured)
+ adaptors[num_adaptors++] = textured;
+
+ if (overlay && !prefer_overlay)
+ adaptors[num_adaptors++] = overlay;
+
+ if (num_adaptors)
+ xf86XVScreenInit(screen, adaptors, num_adaptors);
+ else
+ xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
+ "Disabling Xv because no adaptors could be initialized.\n");
+ if (textured)
+ sna_video_xvmc_setup(sna, screen, textured);
+
+ free(adaptors);
+}