* OTHER DEALINGS IN THE SOFTWARE.
*/
+#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"
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);
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])
nouveau_vp3_video_buffer_destroy(&buffer->base);
return NULL;
}
+
+static void
+nouveau_vp3_decoder_flush(struct pipe_video_codec *decoder)
+{
+}
+
+static void
+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_codec *decoder,
+ struct pipe_video_buffer *target,
+ struct pipe_picture_desc *picture)
+{
+}
+
+static void
+nouveau_vp3_decoder_destroy(struct pipe_video_codec *decoder)
+{
+ struct nouveau_vp3_decoder *dec = (struct nouveau_vp3_decoder *)decoder;
+ int i;
+
+ nouveau_bo_ref(NULL, &dec->ref_bo);
+ nouveau_bo_ref(NULL, &dec->bitplane_bo);
+ nouveau_bo_ref(NULL, &dec->inter_bo[0]);
+ nouveau_bo_ref(NULL, &dec->inter_bo[1]);
+#if NOUVEAU_VP3_DEBUG_FENCE
+ nouveau_bo_ref(NULL, &dec->fence_bo);
+#endif
+ nouveau_bo_ref(NULL, &dec->fw_bo);
+
+ for (i = 0; i < NOUVEAU_VP3_VIDEO_QDEPTH; ++i)
+ nouveau_bo_ref(NULL, &dec->bsp_bo[i]);
+
+ nouveau_object_del(&dec->bsp);
+ nouveau_object_del(&dec->vp);
+ nouveau_object_del(&dec->ppp);
+
+ if (dec->channel[0] != dec->channel[1]) {
+ for (i = 0; i < 3; ++i) {
+ nouveau_pushbuf_del(&dec->pushbuf[i]);
+ nouveau_object_del(&dec->channel[i]);
+ }
+ } else {
+ nouveau_pushbuf_del(dec->pushbuf);
+ nouveau_object_del(dec->channel);
+ }
+
+ FREE(dec);
+}
+
+void
+nouveau_vp3_decoder_init_common(struct pipe_video_codec *dec)
+{
+ dec->destroy = nouveau_vp3_decoder_destroy;
+ dec->flush = nouveau_vp3_decoder_flush;
+ dec->begin_frame = nouveau_vp3_decoder_begin_frame;
+ 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_FORMAT_MPEG12: {
+ sprintf(path, "/lib/firmware/nouveau/vuc-mpeg12-0");
+ break;
+ }
+ case PIPE_VIDEO_FORMAT_MPEG4: {
+ sprintf(path, "/lib/firmware/nouveau/vuc-mpeg4-0");
+ break;
+ }
+ case PIPE_VIDEO_FORMAT_VC1: {
+ sprintf(path, "/lib/firmware/nouveau/vuc-vc1-0");
+ break;
+ }
+ case PIPE_VIDEO_FORMAT_MPEG4_AVC: {
+ sprintf(path, "/lib/firmware/nouveau/vuc-h264-0");
+ break;
+ }
+ default: assert(0);
+ }
+}
+
+int
+nouveau_vp3_load_firmware(struct nouveau_vp3_decoder *dec,
+ enum pipe_video_profile profile,
+ unsigned chipset)
+{
+ int fd;
+ char path[PATH_MAX];
+ ssize_t r;
+ uint32_t *end, endval;
+
+ 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;
+
+ fd = open(path, O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ fprintf(stderr, "opening firmware file %s failed: %m\n", path);
+ return 1;
+ }
+ r = read(fd, dec->fw_bo->map, 0x4000);
+ close(fd);
+
+ if (r < 0) {
+ fprintf(stderr, "reading firmware file %s failed: %m\n", path);
+ return 1;
+ }
+
+ if (r == 0x4000) {
+ fprintf(stderr, "firmware file %s too large!\n", path);
+ return 1;
+ }
+
+ if (r & 0xff) {
+ fprintf(stderr, "firmware file %s wrong size!\n", path);
+ return 1;
+ }
+
+ end = dec->fw_bo->map + r - 4;
+ endval = *end;
+ while (endval == *end)
+ end--;
+
+ r = (intptr_t)end - (intptr_t)dec->fw_bo->map + 4;
+
+ switch (u_reduce_video_profile(profile)) {
+ case PIPE_VIDEO_FORMAT_MPEG12: {
+ assert((r & 0xff) == 0xe0);
+ dec->fw_sizes = (0x2e0<<16) | (r - 0x2e0);
+ break;
+ }
+ case PIPE_VIDEO_FORMAT_MPEG4: {
+ assert((r & 0xff) == 0xe0);
+ dec->fw_sizes = (0x2e0<<16) | (r - 0x2e0);
+ break;
+ }
+ case PIPE_VIDEO_FORMAT_VC1: {
+ assert((r & 0xff) == 0xac);
+ dec->fw_sizes = (0x3ac<<16) | (r - 0x3ac);
+ break;
+ }
+ case PIPE_VIDEO_FORMAT_MPEG4_AVC: {
+ assert((r & 0xff) == 0x70);
+ dec->fw_sizes = (0x370<<16) | (r - 0x370);
+ break;
+ }
+ default:
+ return 1;
+ }
+ munmap(dec->fw_bo->map, dec->fw_bo->size);
+ 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);
+}