radeonsi: set a better NUM_PATCHES hard limit
[mesa.git] / src / gallium / drivers / nouveau / nouveau_vp3_video.c
index a3387b3e5652f27ef97ef29e35ccf96d97290add..e7a63181de825f6b3c64d66235e0bef23aa8397a 100644 (file)
  */
 
 #include <sys/mman.h>
+#include <sys/stat.h>
 #include <stdio.h>
 #include <fcntl.h>
 
+#include <nvif/class.h>
+
 #include "nouveau_screen.h"
 #include "nouveau_context.h"
 #include "nouveau_vp3_video.h"
@@ -82,10 +85,10 @@ nouveau_vp3_video_buffer_create(struct pipe_context *pipe,
    struct pipe_sampler_view sv_templ;
    struct pipe_surface surf_templ;
 
-   assert(templat->interlaced);
    if (getenv("XVMC_VL") || templat->buffer_format != PIPE_FORMAT_NV12)
       return vl_video_buffer_create(pipe, templat);
 
+   assert(templat->interlaced);
    assert(templat->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420);
 
    buffer = CALLOC_STRUCT(nouveau_vp3_video_buffer);
@@ -138,8 +141,8 @@ nouveau_vp3_video_buffer_create(struct pipe_context *pipe,
          goto error;
 
       for (j = 0; j < nr_components; ++j, ++component) {
-         sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = PIPE_SWIZZLE_RED + j;
-         sv_templ.swizzle_a = PIPE_SWIZZLE_ONE;
+         sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = PIPE_SWIZZLE_X + j;
+         sv_templ.swizzle_a = PIPE_SWIZZLE_1;
 
          buffer->sampler_view_components[component] = pipe->create_sampler_view(pipe, res, &sv_templ);
          if (!buffer->sampler_view_components[component])
@@ -169,26 +172,26 @@ error:
 }
 
 static void
-nouveau_vp3_decoder_flush(struct pipe_video_decoder *decoder)
+nouveau_vp3_decoder_flush(struct pipe_video_codec *decoder)
 {
 }
 
 static void
-nouveau_vp3_decoder_begin_frame(struct pipe_video_decoder *decoder,
+nouveau_vp3_decoder_begin_frame(struct pipe_video_codec *decoder,
                                 struct pipe_video_buffer *target,
                                 struct pipe_picture_desc *picture)
 {
 }
 
 static void
-nouveau_vp3_decoder_end_frame(struct pipe_video_decoder *decoder,
+nouveau_vp3_decoder_end_frame(struct pipe_video_codec *decoder,
                               struct pipe_video_buffer *target,
                               struct pipe_picture_desc *picture)
 {
 }
 
 static void
-nouveau_vp3_decoder_destroy(struct pipe_video_decoder *decoder)
+nouveau_vp3_decoder_destroy(struct pipe_video_codec *decoder)
 {
    struct nouveau_vp3_decoder *dec = (struct nouveau_vp3_decoder *)decoder;
    int i;
@@ -223,7 +226,7 @@ nouveau_vp3_decoder_destroy(struct pipe_video_decoder *decoder)
 }
 
 void
-nouveau_vp3_decoder_init_common(struct pipe_video_decoder *dec)
+nouveau_vp3_decoder_init_common(struct pipe_video_codec *dec)
 {
    dec->destroy = nouveau_vp3_decoder_destroy;
    dec->flush = nouveau_vp3_decoder_flush;
@@ -231,22 +234,41 @@ nouveau_vp3_decoder_init_common(struct pipe_video_decoder *dec)
    dec->end_frame = nouveau_vp3_decoder_end_frame;
 }
 
+static void vp3_getpath(enum pipe_video_profile profile, char *path)
+{
+   switch (u_reduce_video_profile(profile)) {
+      case PIPE_VIDEO_FORMAT_MPEG12: {
+         sprintf(path, "/lib/firmware/nouveau/vuc-vp3-mpeg12-0");
+         break;
+      }
+      case PIPE_VIDEO_FORMAT_VC1: {
+         sprintf(path, "/lib/firmware/nouveau/vuc-vp3-vc1-0");
+         break;
+      }
+      case PIPE_VIDEO_FORMAT_MPEG4_AVC: {
+         sprintf(path, "/lib/firmware/nouveau/vuc-vp3-h264-0");
+         break;
+      }
+      default: assert(0);
+   }
+}
+
 static void vp4_getpath(enum pipe_video_profile profile, char *path)
 {
    switch (u_reduce_video_profile(profile)) {
-      case PIPE_VIDEO_CODEC_MPEG12: {
+      case PIPE_VIDEO_FORMAT_MPEG12: {
          sprintf(path, "/lib/firmware/nouveau/vuc-mpeg12-0");
          break;
       }
-      case PIPE_VIDEO_CODEC_MPEG4: {
+      case PIPE_VIDEO_FORMAT_MPEG4: {
          sprintf(path, "/lib/firmware/nouveau/vuc-mpeg4-0");
          break;
       }
-      case PIPE_VIDEO_CODEC_VC1: {
+      case PIPE_VIDEO_FORMAT_VC1: {
          sprintf(path, "/lib/firmware/nouveau/vuc-vc1-0");
          break;
       }
-      case PIPE_VIDEO_CODEC_MPEG4_AVC: {
+      case PIPE_VIDEO_FORMAT_MPEG4_AVC: {
          sprintf(path, "/lib/firmware/nouveau/vuc-h264-0");
          break;
       }
@@ -264,7 +286,10 @@ nouveau_vp3_load_firmware(struct nouveau_vp3_decoder *dec,
    ssize_t r;
    uint32_t *end, endval;
 
-   vp4_getpath(profile, path);
+   if (chipset >= 0xa3 && chipset != 0xaa && chipset != 0xac)
+      vp4_getpath(profile, path);
+   else
+      vp3_getpath(profile, path);
 
    if (nouveau_bo_map(dec->fw_bo, NOUVEAU_BO_WR, dec->client))
       return 1;
@@ -300,22 +325,22 @@ nouveau_vp3_load_firmware(struct nouveau_vp3_decoder *dec,
    r = (intptr_t)end - (intptr_t)dec->fw_bo->map + 4;
 
    switch (u_reduce_video_profile(profile)) {
-      case PIPE_VIDEO_CODEC_MPEG12: {
+      case PIPE_VIDEO_FORMAT_MPEG12: {
          assert((r & 0xff) == 0xe0);
          dec->fw_sizes = (0x2e0<<16) | (r - 0x2e0);
          break;
       }
-      case PIPE_VIDEO_CODEC_MPEG4: {
+      case PIPE_VIDEO_FORMAT_MPEG4: {
          assert((r & 0xff) == 0xe0);
          dec->fw_sizes = (0x2e0<<16) | (r - 0x2e0);
          break;
       }
-      case PIPE_VIDEO_CODEC_VC1: {
+      case PIPE_VIDEO_FORMAT_VC1: {
          assert((r & 0xff) == 0xac);
          dec->fw_sizes = (0x3ac<<16) | (r - 0x3ac);
          break;
       }
-      case PIPE_VIDEO_CODEC_MPEG4_AVC: {
+      case PIPE_VIDEO_FORMAT_MPEG4_AVC: {
          assert((r & 0xff) == 0x70);
          dec->fw_sizes = (0x370<<16) | (r - 0x370);
          break;
@@ -327,3 +352,154 @@ nouveau_vp3_load_firmware(struct nouveau_vp3_decoder *dec,
    dec->fw_bo->map = NULL;
    return 0;
 }
+
+static const struct nouveau_mclass
+nouveau_decoder_msvld[] = {
+   { G98_MSVLD, -1 },
+   { IGT21A_MSVLD, -1 },
+   { GT212_MSVLD, -1 },
+   { GF100_MSVLD, -1 },
+   { GK104_MSVLD, -1 },
+   {}
+};
+
+static int
+firmware_present(struct pipe_screen *pscreen, enum pipe_video_profile profile)
+{
+   struct nouveau_screen *screen = nouveau_screen(pscreen);
+   int chipset = screen->device->chipset;
+   int vp3 = chipset < 0xa3 || chipset == 0xaa || chipset == 0xac;
+   int vp5 = chipset >= 0xd0;
+   int ret;
+
+   /* For all chipsets, try to create a BSP objects. Assume that if firmware
+    * is present for it, firmware is also present for VP/PPP */
+   if (!(screen->firmware_info.profiles_checked & 1)) {
+      struct nouveau_object *channel = NULL, *bsp = NULL;
+      struct nv04_fifo nv04_data = {.vram = 0xbeef0201, .gart = 0xbeef0202};
+      struct nvc0_fifo nvc0_args = {};
+      struct nve0_fifo nve0_args = {.engine = NVE0_FIFO_ENGINE_BSP};
+      void *data = NULL;
+      int size;
+
+      if (chipset < 0xc0) {
+         data = &nv04_data;
+         size = sizeof(nv04_data);
+      } else if (chipset < 0xe0) {
+         data = &nvc0_args;
+         size = sizeof(nvc0_args);
+      } else {
+         data = &nve0_args;
+         size = sizeof(nve0_args);
+      }
+
+      /* kepler must have its own channel, so just do this for everyone */
+      nouveau_object_new(&screen->device->object, 0,
+                         NOUVEAU_FIFO_CHANNEL_CLASS,
+                         data, size, &channel);
+
+      if (channel) {
+         ret = nouveau_object_mclass(channel, nouveau_decoder_msvld);
+         if (ret >= 0)
+            nouveau_object_new(channel, 0, nouveau_decoder_msvld[ret].oclass,
+                               NULL, 0, &bsp);
+         if (bsp)
+            screen->firmware_info.profiles_present |= 1;
+         nouveau_object_del(&bsp);
+         nouveau_object_del(&channel);
+      }
+      screen->firmware_info.profiles_checked |= 1;
+   }
+
+   if (!(screen->firmware_info.profiles_present & 1))
+      return 0;
+
+   /* For vp3/vp4 chipsets, make sure that the relevant firmware is present */
+   if (!vp5 && !(screen->firmware_info.profiles_checked & (1 << profile))) {
+      char path[PATH_MAX];
+      struct stat s;
+      if (vp3)
+         vp3_getpath(profile, path);
+      else
+         vp4_getpath(profile, path);
+      ret = stat(path, &s);
+      if (!ret && s.st_size > 1000)
+         screen->firmware_info.profiles_present |= (1 << profile);
+      screen->firmware_info.profiles_checked |= (1 << profile);
+   }
+
+   return vp5 || (screen->firmware_info.profiles_present & (1 << profile));
+}
+
+int
+nouveau_vp3_screen_get_video_param(struct pipe_screen *pscreen,
+                                   enum pipe_video_profile profile,
+                                   enum pipe_video_entrypoint entrypoint,
+                                   enum pipe_video_cap param)
+{
+   int chipset = nouveau_screen(pscreen)->device->chipset;
+   int vp3 = chipset < 0xa3 || chipset == 0xaa || chipset == 0xac;
+   int vp5 = chipset >= 0xd0;
+   enum pipe_video_format codec = u_reduce_video_profile(profile);
+   switch (param) {
+   case PIPE_VIDEO_CAP_SUPPORTED:
+      /* VP3 does not support MPEG4, VP4+ do. */
+      return entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM &&
+         profile >= PIPE_VIDEO_PROFILE_MPEG1 &&
+         profile < PIPE_VIDEO_PROFILE_HEVC_MAIN &&
+         (!vp3 || codec != PIPE_VIDEO_FORMAT_MPEG4) &&
+         firmware_present(pscreen, profile);
+   case PIPE_VIDEO_CAP_NPOT_TEXTURES:
+      return 1;
+   case PIPE_VIDEO_CAP_MAX_WIDTH:
+   case PIPE_VIDEO_CAP_MAX_HEIGHT:
+      return vp5 ? 4096 : 2048;
+   case PIPE_VIDEO_CAP_PREFERED_FORMAT:
+      return PIPE_FORMAT_NV12;
+   case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:
+   case PIPE_VIDEO_CAP_PREFERS_INTERLACED:
+      return true;
+   case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE:
+      return false;
+   case PIPE_VIDEO_CAP_MAX_LEVEL:
+      switch (profile) {
+      case PIPE_VIDEO_PROFILE_MPEG1:
+         return 0;
+      case PIPE_VIDEO_PROFILE_MPEG2_SIMPLE:
+      case PIPE_VIDEO_PROFILE_MPEG2_MAIN:
+         return 3;
+      case PIPE_VIDEO_PROFILE_MPEG4_SIMPLE:
+         return 3;
+      case PIPE_VIDEO_PROFILE_MPEG4_ADVANCED_SIMPLE:
+         return 5;
+      case PIPE_VIDEO_PROFILE_VC1_SIMPLE:
+         return 1;
+      case PIPE_VIDEO_PROFILE_VC1_MAIN:
+         return 2;
+      case PIPE_VIDEO_PROFILE_VC1_ADVANCED:
+         return 4;
+      case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
+      case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
+      case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
+         return 41;
+      default:
+         debug_printf("unknown video profile: %d\n", profile);
+         return 0;
+      }
+   default:
+      debug_printf("unknown video param: %d\n", param);
+      return 0;
+   }
+}
+
+boolean
+nouveau_vp3_screen_video_supported(struct pipe_screen *screen,
+                                   enum pipe_format format,
+                                   enum pipe_video_profile profile,
+                                   enum pipe_video_entrypoint entrypoint)
+{
+   if (profile != PIPE_VIDEO_PROFILE_UNKNOWN)
+      return format == PIPE_FORMAT_NV12;
+
+   return vl_video_buffer_is_format_supported(screen, format, profile, entrypoint);
+}