[Mesa-dev] [PATCH] nouveau: Add support for hardware video decoding
Marcin Slusarz
marcin.slusarz at gmail.com
Fri Sep 2 10:12:53 PDT 2011
On Fri, Sep 02, 2011 at 06:15:00PM +0200, Maarten Lankhorst wrote:
> Try to use the PMPEG where available
>
> Signed-off-by: Maarten Lankhorst <m.b.lankhorst at gmail.com>
>
> ---
> diff --git a/src/gallium/drivers/nouveau/nouveau_video.c b/src/gallium/drivers/nouveau/nouveau_video.c
> index 620c030..2b90056 100644
> --- a/src/gallium/drivers/nouveau/nouveau_video.c
> +++ b/src/gallium/drivers/nouveau/nouveau_video.c
(...)
> +
> +static unsigned
> +nouveau_decoder_surface_index(struct nouveau_decoder *dec,
> + struct pipe_video_buffer *buffer)
> +{
> + struct nouveau_video_buffer *buf = (struct nouveau_video_buffer *)buffer;
> + struct nouveau_channel *chan = dec->screen->channel;
> + struct nouveau_bo *bo_y, *bo_c;
> + unsigned i;
> +
> + if (!buf)
> + return 8;
> + for (i = 0; i < dec->num_surfaces; ++i) {
> + if (dec->surfaces[i] == buf)
> + return i;
> + }
> + assert(i < 8);
> + dec->surfaces[i] = buf;
> + dec->num_surfaces++;
> +
> + if (dec->screen->device->chipset < 0x50) {
> + bo_y = ((struct nvfx_resource *)buf->resources[0])->bo;
> + bo_c = ((struct nvfx_resource *)buf->resources[1])->bo;
> + } else {
> + bo_y = ((struct nv04_resource *)buf->resources[0])->bo;
> + bo_c = ((struct nv04_resource *)buf->resources[1])->bo;
> + }
This is not going to work for nv6x's - they are nv40-class cards (IGPs IIRC)
and are handled by nvfx driver
> + MARK_RING(chan, 3, 2);
> + BEGIN_RING(chan, dec->mpeg, NV31_MPEG_IMAGE_Y_OFFSET(i), 2);
> + OUT_RELOCl(chan, bo_y, 0, NOUVEAU_BO_RDWR);
> + OUT_RELOCl(chan, bo_c, 0, NOUVEAU_BO_RDWR);
> + return i;
> +}
> +
(...)
> +
> +static struct pipe_video_decoder *
> +nouveau_create_decoder(struct pipe_context *context,
> + struct nouveau_screen *screen,
> + enum pipe_video_profile profile,
> + enum pipe_video_entrypoint entrypoint,
> + enum pipe_video_chroma_format chroma_format,
> + unsigned width, unsigned height)
> +{
> + struct nouveau_channel *chan = screen->channel;
> + struct nouveau_grobj *mpeg = NULL;
> + struct nouveau_decoder *dec;
> + int ret;
> +
> + debug_printf("Acceleration level: %s\n", entrypoint <= PIPE_VIDEO_ENTRYPOINT_BITSTREAM ? "bit":
> + entrypoint == PIPE_VIDEO_ENTRYPOINT_IDCT ? "IDCT" : "MC");
> +
> + if (getenv("XVMC_VL"))
> + goto vl;
> + if (u_reduce_video_profile(profile) != PIPE_VIDEO_CODEC_MPEG12)
> + goto vl;
> + if (screen->device->chipset >= 0x98 && screen->device->chipset != 0xa0)
> + goto vl;
> +
> + width = align(width, 64);
> + height = align(height, 64);
> +
> + if (screen->device->chipset > 0x50)
> + ret = nouveau_grobj_alloc(chan, 0xbeef8274, 0x8274, &mpeg);
> + else
> + ret = nouveau_grobj_alloc(chan, 0xbeef8274, 0x3174, &mpeg);
As above. You want to check for > 0x80.
> + if (ret < 0) {
> + debug_printf("Creation failed: %s (%i)\n", strerror(-ret), ret);
> + return NULL;
> + }
> +
> + dec = CALLOC_STRUCT(nouveau_decoder);
> + if (!dec) {
> + nouveau_grobj_free(&mpeg);
> + goto fail;
> + }
> + dec->mpeg = mpeg;
> + dec->base.context = context;
> + dec->base.profile = profile;
> + dec->base.entrypoint = entrypoint;
> + dec->base.chroma_format = chroma_format;
> + dec->base.width = width;
> + dec->base.height = height;
> + dec->base.destroy = nouveau_decoder_destroy;
> + dec->base.begin_frame = nouveau_decoder_begin_frame;
> + dec->base.end_frame = nouveau_decoder_end_frame;
> + dec->base.set_decode_target = nouveau_decoder_set_decode_target;
> + dec->base.set_picture_parameters = nouveau_decoder_set_picture_parameters;
> + dec->base.set_reference_frames = nouveau_decoder_set_reference_frames;
> + dec->base.decode_macroblock = nouveau_decoder_decode_macroblock;
> + dec->base.flush = nouveau_decoder_flush;
> + dec->screen = screen;
> +
> + ret = nouveau_bo_new(dec->screen->device, NOUVEAU_BO_GART, 0, 1024 * 1024, &dec->cmd_bo);
> + if (ret)
> + goto fail;
> +
> + ret = nouveau_bo_new(dec->screen->device, NOUVEAU_BO_GART, 0, width * height * 6, &dec->data_bo);
> + if (ret)
> + goto fail;
> +
> + ret = nouveau_bo_new(dec->screen->device, NOUVEAU_BO_GART|NOUVEAU_BO_MAP, 0, 4096,
> + &dec->fence_bo);
> + if (ret)
> + goto fail;
> + nouveau_bo_map(dec->fence_bo, NOUVEAU_BO_RDWR);
> + dec->fence_map = dec->fence_bo->map;
> + nouveau_bo_unmap(dec->fence_bo);
> + dec->fence_map[0] = 0;
> +
> + if (dec->screen->device->chipset > 0x50)
> + MARK_RING(chan, 25, 3);
> + else
> + MARK_RING(chan, 20, 2);
> +
Again s/0x50/0x80.
> + BEGIN_RING(chan, mpeg, NV31_MPEG_DMA_CMD, 1);
> + OUT_RING(chan, chan->vram->handle);
> +
> + BEGIN_RING(chan, mpeg, NV31_MPEG_DMA_DATA, 1);
> + OUT_RING(chan, chan->vram->handle);
> +
> + BEGIN_RING(chan, mpeg, NV31_MPEG_DMA_IMAGE, 1);
> + OUT_RING(chan, chan->vram->handle);
> +
> + BEGIN_RING(chan, mpeg, NV31_MPEG_PITCH, 2);
> + OUT_RING(chan, width | NV31_MPEG_PITCH_UNK);
> + OUT_RING(chan, (height << NV31_MPEG_SIZE_H__SHIFT) | width);
> +
> + BEGIN_RING(chan, mpeg, NV31_MPEG_FORMAT, 2);
> + OUT_RING(chan, 0);
> + switch (entrypoint) {
> + case PIPE_VIDEO_ENTRYPOINT_BITSTREAM: OUT_RING(chan, 0x100); break;
> + case PIPE_VIDEO_ENTRYPOINT_IDCT: OUT_RING(chan, 1); break;
> + case PIPE_VIDEO_ENTRYPOINT_MC: OUT_RING(chan, 0); break;
> + default: assert(0);
> + }
> +
> + if (dec->screen->device->chipset > 0x50) {
> + BEGIN_RING(chan, mpeg, NV84_MPEG_DMA_QUERY, 1);
> + OUT_RING(chan, chan->vram->handle);
> +
> + BEGIN_RING(chan, mpeg, NV84_MPEG_QUERY_OFFSET, 2);
> + OUT_RELOCl(chan, dec->fence_bo, 0, NOUVEAU_BO_WR|NOUVEAU_BO_GART);
> + OUT_RING(chan, dec->fence_seq);
> + }
And here.
> +
> + ret = nouveau_vpe_init(dec);
> + if (ret)
> + goto fail;
> + nouveau_vpe_fini(dec);
> + return &dec->base;
> +
> +fail:
> + nouveau_decoder_destroy(&dec->base);
> + return NULL;
> +
> +vl:
> + debug_printf("Using g3dvl renderer\n");
> + return vl_create_decoder(context, profile, entrypoint,
> + chroma_format, width, height);
> +}
> +
More information about the mesa-dev
mailing list