[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