[PATCH xf86-video-nouveau] add dri2video support
Rob Clark
rob.clark at linaro.org
Tue Nov 15 14:49:49 PST 2011
From: Rob Clark <rob at ti.com>
TODO:
+ format advertised as I420 appears to actually be NV12
+ add non-fourcc format values for hw decode directly to VRAM
mapped buffer (skip GART->VRAM move)
+ CSC_MATRIX and OSD support..
---
src/nouveau_dri2.c | 214 ++++++++++++++++++++++++++++-----
src/nouveau_xv.c | 324 +++++++++++++++++++++++++++++++++++++++----------
src/nv30_xv_tex.c | 4 +-
src/nv40_xv_tex.c | 4 +-
src/nv50_xv.c | 2 +-
src/nv_accel_common.c | 11 ++
src/nv_type.h | 1 +
src/nvc0_xv.c | 2 +-
8 files changed, 459 insertions(+), 103 deletions(-)
diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c
index d14443f..445cd52 100644
--- a/src/nouveau_dri2.c
+++ b/src/nouveau_dri2.c
@@ -10,6 +10,10 @@
#include "dri2.h"
#endif
+// put these somewhere common..
+#define FOURCC(a, b, c, d) ((uint32_t)(uint8_t)(a) | ((uint32_t)(uint8_t)(b) << 8) | ((uint32_t)(uint8_t)(c) << 16) | ((uint32_t)(uint8_t)(d) << 24 ))
+#define FOURCC_STR(str) FOURCC(str[0], str[1], str[2], str[3])
+
#if defined(DRI2) && DRI2INFOREC_VERSION >= 3
struct nouveau_dri2_buffer {
DRI2BufferRec base;
@@ -22,19 +26,87 @@ nouveau_dri2_buffer(DRI2BufferPtr buf)
return (struct nouveau_dri2_buffer *)buf;
}
-DRI2BufferPtr
-nouveau_dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment,
- unsigned int format)
+static DRI2BufferPtr
+nouveau_dri2_create_buffer_2(DrawablePtr pDraw, unsigned int attachment,
+ unsigned int format, PixmapPtr ppix)
{
ScreenPtr pScreen = pDraw->pScreen;
NVPtr pNv = NVPTR(xf86Screens[pScreen->myNum]);
- struct nouveau_dri2_buffer *nvbuf;
struct nouveau_pixmap *nvpix;
- PixmapPtr ppix;
+ struct nouveau_dri2_buffer *nvbuf;
nvbuf = calloc(1, sizeof(*nvbuf));
- if (!nvbuf)
+ if (!nvbuf) {
+ // XXX cleanup..
+ return NULL;
+ }
+
+ pNv->exa_force_cp = TRUE;
+ exaMoveInPixmap(ppix);
+ pNv->exa_force_cp = FALSE;
+
+ nvbuf->base.attachment = attachment;
+ nvbuf->base.pitch = ppix->devKind;
+ nvbuf->base.cpp = ppix->drawable.bitsPerPixel / 8;
+ nvbuf->base.driverPrivate = nvbuf;
+ nvbuf->base.format = format;
+ nvbuf->base.flags = 0;
+ nvbuf->ppix = ppix;
+
+ nvpix = nouveau_pixmap(ppix);
+ if (!nvpix || !nvpix->bo ||
+ nouveau_bo_handle_get(nvpix->bo, &nvbuf->base.name)) {
+ pScreen->DestroyPixmap(nvbuf->ppix);
+ free(nvbuf);
return NULL;
+ }
+
+ return &nvbuf->base;
+
+}
+
+static DRI2BufferPtr
+nouveau_dri2_create_buffer_vid(DrawablePtr pDraw, unsigned int attachment,
+ unsigned int format, unsigned int width, unsigned int height)
+{
+ ScreenPtr pScreen = pDraw->pScreen;
+ PixmapPtr ppix;
+ int bpp;
+
+ switch(format) {
+ case FOURCC('I','4','2','0'):
+ case FOURCC('Y','V','1','2'):
+ /* to avoid confusing CreatePixmap too much, call these 1cpp
+ * and 1.5x height
+ */
+ bpp = 8;
+ height = ((height + 1) & ~1) * 3 / 2;
+ break;
+ case FOURCC('Y','U','Y','2'):
+ case FOURCC('U','Y','V','Y'):
+ bpp = 16;
+ break;
+ case FOURCC('R','G','B','3'): /* depth=24, bpp=32 */
+ case 24:
+ case FOURCC('R','G','B','4'): /* depth=32, bpp=32 */
+ case 32:
+ bpp = 32;
+ break;
+ default:
+ return NULL;
+ }
+
+ ppix = pScreen->CreatePixmap(pScreen, width, height, bpp, NOUVEAU_CREATE_PIXMAP_VIDEO);
+
+ return nouveau_dri2_create_buffer_2(pDraw, attachment, format, ppix);
+}
+
+DRI2BufferPtr
+nouveau_dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment,
+ unsigned int format)
+{
+ ScreenPtr pScreen = pDraw->pScreen;
+ PixmapPtr ppix;
if (attachment == DRI2BufferFrontLeft) {
if (pDraw->type == DRAWABLE_PIXMAP) {
@@ -59,27 +131,7 @@ nouveau_dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment,
usage_hint);
}
- pNv->exa_force_cp = TRUE;
- exaMoveInPixmap(ppix);
- pNv->exa_force_cp = FALSE;
-
- nvbuf->base.attachment = attachment;
- nvbuf->base.pitch = ppix->devKind;
- nvbuf->base.cpp = ppix->drawable.bitsPerPixel / 8;
- nvbuf->base.driverPrivate = nvbuf;
- nvbuf->base.format = format;
- nvbuf->base.flags = 0;
- nvbuf->ppix = ppix;
-
- nvpix = nouveau_pixmap(ppix);
- if (!nvpix || !nvpix->bo ||
- nouveau_bo_handle_get(nvpix->bo, &nvbuf->base.name)) {
- pScreen->DestroyPixmap(nvbuf->ppix);
- free(nvbuf);
- return NULL;
- }
-
- return &nvbuf->base;
+ return nouveau_dri2_create_buffer_2(pDraw, attachment, format, ppix);
}
void
@@ -95,6 +147,13 @@ nouveau_dri2_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buf)
free(nvbuf);
}
+/* moveme: */
+int
+nouveau_put_texture_image(DrawablePtr pDraw, PixmapPtr srcPix, int id,
+ short src_x, short src_y, short drw_x, short drw_y,
+ short src_w, short src_h, short drw_w, short drw_h,
+ short width, short height);
+
void
nouveau_dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer)
@@ -332,6 +391,49 @@ fail:
}
static Bool
+nouveau_dri2_schedule_swap_vid(ClientPtr client, DrawablePtr draw,
+ DRI2BufferPtr dst, DRI2BufferPtr src,
+ BoxPtr b, DrawablePtr osd,
+ CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
+ DRI2SwapEventPtr func, void *data)
+{
+ ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
+ PixmapPtr src_pix = nouveau_dri2_buffer(src)->ppix;
+ short width, height;
+ int ret;
+
+ width = src_pix->drawable.width;
+ height = src_pix->drawable.height;
+
+ if (src->format == FOURCC_STR("I420") ||
+ src->format == FOURCC_STR("YV12")) {
+ /* undo the 'height *= 1.5' trick to recover real height */
+ height = (height * 2) / 3;
+ }
+
+ /* attempt to hijack some of the XV USE_TEXTURE code.. maybe not the
+ * cleanest way, or even work on all cards, but just for proof of concept..
+ *
+ * XXX this probably won't work for RGB formats, at least not on all
+ * chipset versions (like NV50).. probably want to use the CopyRegion
+ * code path (or something similar?) for RGB??
+ */
+ ret = nouveau_put_texture_image(draw, src_pix, src->format,
+ b->x1, b->y1, draw->x, draw->y,
+ b->x2 - b->x1, b->y2 - b->y1, draw->width, draw->height,
+ width, height);
+
+ if (ret != Success) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING, "blit failed: %d\n", ret);
+ return FALSE;
+ }
+
+ DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
+
+ return TRUE;
+}
+
+static Bool
nouveau_dri2_schedule_wait(ClientPtr client, DrawablePtr draw,
CARD64 target_msc, CARD64 divisor, CARD64 remainder)
{
@@ -396,6 +498,37 @@ nouveau_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
return TRUE;
}
+#define ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
+
+static int
+nouveau_set_attribute(DrawablePtr pDraw, Atom attribute,
+ int len, const CARD32 *val)
+{
+ /* just for testing.. bogus colorspace conversion matrix.. */
+ if (attribute == ATOM("XV_CSC_MATRIX")) {
+ return Success;
+ }
+ return BadMatch;
+}
+
+static int
+nouveau_get_attribute(DrawablePtr pDraw, Atom attribute,
+ int *len, const CARD32 **val)
+{
+ /* just for testing.. bogus colorspace conversion matrix.. */
+ if (attribute == ATOM("XV_CSC_MATRIX")) {
+ static const CARD32 csc[] = {
+ 0x00, 0x01, 0x02, 0x03,
+ 0x10, 0x11, 0x12, 0x13,
+ 0x20, 0x21, 0x22, 0x23,
+ };
+ *val = csc;
+ *len = sizeof(csc) / 4;
+ return Success;
+ }
+ return BadMatch;
+}
+
void
nouveau_dri2_vblank_handler(int fd, unsigned int frame,
unsigned int tv_sec, unsigned int tv_usec,
@@ -428,28 +561,47 @@ nouveau_dri2_init(ScreenPtr pScreen)
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
NVPtr pNv = NVPTR(pScrn);
DRI2InfoRec dri2 = { 0 };
- const char *drivernames[2][2] = {
- { "nouveau", "nouveau" },
- { "nouveau_vieux", "nouveau_vieux" }
+ const char *drivernames[2][3] = {
+ { "nouveau", "nouveau", "nouveau" },
+ { "nouveau_vieux", "nouveau_vieux", NULL }
+ };
+ const unsigned int formats[] = {
+ FOURCC_STR("YUY2"),
+ FOURCC_STR("YV12"),
+ FOURCC_STR("UYVY"),
+ FOURCC_STR("I420"),
+ FOURCC_STR("RGB3"), /* depth=24, bpp=32 */
+ FOURCC_STR("RGB4"), /* depth=32, bpp=32 */
+ /* non-common formats: */
+ // XXX check what might have been passed by mesa!!
+ 24,
+ 32,
};
if (pNv->Architecture >= NV_ARCH_30)
dri2.driverNames = drivernames[0];
else
dri2.driverNames = drivernames[1];
- dri2.numDrivers = 2;
+ dri2.numDrivers = 3;
dri2.driverName = dri2.driverNames[0];
+ dri2.numFormats = ARRAY_SIZE(formats);
+ dri2.formats = formats;
+
dri2.fd = nouveau_device(pNv->dev)->fd;
dri2.deviceName = pNv->drm_device_name;
dri2.version = DRI2INFOREC_VERSION;
dri2.CreateBuffer = nouveau_dri2_create_buffer;
+ dri2.CreateBufferVid = nouveau_dri2_create_buffer_vid;
dri2.DestroyBuffer = nouveau_dri2_destroy_buffer;
dri2.CopyRegion = nouveau_dri2_copy_region;
dri2.ScheduleSwap = nouveau_dri2_schedule_swap;
+ dri2.ScheduleSwapVid = nouveau_dri2_schedule_swap_vid;
dri2.ScheduleWaitMSC = nouveau_dri2_schedule_wait;
dri2.GetMSC = nouveau_dri2_get_msc;
+ dri2.SetAttribute = nouveau_set_attribute;
+ dri2.GetAttribute = nouveau_get_attribute;
return DRI2ScreenInit(pScreen, &dri2);
}
diff --git a/src/nouveau_xv.c b/src/nouveau_xv.c
index 5a5337c..2733a2c 100644
--- a/src/nouveau_xv.c
+++ b/src/nouveau_xv.c
@@ -561,6 +561,10 @@ NVCopyNV12ColorPlanes(unsigned char *src1, unsigned char *src2,
}
+// put these somewhere common..
+#define FOURCC(a, b, c, d) ((uint32_t)(uint8_t)(a) | ((uint32_t)(uint8_t)(b) << 8) | ((uint32_t)(uint8_t)(c) << 16) | ((uint32_t)(uint8_t)(d) << 24 ))
+#define FOURCC_STR(str) FOURCC(str[0], str[1], str[2], str[3])
+
static int
NV_set_dimensions(ScrnInfoPtr pScrn, int action_flags, INT32 *xa, INT32 *xb,
INT32 *ya, INT32 *yb, short *src_x, short *src_y,
@@ -887,6 +891,87 @@ NV_set_action_flags(ScrnInfoPtr pScrn, DrawablePtr pDraw, NVPortPrivPtr pPriv,
}
}
+/* move from GART -> VRAM */
+static int
+nouveau_xv_m2mf(ScrnInfoPtr pScrn, int action_flags,
+ struct nouveau_bo *src /* GART buffer */,
+ struct nouveau_bo *dst /* VRAM buffer */,
+ int offset, int uv_offset, int nlines, int line_len, int dstPitch)
+{
+ NVPtr pNv = NVPTR(pScrn);
+ struct nouveau_channel *chan = pNv->chan;
+ struct nouveau_grobj *m2mf = pNv->NvMemFormat;
+
+ if (pNv->Architecture >= NV_ARCH_C0) {
+ nvc0_xv_m2mf(m2mf, dst, uv_offset, dstPitch,
+ nlines, src, line_len);
+ return Success;
+ }
+
+ if (MARK_RING(chan, 64, 4))
+ return BadAlloc;
+
+ BEGIN_RING(chan, m2mf,
+ NV04_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2);
+ OUT_RING (chan, pNv->chan->gart->handle);
+ OUT_RING (chan, pNv->chan->vram->handle);
+
+ if (pNv->Architecture >= NV_ARCH_50) {
+ BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_IN, 1);
+ OUT_RING (chan, 1);
+
+ BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_OUT, 7);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, src->tile_mode << 4);
+ OUT_RING (chan, dstPitch);
+ OUT_RING (chan, nlines);
+ OUT_RING (chan, 1);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, 0);
+ }
+
+ /* DMA to VRAM */
+ if ( (action_flags & IS_YV12) &&
+ !(action_flags & CONVERT_TO_YUY2)) {
+ /* we start the color plane transfer separately */
+
+ BEGIN_RING(chan, m2mf,
+ NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
+ if (OUT_RELOCl(chan, src,
+ line_len * nlines,
+ NOUVEAU_BO_GART | NOUVEAU_BO_RD) ||
+ OUT_RELOCl(chan, dst,
+ offset + uv_offset,
+ NOUVEAU_BO_VRAM | NOUVEAU_BO_WR)) {
+ MARK_UNDO(chan);
+ return BadAlloc;
+ }
+ OUT_RING (chan, line_len);
+ OUT_RING (chan, dstPitch);
+ OUT_RING (chan, line_len);
+ OUT_RING (chan, (nlines >> 1));
+ OUT_RING (chan, (1<<8)|1);
+ OUT_RING (chan, 0);
+ }
+
+ BEGIN_RING(chan, m2mf,
+ NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
+ if (OUT_RELOCl(chan, src, 0,
+ NOUVEAU_BO_GART | NOUVEAU_BO_RD) ||
+ OUT_RELOCl(chan, dst, offset,
+ NOUVEAU_BO_VRAM | NOUVEAU_BO_WR)) {
+ MARK_UNDO(chan);
+ return BadAlloc;
+ }
+ OUT_RING (chan, line_len);
+ OUT_RING (chan, dstPitch);
+ OUT_RING (chan, line_len);
+ OUT_RING (chan, nlines);
+ OUT_RING (chan, (1<<8)|1);
+ OUT_RING (chan, 0);
+
+ return Success;
+}
/**
* NVPutImage
@@ -936,8 +1021,6 @@ NVPutImage(ScrnInfoPtr pScrn, short src_x, short src_y, short drw_x,
* and lines we are interested in
*/
int top = 0, left = 0, right = 0, bottom = 0, npixels = 0, nlines = 0;
- struct nouveau_channel *chan = pNv->chan;
- struct nouveau_grobj *m2mf = pNv->NvMemFormat;
Bool skip = FALSE;
BoxRec dstBox;
CARD32 tmp = 0;
@@ -1111,73 +1194,17 @@ NVPutImage(ScrnInfoPtr pScrn, short src_x, short src_y, short drw_x,
nouveau_bo_unmap(destination_buffer);
- if (pNv->Architecture >= NV_ARCH_C0) {
- nvc0_xv_m2mf(m2mf, pPriv->video_mem, uv_offset, dstPitch,
- nlines, destination_buffer, line_len);
- goto put_image;
- }
-
- if (MARK_RING(chan, 64, 4))
- return FALSE;
-
- BEGIN_RING(chan, m2mf,
- NV04_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN, 2);
- OUT_RING (chan, pNv->chan->gart->handle);
- OUT_RING (chan, pNv->chan->vram->handle);
-
- if (pNv->Architecture >= NV_ARCH_50) {
- BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_IN, 1);
- OUT_RING (chan, 1);
-
- BEGIN_RING(chan, m2mf, NV50_MEMORY_TO_MEMORY_FORMAT_LINEAR_OUT, 7);
- OUT_RING (chan, 0);
- OUT_RING (chan, destination_buffer->tile_mode << 4);
- OUT_RING (chan, dstPitch);
- OUT_RING (chan, nlines);
- OUT_RING (chan, 1);
- OUT_RING (chan, 0);
- OUT_RING (chan, 0);
- }
-
- /* DMA to VRAM */
- if ( (action_flags & IS_YV12) &&
- !(action_flags & CONVERT_TO_YUY2)) {
- /* we start the color plane transfer separately */
-
- BEGIN_RING(chan, m2mf,
- NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
- if (OUT_RELOCl(chan, destination_buffer,
- line_len * nlines,
- NOUVEAU_BO_GART | NOUVEAU_BO_RD) ||
- OUT_RELOCl(chan, pPriv->video_mem,
- offset + uv_offset,
- NOUVEAU_BO_VRAM | NOUVEAU_BO_WR)) {
- MARK_UNDO(chan);
- return BadAlloc;
- }
- OUT_RING (chan, line_len);
- OUT_RING (chan, dstPitch);
- OUT_RING (chan, line_len);
- OUT_RING (chan, (nlines >> 1));
- OUT_RING (chan, (1<<8)|1);
- OUT_RING (chan, 0);
+ ret = nouveau_xv_m2mf(pScrn, action_flags,
+ destination_buffer, pPriv->video_mem,
+ offset, uv_offset, nlines, line_len, dstPitch);
+ if (ret != Success) {
+ return ret;
}
- BEGIN_RING(chan, m2mf,
- NV04_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
- if (OUT_RELOCl(chan, destination_buffer, 0,
- NOUVEAU_BO_GART | NOUVEAU_BO_RD) ||
- OUT_RELOCl(chan, pPriv->video_mem, offset,
- NOUVEAU_BO_VRAM | NOUVEAU_BO_WR)) {
- MARK_UNDO(chan);
- return BadAlloc;
+ if (pNv->Architecture >= NV_ARCH_C0) {
+ /* is this needed? It is to preserve the original code flow */
+ goto put_image;
}
- OUT_RING (chan, line_len);
- OUT_RING (chan, dstPitch);
- OUT_RING (chan, line_len);
- OUT_RING (chan, nlines);
- OUT_RING (chan, (1<<8)|1);
- OUT_RING (chan, 0);
} else {
CPU_copy:
nouveau_bo_map(pPriv->video_mem, NOUVEAU_BO_WR);
@@ -1356,6 +1383,171 @@ put_image:
return Success;
}
+int
+nouveau_put_texture_image(DrawablePtr pDraw, PixmapPtr srcPix, int id,
+ short src_x, short src_y, short drw_x, short drw_y,
+ short src_w, short src_h, short drw_w, short drw_h,
+ short width, short height)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pDraw->pScreen->myNum];
+ NVPtr pNv = NVPTR(pScrn);
+ PixmapPtr dstPix = NVGetDrawablePixmap(pDraw);
+ BoxRec dstBox;
+ RegionRec clipRegion;
+ int action_flags;
+ struct nouveau_bo *src;
+ int ret = BadImplementation;
+
+ // XXX we just need pPriv->video_mem... maybe there is a better way?
+ NVPortPrivPtr pPriv = (NVPortPrivPtr)((pNv)->textureAdaptor[0]->pPortPrivates[0].ptr);
+
+ /* source box */
+ INT32 xa = 0, xb = 0, ya = 0, yb = 0;
+ /* size to allocate in VRAM and in GART respectively */
+ int newFBSize = 0, newTTSize = 0; /* ignored */
+ /* card VRAM offsets, source offsets for U and V planes */
+ int offset = 0, uv_offset = 0, s2offset = 0, s3offset = 0;
+ /* source pitch, source pitch of U and V planes in case of YV12,
+ * VRAM destination pitch
+ */
+ int srcPitch = 0, srcPitch2 = 0, dstPitch = 0;
+ /* position of the given source data (using src_*), number of pixels
+ * and lines we are interested in
+ */
+ int top = 0, left = 0, right = 0, bottom = 0, npixels = 0, nlines = 0;
+ /* length of a line, like npixels, but in bytes */
+ int line_len = 0;
+
+ RegionInit(&clipRegion, (&(BoxRec){ 0, 0, pDraw->width, pDraw->height }), 0);
+ RegionTranslate(&clipRegion, pDraw->x, pDraw->y);
+
+ action_flags = USE_TEXTURE;
+
+ switch(id) {
+ case FOURCC_YUY2:
+ case FOURCC_UYVY:
+ action_flags |= IS_YUY2;
+ break;
+ case FOURCC_I420:
+ action_flags |= SWAP_UV;
+ /* fallthrough */
+ case FOURCC_YV12:
+ action_flags |= IS_YV12;
+ break;
+ case FOURCC_RGB:
+ case FOURCC('R','G','B','4'):
+ case FOURCC('R','G','B','3'):
+ action_flags |= IS_RGB;
+ break;
+ default:
+ return BadColor;
+ }
+
+ if (NV_set_dimensions(pScrn, action_flags, &xa, &xb, &ya, &yb,
+ &src_x, &src_y, &src_w, &src_h,
+ &drw_x, &drw_y, &drw_w, &drw_h,
+ &left, &top, &right, &bottom, &dstBox,
+ &npixels, &nlines, &clipRegion, width, height)) {
+ return Success;
+ }
+
+ /* note: in Xv code, pixel buffer is src, uploaded YUV data is dst
+ * which becomes the src for the PutTextureImage() step.. so dstPitch
+ * is really our srcPitch (of src pixmap) and srcPitch's are ignored..
+ * as are a couple other things..
+ */
+ if (NV_calculate_pitches_and_mem_size(pNv, action_flags, &srcPitch,
+ &srcPitch2, &dstPitch, &s2offset,
+ &s3offset, &uv_offset,
+ &newFBSize, &newTTSize,
+ &line_len, npixels, nlines,
+ width, height)) {
+ return BadImplementation;
+ }
+
+ /* Ensure src and dst pixmap is in offscreen memory */
+ pNv->exa_force_cp = TRUE;
+ exaMoveInPixmap(dstPix);
+ exaMoveInPixmap(srcPix);
+ pNv->exa_force_cp = FALSE;
+
+ if (!exaGetPixmapDriverPrivate(dstPix) ||
+ !exaGetPixmapDriverPrivate(srcPix)) {
+ return BadAlloc;
+ }
+
+ src = nouveau_pixmap_bo(srcPix);
+
+#ifdef COMPOSITE
+ /* Convert screen coords to pixmap coords */
+ if (dstPix->screen_x || dstPix->screen_y) {
+ REGION_TRANSLATE(pScrn->pScreen, &clipRegion,
+ -dstPix->screen_x, -dstPix->screen_y);
+ dstBox.x1 -= dstPix->screen_x;
+ dstBox.x2 -= dstPix->screen_x;
+ dstBox.y1 -= dstPix->screen_y;
+ dstBox.y2 -= dstPix->screen_y;
+ }
+#endif
+
+ /* TODO check if src buffer is already in VRAM.. for hw decode
+ * we probably want to allow giving the client buffers in VRAM
+ * directly (via non-fourcc format values)
+ */
+
+ ret = nouveau_xv_bo_realloc(pScrn, NOUVEAU_BO_VRAM, newFBSize,
+ &pPriv->video_mem);
+ if (ret)
+ return BadAlloc;
+
+ ret = nouveau_xv_m2mf(pScrn, action_flags, src, pPriv->video_mem,
+ offset, uv_offset, nlines, line_len, dstPitch);
+ if (ret != Success) {
+ return ret;
+ }
+
+ if (pNv->Architecture == NV_ARCH_30) {
+ ret = NV30PutTextureImage(pScrn, pPriv->video_mem,
+ offset, uv_offset,
+ id, dstPitch, &dstBox, 0, 0,
+ xb, yb, npixels, nlines,
+ src_w, src_h, drw_w, drw_h,
+ &clipRegion, dstPix, NULL);
+ } else if (pNv->Architecture == NV_ARCH_40) {
+ ret = NV40PutTextureImage(pScrn, pPriv->video_mem,
+ offset, uv_offset,
+ id, dstPitch, &dstBox, 0, 0,
+ xb, yb, npixels, nlines,
+ src_w, src_h, drw_w, drw_h,
+ &clipRegion, dstPix, NULL);
+ } else if (pNv->Architecture == NV_ARCH_50) {
+ ret = nv50_xv_image_put(pScrn, pPriv->video_mem,
+ offset, uv_offset,
+ id, dstPitch, &dstBox, 0, 0,
+ xb, yb, npixels, nlines,
+ src_w, src_h, drw_w, drw_h,
+ &clipRegion, dstPix, NULL);
+ } else {
+ ret = nvc0_xv_image_put(pScrn, pPriv->video_mem,
+ offset, uv_offset,
+ id, dstPitch, &dstBox, 0, 0,
+ xb, yb, npixels, nlines,
+ src_w, src_h, drw_w, drw_h,
+ &clipRegion, dstPix, NULL);
+ }
+
+#ifdef COMPOSITE
+ /* Damage tracking */
+ if (!(action_flags & USE_OVERLAY))
+ DamageDamageRegion(&dstPix->drawable, &clipRegion);
+#endif
+
+ RegionUninit(&clipRegion);
+
+ return ret;
+}
+
+
/**
* QueryImageAttributes
*
diff --git a/src/nv30_xv_tex.c b/src/nv30_xv_tex.c
index 6d4e089..9c0e828 100644
--- a/src/nv30_xv_tex.c
+++ b/src/nv30_xv_tex.c
@@ -259,7 +259,7 @@ NV30PutTextureImage(ScrnInfoPtr pScrn, struct nouveau_bo *src, int src_offset,
struct nouveau_channel *chan = pNv->chan;
struct nouveau_grobj *rankine = pNv->Nv3D;
struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
- Bool bicubic = pPriv->bicubic;
+ Bool bicubic = pPriv && pPriv->bicubic;
float X1, X2, Y1, Y2;
BoxPtr pbox;
int nbox;
@@ -349,7 +349,7 @@ NV30PutTextureImage(ScrnInfoPtr pScrn, struct nouveau_bo *src, int src_offset,
}
/* Just before rendering we wait for vblank in the non-composited case. */
- if (pPriv->SyncToVBlank) {
+ if (pPriv && pPriv->SyncToVBlank) {
FIRE_RING(chan);
NV11SyncToVBlank(ppix, dstBox);
}
diff --git a/src/nv40_xv_tex.c b/src/nv40_xv_tex.c
index 0910e12..6249faf 100644
--- a/src/nv40_xv_tex.c
+++ b/src/nv40_xv_tex.c
@@ -263,7 +263,7 @@ NV40PutTextureImage(ScrnInfoPtr pScrn,
struct nouveau_channel *chan = pNv->chan;
struct nouveau_grobj *curie = pNv->Nv3D;
struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
- Bool bicubic = pPriv->bicubic;
+ Bool bicubic = pPriv && pPriv->bicubic;
float X1, X2, Y1, Y2;
BoxPtr pbox;
int nbox;
@@ -338,7 +338,7 @@ NV40PutTextureImage(ScrnInfoPtr pScrn,
OUT_RING (chan, 1);
/* Just before rendering we wait for vblank in the non-composited case. */
- if (pPriv->SyncToVBlank) {
+ if (pPriv && pPriv->SyncToVBlank) {
FIRE_RING(chan);
NV11SyncToVBlank(ppix, dstBox);
}
diff --git a/src/nv50_xv.c b/src/nv50_xv.c
index ddeb5bb..8b6bd67 100644
--- a/src/nv50_xv.c
+++ b/src/nv50_xv.c
@@ -290,7 +290,7 @@ nv50_xv_image_put(ScrnInfoPtr pScrn,
if (!nv50_xv_state_emit(ppix, id, src, packed_y, uv, width, height))
return BadAlloc;
- if (pPriv->SyncToVBlank) {
+ if (pPriv && pPriv->SyncToVBlank) {
NV50SyncToVBlank(ppix, dstBox);
}
diff --git a/src/nv_accel_common.c b/src/nv_accel_common.c
index 735f47f..7775331 100644
--- a/src/nv_accel_common.c
+++ b/src/nv_accel_common.c
@@ -30,6 +30,7 @@ nouveau_allocate_surface(ScrnInfoPtr scrn, int width, int height, int bpp,
NVPtr pNv = NVPTR(scrn);
Bool scanout = (usage_hint & NOUVEAU_CREATE_PIXMAP_SCANOUT);
Bool tiled = (usage_hint & NOUVEAU_CREATE_PIXMAP_TILED);
+ Bool video = (usage_hint & NOUVEAU_CREATE_PIXMAP_VIDEO);
int tile_mode = 0, tile_flags = 0;
int flags = NOUVEAU_BO_MAP | (bpp >= 8 ? NOUVEAU_BO_VRAM : 0);
int cpp = bpp / 8, ret;
@@ -114,6 +115,16 @@ nouveau_allocate_surface(ScrnInfoPtr scrn, int width, int height, int bpp,
if (usage_hint & NOUVEAU_CREATE_PIXMAP_SCANOUT)
tile_flags |= NOUVEAU_BO_TILE_SCANOUT;
+ if (video) {
+ if (pNv->Architecture == NV_ARCH_50)
+ tile_flags = 0x7000;
+ else if (pNv->Architecture == NV_ARCH_C0)
+ tile_flags = 0xfe00;
+ tile_flags |= NOUVEAU_BO_TILE_SCANOUT;
+ tile_mode = 0;
+ flags = NOUVEAU_BO_MAP | NOUVEAU_BO_GART;
+ }
+
ret = nouveau_bo_new_tile(pNv->dev, flags, 0, *pitch * height,
tile_mode, tile_flags, bo);
if (ret)
diff --git a/src/nv_type.h b/src/nv_type.h
index 4204556..c73c156 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -156,6 +156,7 @@ typedef struct _NVPortPrivRec {
#define NOUVEAU_CREATE_PIXMAP_ZETA 0x10000000
#define NOUVEAU_CREATE_PIXMAP_TILED 0x20000000
#define NOUVEAU_CREATE_PIXMAP_SCANOUT 0x40000000
+#define NOUVEAU_CREATE_PIXMAP_VIDEO 0x80000000
struct nouveau_pixmap {
struct nouveau_bo *bo;
diff --git a/src/nvc0_xv.c b/src/nvc0_xv.c
index 41ec7a8..149eaaf 100644
--- a/src/nvc0_xv.c
+++ b/src/nvc0_xv.c
@@ -343,7 +343,7 @@ nvc0_xv_image_put(ScrnInfoPtr pScrn,
if (!nvc0_xv_state_emit(ppix, id, src, packed_y, uv, width, height))
return BadAlloc;
- if (0 && pPriv->SyncToVBlank) {
+ if (0 && pPriv && pPriv->SyncToVBlank) {
NV50SyncToVBlank(ppix, dstBox);
}
--
1.7.5.4
More information about the xorg-devel
mailing list