summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2018-04-23 18:32:19 +0200
committerThierry Reding <treding@nvidia.com>2019-08-23 18:08:32 +0200
commit368e571a6857a591b585eb0c86b2bc8b428f64ca (patch)
treeee5de36674ddac377e88efa7c9adee7abcb0da49
parent4632b0ecbbfdc53b0101523a108611c419a31d8d (diff)
WIP: tegra: Add VDE support
-rw-r--r--src/gallium/drivers/tegra/Makefile.sources5
-rw-r--r--src/gallium/drivers/tegra/meson.build5
-rw-r--r--src/gallium/drivers/tegra/tegra_context.c33
-rw-r--r--src/gallium/drivers/tegra/tegra_context.h1
-rw-r--r--src/gallium/drivers/tegra/tegra_screen.c26
-rw-r--r--src/gallium/drivers/tegra/tegra_screen.h3
-rw-r--r--src/gallium/drivers/tegra/tegra_vde.c1690
-rw-r--r--src/gallium/drivers/tegra/tegra_vde.h33
-rw-r--r--src/gallium/drivers/tegra/tegra_vde_uabi.h82
9 files changed, 1872 insertions, 6 deletions
diff --git a/src/gallium/drivers/tegra/Makefile.sources b/src/gallium/drivers/tegra/Makefile.sources
index af4ff838c7ca..0262a94c6c9c 100644
--- a/src/gallium/drivers/tegra/Makefile.sources
+++ b/src/gallium/drivers/tegra/Makefile.sources
@@ -3,4 +3,7 @@ C_SOURCES := \
tegra_context.h \
tegra_resource.h \
tegra_screen.c \
- tegra_screen.h
+ tegra_screen.h \
+ tegra_vde.c \
+ tegra_vde.h \
+ tegra_vde_uabi.h
diff --git a/src/gallium/drivers/tegra/meson.build b/src/gallium/drivers/tegra/meson.build
index 939d6294601c..48c754afc53a 100644
--- a/src/gallium/drivers/tegra/meson.build
+++ b/src/gallium/drivers/tegra/meson.build
@@ -23,6 +23,9 @@ files_tegra = files(
'tegra_context.h',
'tegra_resource.h',
'tegra_screen.c',
+ 'tegra_vde.h',
+ 'tegra_vde.c',
+ 'tegra_vde_uabi.h',
)
libtegra = static_library(
@@ -33,7 +36,7 @@ libtegra = static_library(
inc_include, inc_src, inc_gallium, inc_gallium_aux, inc_gallium_drivers,
inc_gallium_winsys,
],
- dependencies : dep_libdrm,
+ dependencies : [dep_libdrm, dep_libdrm_tegra],
)
driver_tegra = declare_dependency(
diff --git a/src/gallium/drivers/tegra/tegra_context.c b/src/gallium/drivers/tegra/tegra_context.c
index f9a1c55a7c98..cbc7579671bc 100644
--- a/src/gallium/drivers/tegra/tegra_context.c
+++ b/src/gallium/drivers/tegra/tegra_context.c
@@ -40,6 +40,9 @@ tegra_destroy(struct pipe_context *pcontext)
if (context->base.stream_uploader)
u_upload_destroy(context->base.stream_uploader);
+ if (context->vde)
+ context->vde->destroy(context->vde);
+
context->gpu->destroy(context->gpu);
free(context);
}
@@ -988,11 +991,18 @@ tegra_create_video_codec(struct pipe_context *pcontext,
struct tegra_context *context = to_tegra_context(pcontext);
struct pipe_video_codec *codec = NULL;
- printf("> %s(pcontext=%p, template=%p)\n", __func__, pcontext, template);
+ debug_printf("> %s(pcontext=%p, template=%p)\n", __func__, pcontext,
+ template);
+
+ if (context->vde) {
+ codec = context->vde->create_video_codec(context->vde, template);
+ goto out;
+ }
codec = context->gpu->create_video_codec(context->gpu, template);
- printf("< %s() = %p\n", __func__, codec);
+out:
+ debug_printf("< %s() = %p\n", __func__, codec);
return codec;
}
@@ -1003,11 +1013,18 @@ tegra_create_video_buffer(struct pipe_context *pcontext,
struct tegra_context *context = to_tegra_context(pcontext);
struct pipe_video_buffer *buffer = NULL;
- printf("> %s(pcontext=%p, template=%p)\n", __func__, pcontext, template);
+ debug_printf("> %s(pcontext=%p, template=%p)\n", __func__, pcontext,
+ template);
+
+ if (context->vde) {
+ buffer = context->vde->create_video_buffer(context->vde, template);
+ goto out;
+ }
buffer = context->gpu->create_video_buffer(context->gpu, template);
- printf("< %s() = %p\n", __func__, buffer);
+out:
+ debug_printf("< %s() = %p\n", __func__, buffer);
return buffer;
}
@@ -1220,6 +1237,9 @@ tegra_screen_context_create(struct pipe_screen *pscreen, void *priv,
struct tegra_screen *screen = to_tegra_screen(pscreen);
struct tegra_context *context;
+ if (screen->vde && (flags & PIPE_CONTEXT_VIDEO_ONLY))
+ return screen->vde->context_create(screen->vde, NULL, 0);
+
context = calloc(1, sizeof(*context));
if (!context)
return NULL;
@@ -1230,6 +1250,11 @@ tegra_screen_context_create(struct pipe_screen *pscreen, void *priv,
goto free;
}
+ /*
+ if (screen->vde)
+ context->vde = screen->vde->context_create(screen->vde, NULL, 0);
+ */
+
context->base.screen = &screen->base;
context->base.priv = priv;
diff --git a/src/gallium/drivers/tegra/tegra_context.h b/src/gallium/drivers/tegra/tegra_context.h
index 4869b0913a6f..650bce320dda 100644
--- a/src/gallium/drivers/tegra/tegra_context.h
+++ b/src/gallium/drivers/tegra/tegra_context.h
@@ -32,6 +32,7 @@ struct tegra_screen;
struct tegra_context {
struct pipe_context base;
struct pipe_context *gpu;
+ struct pipe_context *vde;
};
static inline struct tegra_context *
diff --git a/src/gallium/drivers/tegra/tegra_screen.c b/src/gallium/drivers/tegra/tegra_screen.c
index ef495cd5c14b..6637cc267fdb 100644
--- a/src/gallium/drivers/tegra/tegra_screen.c
+++ b/src/gallium/drivers/tegra/tegra_screen.c
@@ -31,6 +31,7 @@
#include "drm-uapi/drm_fourcc.h"
#include "drm-uapi/tegra_drm.h"
#include <xf86drm.h>
+#include <tegra.h>
#include "loader/loader.h"
#include "pipe/p_state.h"
@@ -47,12 +48,17 @@
#include "tegra_context.h"
#include "tegra_resource.h"
#include "tegra_screen.h"
+#include "tegra_vde.h"
static void tegra_screen_destroy(struct pipe_screen *pscreen)
{
struct tegra_screen *screen = to_tegra_screen(pscreen);
+ if (screen->vde)
+ screen->vde->destroy(screen->vde);
+
screen->gpu->destroy(screen->gpu);
+ drm_tegra_close(screen->drm);
free(pscreen);
}
@@ -105,6 +111,12 @@ tegra_screen_get_video_param(struct pipe_screen *pscreen,
enum pipe_video_entrypoint entrypoint,
enum pipe_video_cap param)
{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ if (screen->vde)
+ return screen->vde->get_video_param(screen->vde, profile, entrypoint,
+ param);
+
switch (param) {
case PIPE_VIDEO_CAP_SUPPORTED:
if (u_reduce_video_profile(profile) == PIPE_VIDEO_FORMAT_JPEG)
@@ -188,6 +200,10 @@ tegra_screen_is_video_format_supported(struct pipe_screen *pscreen,
{
struct tegra_screen *screen = to_tegra_screen(pscreen);
+ if (screen->vde)
+ return screen->vde->is_video_format_supported(screen->vde, format,
+ profile, entrypoint);
+
return screen->gpu->is_video_format_supported(screen->gpu, format, profile,
entrypoint);
}
@@ -566,6 +582,7 @@ struct pipe_screen *
tegra_screen_create(int fd)
{
struct tegra_screen *screen;
+ int err;
screen = calloc(1, sizeof(*screen));
if (!screen)
@@ -573,6 +590,12 @@ tegra_screen_create(int fd)
screen->fd = fd;
+ err = drm_tegra_new(&screen->drm, fd);
+ if (err < 0) {
+ free(screen);
+ return NULL;
+ }
+
screen->gpu_fd = loader_open_render_node("nouveau");
if (screen->gpu_fd < 0) {
if (errno != ENOENT)
@@ -590,6 +613,9 @@ tegra_screen_create(int fd)
return NULL;
}
+ /* VDE may not be present, so continue even if this fails */
+ screen->vde = tegra_vde_screen_create(&screen->base, screen->drm);
+
screen->base.destroy = tegra_screen_destroy;
screen->base.get_name = tegra_screen_get_name;
screen->base.get_vendor = tegra_screen_get_vendor;
diff --git a/src/gallium/drivers/tegra/tegra_screen.h b/src/gallium/drivers/tegra/tegra_screen.h
index 558d22f2f993..d03f934a13b3 100644
--- a/src/gallium/drivers/tegra/tegra_screen.h
+++ b/src/gallium/drivers/tegra/tegra_screen.h
@@ -28,10 +28,13 @@
struct tegra_screen {
struct pipe_screen base;
+ struct drm_tegra *drm;
int fd;
struct pipe_screen *gpu;
int gpu_fd;
+
+ struct pipe_screen *vde;
};
static inline struct tegra_screen *
diff --git a/src/gallium/drivers/tegra/tegra_vde.c b/src/gallium/drivers/tegra/tegra_vde.c
new file mode 100644
index 000000000000..fb52a57d32e4
--- /dev/null
+++ b/src/gallium/drivers/tegra/tegra_vde.c
@@ -0,0 +1,1690 @@
+/*
+ * Copyright © 2018 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+
+#include "pipe/p_video_codec.h"
+
+#include "util/u_debug.h"
+#include "util/u_format.h"
+#include "util/u_sampler.h"
+#include "util/u_transfer.h"
+#include "util/u_upload_mgr.h"
+#include "util/u_video.h"
+
+#include "state_tracker/drm_driver.h"
+
+#include "vl/vl_defines.h"
+#include "vl/vl_rbsp.h"
+#include "vl/vl_vlc.h"
+
+#include "tegra_vde_uabi.h"
+#include "tegra_vde.h"
+
+#include "tegra_drm.h"
+#include "tegra.h"
+
+struct tegra_vde_buffer {
+ struct pipe_video_buffer base;
+
+ struct pipe_sampler_view *components[VL_NUM_COMPONENTS];
+ struct pipe_resource *planes[VL_NUM_COMPONENTS];
+ struct pipe_surface *surfaces[VL_MAX_SURFACES];
+ unsigned int num_planes;
+
+ unsigned int frame_num;
+ enum pipe_h264_slice_type slice_type;
+ bool is_reference;
+
+ struct pipe_resource *aux;
+};
+
+static inline struct tegra_vde_buffer *
+to_tegra_vde_buffer(struct pipe_video_buffer *buffer)
+{
+ return (struct tegra_vde_buffer *)buffer;
+}
+
+struct tegra_vde_codec {
+ struct pipe_video_codec base;
+
+ struct drm_tegra *drm;
+ struct drm_tegra_bo *bitstream;
+ size_t bitstream_size;
+ struct drm_tegra_bo *secure;
+};
+
+static inline struct tegra_vde_codec *
+to_tegra_vde_codec(struct pipe_video_codec *codec)
+{
+ return (struct tegra_vde_codec *)codec;
+}
+
+struct tegra_vde_context {
+ struct pipe_context base;
+ struct pipe_context *gpu;
+};
+
+static inline struct tegra_vde_context *
+to_tegra_vde_context(struct pipe_context *context)
+{
+ return (struct tegra_vde_context *)context;
+}
+
+struct tegra_vde_sampler_view {
+ struct pipe_sampler_view base;
+};
+
+static inline struct tegra_vde_sampler_view *
+to_tegra_vde_sampler_view(struct pipe_sampler_view *view)
+{
+ return (struct tegra_vde_sampler_view *)view;
+}
+
+struct tegra_vde_surface {
+ struct pipe_surface base;
+};
+
+static inline struct tegra_vde_surface *
+to_tegra_vde_surface(struct pipe_surface *surface)
+{
+ return (struct tegra_vde_surface *)surface;
+}
+
+struct tegra_vde_resource {
+ struct pipe_resource base;
+ struct drm_tegra_bo *bo;
+ unsigned int stride;
+ unsigned int pitch;
+ size_t size;
+};
+
+static inline struct tegra_vde_resource *
+to_tegra_vde_resource(struct pipe_resource *resource)
+{
+ return (struct tegra_vde_resource *)resource;
+}
+
+struct tegra_vde_screen {
+ struct pipe_screen base;
+ struct pipe_screen *gpu;
+
+ struct drm_tegra *drm;
+ int fd;
+};
+
+static inline struct tegra_vde_screen *
+to_tegra_vde_screen(struct pipe_screen *screen)
+{
+ return (struct tegra_vde_screen *)screen;
+}
+
+/*
+ * video buffer implementation
+ */
+
+static void tegra_vde_buffer_destroy(struct pipe_video_buffer *pbuffer)
+{
+ struct tegra_vde_buffer *buffer = to_tegra_vde_buffer(pbuffer);
+ unsigned int i;
+
+ debug_printf("> %s(pbuffer=%p)\n", __func__, pbuffer);
+
+ if (buffer->surfaces) {
+ for (i = 0; i < buffer->num_planes; i++)
+ pipe_surface_reference(&buffer->surfaces[i], NULL);
+
+ free(buffer->surfaces);
+ }
+
+ pipe_resource_reference(&buffer->aux, NULL);
+
+ if (buffer->planes) {
+ for (i = 0; i < buffer->num_planes; i++)
+ pipe_resource_reference(&buffer->planes[i], NULL);
+
+ free(buffer->planes);
+ }
+
+ free(buffer);
+
+ debug_printf("< %s()\n", __func__);
+}
+
+static struct pipe_sampler_view **
+tegra_vde_buffer_get_sampler_view_planes(struct pipe_video_buffer *pbuffer)
+{
+ struct pipe_sampler_view **planes = NULL;
+
+ debug_printf("> %s(pbuffer=%p)\n", __func__, pbuffer);
+ debug_printf("< %s() = %p\n", __func__, planes);
+
+ return planes;
+}
+
+static struct pipe_sampler_view **
+tegra_vde_buffer_get_sampler_view_components(struct pipe_video_buffer *pbuffer)
+{
+ struct tegra_vde_buffer *buffer = to_tegra_vde_buffer(pbuffer);
+ struct pipe_sampler_view **components = NULL;
+ unsigned int i, j, component = 0;
+ struct pipe_sampler_view tmpl;
+
+ debug_printf("> %s(pbuffer=%p)\n", __func__, pbuffer);
+
+ for (i = 0; i < buffer->num_planes; i++) {
+ unsigned int num_components = util_format_get_nr_components(buffer->planes[i]->format);
+
+ for (j = 0; j < num_components; j++, component++) {
+ if (!buffer->components[component]) {
+ memset(&tmpl, 0, sizeof(tmpl));
+ u_sampler_view_default_template(&tmpl, buffer->planes[i], buffer->planes[i]->format);
+ tmpl.swizzle_r = tmpl.swizzle_g = tmpl.swizzle_b= PIPE_SWIZZLE_X + j;
+ tmpl.swizzle_a = PIPE_SWIZZLE_1;
+
+ buffer->components[component] = pbuffer->context->create_sampler_view(pbuffer->context, buffer->planes[i], &tmpl);
+ if (!buffer->components[component])
+ goto unref;
+ }
+ }
+ }
+
+ components = buffer->components;
+
+ debug_printf("< %s() = %p\n", __func__, components);
+
+ return components;
+
+unref:
+ for (i = 0; i < 3; i++)
+ pipe_sampler_view_reference(&buffer->components[i], NULL);
+
+ debug_printf("< %s() = NULL\n", __func__);
+ return NULL;
+}
+
+static struct pipe_surface **
+tegra_vde_buffer_get_surfaces(struct pipe_video_buffer *pbuffer)
+{
+ struct tegra_vde_buffer *buffer = to_tegra_vde_buffer(pbuffer);
+ struct pipe_context *context = pbuffer->context;
+ struct pipe_surface **surfaces = NULL;
+ struct pipe_surface tmpl;
+ unsigned int i;
+
+ debug_printf("> %s(pbuffer=%p)\n", __func__, pbuffer);
+
+ for (i = 0; i < buffer->num_planes; i++) {
+ if (!buffer->surfaces[i]) {
+ memset(&tmpl, 0, sizeof(tmpl));
+ tmpl.format = buffer->planes[i]->format;
+
+ buffer->surfaces[i] = context->create_surface(context,
+ buffer->planes[i],
+ &tmpl);
+ if (!buffer->surfaces[i])
+ goto unref;
+ }
+ }
+
+ surfaces = buffer->surfaces;
+
+ debug_printf("< %s() = %p\n", __func__, surfaces);
+
+ return surfaces;
+
+unref:
+ for (i = 0; i < buffer->num_planes; i++)
+ pipe_surface_reference(&buffer->surfaces[i], NULL);
+
+ return NULL;
+}
+
+static struct pipe_video_buffer *
+tegra_vde_create_video_buffer(struct pipe_context *pcontext,
+ const struct pipe_video_buffer *template)
+{
+ struct tegra_vde_buffer *buffer;
+ unsigned int width, height;
+ struct pipe_resource tmpl;
+
+ debug_printf("> %s(pcontext=%p, template=%p)\n", __func__, pcontext,
+ template);
+
+ buffer = calloc(1, sizeof(*buffer));
+ if (!buffer)
+ goto out;
+
+ width = align(template->width, 16);
+ height = align(template->height, 16);
+
+ buffer->base.context = pcontext;
+ buffer->base.buffer_format = template->buffer_format;
+ buffer->base.chroma_format = template->chroma_format;
+ buffer->base.width = width;
+ buffer->base.height = height;
+ buffer->base.interlaced = template->interlaced;
+ buffer->base.bind = template->bind;
+
+ buffer->base.destroy = tegra_vde_buffer_destroy;
+ buffer->base.get_sampler_view_planes = tegra_vde_buffer_get_sampler_view_planes;
+ buffer->base.get_sampler_view_components = tegra_vde_buffer_get_sampler_view_components;
+ buffer->base.get_surfaces = tegra_vde_buffer_get_surfaces;
+
+ /* XXX parameterize */
+ buffer->num_planes = 2;
+
+ memset(&tmpl, 0, sizeof(tmpl));
+ tmpl.target = PIPE_TEXTURE_2D;
+ tmpl.format = PIPE_FORMAT_R8_UNORM;
+ tmpl.width0 = width;
+ tmpl.height0 = height;
+ tmpl.depth0 = 1;
+ tmpl.array_size = 1;
+ tmpl.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
+ tmpl.usage = PIPE_USAGE_DEFAULT;
+ tmpl.flags = 0;
+
+ buffer->planes[0] = pcontext->screen->resource_create(pcontext->screen,
+ &tmpl);
+ if (!buffer->planes[0])
+ goto destroy;
+
+ tmpl.width0 /= 2;
+ tmpl.height0 /= 2;
+ tmpl.format = PIPE_FORMAT_R8G8_UNORM;
+
+ buffer->planes[1] = pcontext->screen->resource_create(pcontext->screen,
+ &tmpl);
+ if (!buffer->planes[1])
+ goto destroy;
+
+ tmpl.format = PIPE_FORMAT_R8_UNORM;
+
+ buffer->aux = pcontext->screen->resource_create(pcontext->screen, &tmpl);
+ if (!buffer->aux)
+ goto destroy;
+
+out:
+ debug_printf("< %s() = %p\n", __func__, buffer);
+ return buffer ? &buffer->base : NULL;
+
+destroy:
+ tegra_vde_buffer_destroy(&buffer->base);
+ debug_printf("< %s() = NULL\n", __func__);
+ return NULL;
+}
+
+/*
+ * codec implementation
+ */
+
+static void tegra_vde_codec_destroy(struct pipe_video_codec *codec)
+{
+ struct tegra_vde_codec *vde = to_tegra_vde_codec(codec);
+
+ debug_printf("> %s(codec=%p)\n", __func__, codec);
+
+ drm_tegra_bo_unref(vde->secure);
+ drm_tegra_bo_unref(vde->bitstream);
+ free(vde);
+
+ debug_printf("< %s()\n", __func__);
+}
+
+static void tegra_vde_codec_begin_frame(struct pipe_video_codec *codec,
+ struct pipe_video_buffer *buffer,
+ struct pipe_picture_desc *picture)
+{
+ debug_printf("> %s(codec=%p, buffer=%p, picture=%p)\n", __func__, codec,
+ buffer, picture);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_codec_decode_bitstream(struct pipe_video_codec *codec,
+ struct pipe_video_buffer *target,
+ struct pipe_picture_desc *picture,
+ unsigned num_buffers,
+ const void * const *buffers,
+ const unsigned int *sizes)
+{
+ struct pipe_h264_picture_desc *desc = (struct pipe_h264_picture_desc *)picture;
+ struct tegra_vde_buffer *buffer = to_tegra_vde_buffer(target);
+ struct tegra_vde_codec *vde = to_tegra_vde_codec(codec);
+ unsigned int i, j, offset = 0;
+ struct vl_rbsp rbsp;
+ struct vl_vlc vlc;
+ void *ptr;
+ int err;
+
+ debug_printf("> %s(codec=%p, target=%p, picture=%p, num_buffers=%u, buffers=%p, sizes=%p)\n",
+ __func__, codec, target, picture, num_buffers, buffers, sizes);
+ debug_printf(" target: %ux%u\n", target->width, target->height);
+ debug_printf(" planes: %u\n", buffer->num_planes);
+ debug_printf(" picture: profile: %d entrypoint %d\n", picture->profile, picture->entry_point);
+
+ if (u_reduce_video_profile(picture->profile) != PIPE_VIDEO_FORMAT_MPEG4_AVC) {
+ debug_printf("not a valid MPEG4 AVC frame\n");
+ goto out;
+ }
+
+ debug_printf(" h264:\n");
+ debug_printf(" pps:\n");
+ debug_printf(" sps:\n");
+ debug_printf(" level_idc: %u\n", desc->pps->sps->level_idc);
+ debug_printf(" chroma_format_idc: %u\n", desc->pps->sps->chroma_format_idc);
+ debug_printf(" ...\n");
+ debug_printf(" pic_order_cnt_type: %u\n", desc->pps->sps->pic_order_cnt_type);
+ debug_printf(" ...\n");
+ debug_printf(" max_num_ref_frames: %u\n", desc->pps->sps->max_num_ref_frames);
+ debug_printf(" ..\n");
+ debug_printf(" entropy_coding_mode_flags: %u\n", desc->pps->entropy_coding_mode_flag);
+ debug_printf(" ...\n");
+ debug_printf(" chroma_qp_index_offset: %u\n", desc->pps->chroma_qp_index_offset);
+ debug_printf(" ...\n");
+ debug_printf(" frame_num: %u\n", desc->frame_num);
+ debug_printf(" field_pic_flag: %u\n", desc->field_pic_flag);
+ debug_printf(" bottom_field_flag: %u\n", desc->bottom_field_flag);
+ debug_printf(" ...\n");
+ debug_printf(" slice_count: %u\n", desc->slice_count);
+ debug_printf(" field_order_cnt:\n");
+ debug_printf(" 0: %u\n", desc->field_order_cnt[0]);
+ debug_printf(" 1: %u\n", desc->field_order_cnt[1]);
+ debug_printf(" is_reference: %d\n", desc->is_reference);
+ debug_printf(" num_ref_frames: %u\n", desc->num_ref_frames);
+
+ for (i = 0; i < desc->num_ref_frames; i++)
+ debug_printf(" %u: %p\n", i, desc->ref[i]);
+
+ buffer->frame_num = desc->frame_num;
+ buffer->is_reference = desc->is_reference;
+
+ /* parse slice type from bitstream */
+ vl_vlc_init(&vlc, num_buffers, buffers, sizes);
+ debug_printf(" bitstream:\n");
+ debug_printf(" %06x\n", vl_vlc_peekbits(&vlc, 24));
+
+ if (vl_vlc_peekbits(&vlc, 32) == 0x00000001)
+ vl_vlc_eatbits(&vlc, 8);
+
+ if (vl_vlc_peekbits(&vlc, 24) != 0x000001) {
+ debug_printf("bad NAL start code: %06x\n", vl_vlc_peekbits(&vlc, 24));
+ return;
+ }
+
+ vl_vlc_eatbits(&vlc, 24);
+
+ /* forbidden_zero_bit */
+ vl_vlc_eatbits(&vlc, 1);
+
+ /* nal_ref_idc */
+ vl_vlc_get_uimsbf(&vlc, 2);
+
+ /* nal_unit_type */
+ vl_vlc_get_uimsbf(&vlc, 5);
+
+ vl_rbsp_init(&rbsp, &vlc, 128);
+
+ /* first_mb_in_slice */
+ vl_rbsp_ue(&rbsp);
+
+ /* slice_type */
+ buffer->slice_type = vl_rbsp_ue(&rbsp) % 5;
+
+ err = drm_tegra_bo_map(vde->bitstream, &ptr);
+ if (err < 0) {
+ debug_printf("failed to map bitstream buffer: %d\n", err);
+ goto out;
+ }
+
+ debug_printf(" copying from %u buffers:\n", num_buffers);
+
+ for (i = 0; i < num_buffers; i++) {
+ unsigned int count = (sizes[i] < 8) ? sizes[i]: 8;
+ const uint8_t *data = buffers[i];
+
+ debug_printf(" %3u: %p (%u bytes)\n", i, buffers[i], sizes[i]);
+ debug_printf(" ");
+
+ for (j = 0; j < count; j++)
+ debug_printf(" %02x", data[j]);
+
+ debug_printf("\n");
+
+ memcpy(ptr + offset, buffers[i], sizes[i]);
+
+ offset += sizes[i];
+ }
+
+ memset(ptr + offset, 0, vde->bitstream_size - offset);
+ drm_tegra_bo_unmap(vde->bitstream);
+
+out:
+ debug_printf("< %s()\n", __func__);
+}
+
+static int tegra_vde_h264_frame_init(struct tegra_vde_h264_frame *frame,
+ struct tegra_vde_buffer *buffer,
+ int *fds, unsigned int num_fds)
+{
+ struct tegra_vde_resource *resource;
+ unsigned int i;
+ int err;
+
+ for (i = 0; i < buffer->num_planes; i++) {
+ resource = to_tegra_vde_resource(buffer->planes[i]);
+
+ err = drm_tegra_bo_export(resource->bo, 0);
+ if (err < 0) {
+ debug_printf("failed to export plane %u: %d\n", i, err);
+
+ while (i--)
+ close(fds[i]);
+
+ return err;;
+ }
+
+ fds[i] = err;
+ }
+
+ resource = to_tegra_vde_resource(buffer->aux);
+
+ err = drm_tegra_bo_export(resource->bo, 0);
+ if (err < 0) {
+ debug_printf("failed to export AUX buffer: %d\n", err);
+
+ while (i--)
+ close(fds[i]);
+
+ return err;
+ }
+
+ fds[2] = err;
+
+ resource = to_tegra_vde_resource(buffer->planes[1]);
+
+ debug_printf("%s(): fds: [0]: %d [1]: %d [2]: %d\n", __func__, fds[0],
+ fds[1], fds[2]);
+
+ frame->y_fd = fds[0];
+ frame->cb_fd = fds[1];
+ frame->cr_fd = fds[1];
+ frame->aux_fd = fds[2];
+
+ frame->y_offset = 0;
+ frame->cb_offset = 0;
+ frame->cr_offset = resource->size / 2;
+ frame->aux_offset = 0;
+
+ frame->frame_num = buffer->frame_num;
+ frame->flags = 0;
+
+ if (buffer->slice_type == PIPE_H264_SLICE_TYPE_B)
+ frame->flags |= FLAG_B_FRAME;
+
+ if (buffer->is_reference)
+ frame->flags |= FLAG_REFERENCE;
+
+ return 3;
+}
+
+static void tegra_vde_codec_end_frame(struct pipe_video_codec *codec,
+ struct pipe_video_buffer *buffer,
+ struct pipe_picture_desc *picture)
+{
+ struct tegra_vde_screen *screen = to_tegra_vde_screen(codec->context->screen);
+ struct tegra_vde_buffer *target = to_tegra_vde_buffer(buffer);
+ struct tegra_vde_codec *vde = to_tegra_vde_codec(codec);
+ unsigned int num_refs = 0, num_fds, i, index = 0;
+ int err, bitstream_fd, secure_fd, *fds = NULL;
+ struct tegra_vde_h264_decoder_ctx args;
+ struct pipe_h264_picture_desc *desc;
+ struct tegra_vde_h264_frame *frames;
+
+ debug_printf("> %s(codec=%p, buffer=%p, picture=%p)\n", __func__, codec,
+ buffer, picture);
+
+ desc = (struct pipe_h264_picture_desc *)picture;
+ num_refs = desc->num_ref_frames;
+
+ for (i = 0; i < num_refs; i++) {
+ if (!desc->ref[i])
+ break;
+ }
+
+ num_refs = i;
+
+ debug_printf(" %u reference frames\n", num_refs);
+
+ num_fds = (1 + num_refs) * 3;
+
+ if (u_reduce_video_profile(picture->profile) != PIPE_VIDEO_FORMAT_MPEG4_AVC) {
+ debug_printf("not a valid MPEG4 AVC frame\n");
+ goto out;
+ }
+
+ frames = calloc(1 + num_refs, sizeof(*frames));
+ if (!frames) {
+ debug_printf("failed to allocate %u frames\n", 1 + num_refs);
+ goto out;
+ }
+
+ fds = calloc(num_fds, sizeof(int));
+ if (!fds) {
+ debug_printf("failed to allocate %u file descriptors\n", num_fds);
+ goto free;
+ }
+
+ for (i = 0; i < num_fds; i++)
+ fds[i] = -1;
+
+ bitstream_fd = drm_tegra_bo_export(vde->bitstream, 0);
+ if (bitstream_fd < 0) {
+ debug_printf("failed to export bitstream buffer: %d\n", bitstream_fd);
+ goto free;
+ }
+
+ secure_fd = drm_tegra_bo_export(vde->secure, 0);
+ if (secure_fd < 0) {
+ debug_printf("failed to export secure buffer: %d\n", secure_fd);
+ goto free;
+ }
+
+ err = tegra_vde_h264_frame_init(&frames[0], target, &fds[index],
+ num_fds - index);
+ if (err < 0) {
+ debug_printf("failed to initialize H264 frame: %d\n", err);
+ goto close;
+ }
+
+ index += err;
+
+ for (i = 0; i < num_refs; i++) {
+ struct tegra_vde_buffer *ref = to_tegra_vde_buffer(desc->ref[i]);
+
+ err = tegra_vde_h264_frame_init(&frames[1 + i], ref, &fds[index],
+ num_fds - index);
+ if (err < 0) {
+ debug_printf("failed to initialize H264 reference frame: %d\n", err);
+ goto close;
+ }
+
+ index += err;
+ }
+
+ memset(&args, 0, sizeof(args));
+ args.bitstream_data_fd = bitstream_fd;
+ args.bitstream_data_offset = 0;
+ args.secure_fd = secure_fd;
+ args.secure_offset = 0;
+ args.dpb_frames_nb = 1 + num_refs;
+ args.dpb_frames_ptr = (uintptr_t)frames;
+ args.dpb_ref_frames_with_earlier_poc_nb = 0; /* XXX */
+ args.baseline_profile = 1;
+ args.level_idc = 15; /* XXX */
+ args.log2_max_pic_order_cnt_lsb = desc->pps->sps->log2_max_pic_order_cnt_lsb_minus4 + 4;
+ args.log2_max_frame_num = desc->pps->sps->log2_max_frame_num_minus4 + 4;
+ args.pic_order_cnt_type = desc->pps->sps->pic_order_cnt_type;
+ args.direct_8x8_inference_flag = desc->pps->sps->direct_8x8_inference_flag;
+ args.pic_width_in_mbs = buffer->width / 16;
+ args.pic_height_in_mbs = buffer->height / 16;
+ args.pic_init_qp = desc->pps->pic_init_qp_minus26 + 26;
+ args.deblocking_filter_control_present_flag = desc->pps->deblocking_filter_control_present_flag;
+ args.constrained_intra_pred_flag = desc->pps->constrained_intra_pred_flag;
+ args.chroma_qp_index_offset = desc->pps->chroma_qp_index_offset & 0x1f;
+ args.pic_order_present_flag = 0; /* XXX */
+ args.num_ref_idx_l0_active_minus1 = desc->num_ref_idx_l0_active_minus1;
+ args.num_ref_idx_l1_active_minus1 = desc->num_ref_idx_l1_active_minus1;
+ args.reserved = 0;
+
+ do {
+ err = ioctl(screen->fd, TEGRA_VDE_IOCTL_DECODE_H264, &args);
+ if (err < 0)
+ err = -errno;
+ } while (err == -EINTR || errno == -EAGAIN);
+
+ if (err < 0)
+ debug_printf("ioctl(TEGRA_VDE_IOCTL_DECODE_H264) failed: %d\n", err);
+
+close:
+ for (i = 0; i < num_fds; i++) {
+ if (fds[i] >= 0)
+ close(fds[i]);
+ }
+
+ close(bitstream_fd);
+
+free:
+ if (fds)
+ free(fds);
+
+ free(frames);
+
+out:
+ debug_printf("< %s()\n", __func__);
+}
+
+static void tegra_vde_codec_flush(struct pipe_video_codec *codec)
+{
+ debug_printf("> %s(codec=%p)\n", __func__, codec);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void tegra_vde_codec_get_feedback(struct pipe_video_codec *codec,
+ void *feedback, unsigned *size)
+{
+ debug_printf("> %s(codec=%p, feedback=%p, size%p)\n", __func__, codec,
+ feedback, size);
+ debug_printf("< %s()\n", __func__);
+}
+
+static struct pipe_video_codec *
+tegra_vde_create_video_codec(struct pipe_context *pcontext,
+ const struct pipe_video_codec *template)
+{
+ struct tegra_vde_screen *screen = to_tegra_vde_screen(pcontext->screen);
+ struct tegra_vde_codec *codec;
+ int err;
+
+ debug_printf("> %s(pcontext=%p, template=%p)\n", __func__, pcontext,
+ template);
+#ifdef DEBUG
+ debug_print_video_profile(" profile", template->profile);
+ debug_printf(" level: %u\n", template->level);
+ debug_print_video_entrypoint(" entrypoint", template->entrypoint);
+ debug_printf(" chroma format: %u\n", template->chroma_format);
+ debug_printf(" resolution: %ux%u\n", template->width, template->height);
+ debug_printf(" max references: %u\n", template->max_references);
+ debug_printf(" chunked decode: %d\n", template->expect_chunked_decode);
+#endif
+
+ codec = calloc(1, sizeof(*codec));
+ if (!codec)
+ goto out;
+
+ codec->base = *template;
+ codec->base.context = pcontext;
+ codec->base.destroy = tegra_vde_codec_destroy;
+ codec->base.begin_frame = tegra_vde_codec_begin_frame;
+ codec->base.decode_bitstream = tegra_vde_codec_decode_bitstream;
+ codec->base.end_frame = tegra_vde_codec_end_frame;
+ codec->base.flush = tegra_vde_codec_flush;
+ codec->base.get_feedback = tegra_vde_codec_get_feedback;
+
+ codec->drm = screen->drm;
+
+ err = drm_tegra_bo_new(&codec->bitstream, screen->drm,
+ DRM_TEGRA_GEM_CONTIGUOUS, 256 * 1024);
+ if (err < 0) {
+ free(codec);
+ codec = NULL;
+ goto out;
+ }
+
+ codec->bitstream_size = 256 * 1024;
+
+ err = drm_tegra_bo_new(&codec->secure, screen->drm,
+ DRM_TEGRA_GEM_CONTIGUOUS, 4096);
+ if (err < 0) {
+ drm_tegra_bo_unref(codec->bitstream);
+ free(codec);
+ codec = NULL;
+ goto out;
+ }
+
+out:
+ debug_printf("< %s() = %p\n", __func__, codec);
+ return codec ? &codec->base : NULL;
+}
+
+/*
+ * context implementation
+ */
+
+static void tegra_vde_context_destroy(struct pipe_context *pcontext)
+{
+ struct tegra_vde_context *context = to_tegra_vde_context(pcontext);
+
+ debug_printf("> %s(pcontext=%p)\n", __func__, pcontext);
+
+ if (context->gpu)
+ context->gpu->destroy(context->gpu);
+
+ free(context);
+
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_draw_vbo(struct pipe_context *pcontext,
+ const struct pipe_draw_info *info)
+{
+ debug_printf("> %s(pcontext=%p, info=%p)\n", __func__, pcontext, info);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void *
+tegra_vde_create_blend_state(struct pipe_context *pcontext,
+ const struct pipe_blend_state *template)
+{
+ void *state = NULL;
+ debug_printf("> %s(pcontext=%p, template=%p)\n", __func__, pcontext, template);
+ debug_printf("< %s() = %p\n", __func__, state);
+ return state;
+}
+
+static void
+tegra_vde_bind_blend_state(struct pipe_context *pcontext, void *state)
+{
+ debug_printf("> %s(pcontext=%p, state=%p)\n", __func__, pcontext, state);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_delete_blend_state(struct pipe_context *pcontext, void *state)
+{
+ debug_printf("> %s(pcontext=%p, state=%p)\n", __func__, pcontext, state);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void *
+tegra_vde_create_sampler_state(struct pipe_context *pcontext,
+ const struct pipe_sampler_state *template)
+{
+ void *state = NULL;
+ debug_printf("> %s(pcontext=%p, template=%p)\n", __func__, pcontext, template);
+ debug_printf("< %s() = %p\n", __func__, state);
+ return state;
+}
+
+static void
+tegra_vde_bind_sampler_states(struct pipe_context *pcontext,
+ enum pipe_shader_type shader,
+ unsigned int start_slot,
+ unsigned int num_samplers,
+ void **samplers)
+{
+ debug_printf("> %s(pcontext=%p, shader=%d, start_slot=%u, num_samplers=%u, samplers=%p)\n",
+ __func__, pcontext, shader, start_slot, num_samplers, samplers);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_delete_sampler_state(struct pipe_context *pcontext, void *state)
+{
+ debug_printf("> %s(pcontext=%p, state=%p)\n", __func__, pcontext, state);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void *
+tegra_vde_create_rasterizer_state(struct pipe_context *pcontext,
+ const struct pipe_rasterizer_state *template)
+{
+ void *state = NULL;
+ debug_printf("> %s(pcontext=%p, template=%p)\n", __func__, pcontext, template);
+ debug_printf("< %s() = %p\n", __func__, state);
+ return state;
+}
+
+static void
+tegra_vde_bind_rasterizer_state(struct pipe_context *pcontext,
+ void *state)
+{
+ debug_printf("> %s(pcontext=%p, state=%p)\n", __func__, pcontext, state);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_delete_rasterizer_state(struct pipe_context *pcontext, void *state)
+{
+ debug_printf("> %s(pcontext=%p, state=%p)\n", __func__, pcontext, state);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void *
+tegra_vde_create_depth_stencil_alpha_state(struct pipe_context *pcontext,
+ const struct pipe_depth_stencil_alpha_state *template)
+{
+ void *state = NULL;
+ debug_printf("> %s(pcontext=%p, template=%p)\n", __func__, pcontext, template);
+ debug_printf("< %s() = %p\n", __func__, state);
+ return state;
+}
+
+static void
+tegra_vde_bind_depth_stencil_alpha_state(struct pipe_context *pcontext,
+ void *state)
+{
+ debug_printf("> %s(pcontext=%p, state=%p)\n", __func__, pcontext, state);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_delete_depth_stencil_alpha_state(struct pipe_context *pcontext,
+ void *state)
+{
+ debug_printf("> %s(pcontext=%p, state=%p)\n", __func__, pcontext, state);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void *
+tegra_vde_create_fs_state(struct pipe_context *pcontext,
+ const struct pipe_shader_state *template)
+{
+ void *state = (void *)-1;
+ debug_printf("> %s(pcontext=%p, template=%p)\n", __func__, pcontext, template);
+ debug_printf("< %s() = %p\n", __func__, state);
+ return state;
+}
+
+static void
+tegra_vde_bind_fs_state(struct pipe_context *pcontext, void *state)
+{
+ debug_printf("> %s(pcontext=%p, state=%p)\n", __func__, pcontext, state);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_delete_fs_state(struct pipe_context *pcontext, void *state)
+{
+ debug_printf("> %s(pcontext=%p, state=%p)\n", __func__, pcontext, state);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void *
+tegra_vde_create_vs_state(struct pipe_context *pcontext,
+ const struct pipe_shader_state *template)
+{
+ void *state = (void *)-1;
+ debug_printf("> %s(pcontext=%p, template=%p)\n", __func__, pcontext, template);
+ debug_printf("< %s() = %p\n", __func__, state);
+ return state;
+}
+
+static void
+tegra_vde_bind_vs_state(struct pipe_context *pcontext, void *state)
+{
+ debug_printf("> %s(pcontext=%p, state=%p)\n", __func__, pcontext, state);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_delete_vs_state(struct pipe_context *pcontext, void *state)
+{
+ debug_printf("> %s(pcontext=%p, state=%p)\n", __func__, pcontext, state);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void *
+tegra_vde_create_vertex_elements_state(struct pipe_context *pcontext,
+ unsigned int num_elements,
+ const struct pipe_vertex_element *template)
+{
+ void *state = (void *)-1;
+ debug_printf("> %s(pcontext=%p, num_elements=%u, template=%p)\n", __func__,
+ pcontext, num_elements, template);
+ debug_printf("< %s() = %p\n", __func__, state);
+ return state;
+}
+
+static void
+tegra_vde_bind_vertex_elements_state(struct pipe_context *pcontext, void *state)
+{
+ debug_printf("> %s(pcontext=%p, state=%p)\n", __func__, pcontext, state);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_delete_vertex_elements_state(struct pipe_context *pcontext, void *state)
+{
+ debug_printf("> %s(pcontext=%p, state=%p)\n", __func__, pcontext, state);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_set_constant_buffer(struct pipe_context *pcontext,
+ enum pipe_shader_type shader,
+ unsigned int index,
+ const struct pipe_constant_buffer *buffer)
+{
+ debug_printf("> %s(pcontext=%p, shader=%d, index=%u, buffer=%p)\n",
+ __func__, pcontext, shader, index, buffer);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_set_framebuffer_state(struct pipe_context *pcontext,
+ const struct pipe_framebuffer_state *state)
+{
+ debug_printf("> %s(pcontext=%p, state=%p)\n", __func__, pcontext, state);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_set_scissor_states(struct pipe_context *pcontext,
+ unsigned int start_slot,
+ unsigned int num_scissors,
+ const struct pipe_scissor_state *states)
+{
+ debug_printf("> %s(pcontext=%p, start_slot=%u, num_scissors=%u, states=%p)\n",
+ __func__, pcontext, start_slot, num_scissors, states);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_set_viewport_states(struct pipe_context *pcontext,
+ unsigned int start_slot,
+ unsigned int num_viewports,
+ const struct pipe_viewport_state *states)
+{
+ debug_printf("> %s(pcontext=%p, start_slot=%u, num_viewports=%u, states=%p)\n",
+ __func__, pcontext, start_slot, num_viewports, states);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_set_sampler_views(struct pipe_context *pcontext,
+ enum pipe_shader_type shader,
+ unsigned int start_slot,
+ unsigned int num_views,
+ struct pipe_sampler_view **views)
+{
+ debug_printf("> %s(pcontext=%p, shader=%d, start_slot=%u, num_views=%u, views=%p)\n",
+ __func__, pcontext, shader, start_slot, num_views, views);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_set_vertex_buffers(struct pipe_context *pcontext,
+ unsigned int start_slot,
+ unsigned int num_buffers,
+ const struct pipe_vertex_buffer *buffers)
+{
+ debug_printf("> %s(pcontext=%p, start_slot=%u, num_buffers=%u, buffers=%p)\n",
+ __func__, pcontext, start_slot, num_buffers, buffers);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void tegra_vde_clear_render_target(struct pipe_context *pcontext,
+ struct pipe_surface *dst,
+ const union pipe_color_union *color,
+ unsigned dstx, unsigned dsty,
+ unsigned width, unsigned height,
+ bool render_condition_enabled)
+{
+ struct tegra_vde_resource *resource = to_tegra_vde_resource(dst->texture);
+ void *ptr;
+ int err;
+
+ debug_printf("> %s(pcontext=%p, dst=%p, color=%p, dstx=%u, dsty=%u, width=%u, height=%u, render_condition_enabled=%d)\n",
+ __func__, pcontext, dst, color, dstx, dsty, width, height, render_condition_enabled);
+
+ err = drm_tegra_bo_map(resource->bo, &ptr);
+ if (err < 0) {
+ debug_printf(" failed to map buffer object: %d\n", err);
+ goto out;
+ }
+
+ memset(ptr, 0xff, resource->size);
+ drm_tegra_bo_unmap(resource->bo);
+
+out:
+ debug_printf("< %s()\n", __func__);
+}
+
+static void tegra_vde_flush(struct pipe_context *pcontext,
+ struct pipe_fence_handle **pfence,
+ unsigned int flags)
+{
+ debug_printf("> %s(pcontext=%p, pfence=%p, flags=%x)\n", __func__,
+ pcontext, pfence, flags);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void *
+tegra_vde_transfer_map(struct pipe_context *pcontext,
+ struct pipe_resource *presource,
+ unsigned int level,
+ unsigned int usage,
+ const struct pipe_box *box,
+ struct pipe_transfer **transferp)
+{
+ struct tegra_vde_resource *resource = to_tegra_vde_resource(presource);
+ struct pipe_transfer *transfer;
+ void *map = NULL;
+ int err;
+
+ debug_printf("> %s(pcontext=%p, presource=%p, level=%u, usage=%x, box=%p, transferp=%p)\n",
+ __func__, pcontext, presource, level, usage, box, transferp);
+
+ transfer = calloc(1, sizeof(*transfer));
+ if (!transfer)
+ goto out;
+
+ transfer->resource = presource;
+ transfer->level = level;
+ transfer->usage = usage;
+ transfer->box = *box;
+ transfer->stride = 0;
+ transfer->layer_stride = 0;
+
+ err = drm_tegra_bo_map(resource->bo, &map);
+ if (err < 0) {
+ debug_printf("failed to map buffer object: %d\n", err);
+ free(transfer);
+ goto out;
+ }
+
+ *transferp = transfer;
+
+out:
+ debug_printf("< %s() = %p\n", __func__, map);
+ return map;
+}
+
+static void
+tegra_vde_transfer_flush_region(struct pipe_context *pcontext,
+ struct pipe_transfer *transfer,
+ const struct pipe_box *box)
+{
+ debug_printf("> %s(pcontext=%p, transfer=%p, box=%p)\n", __func__, pcontext, transfer, box);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_transfer_unmap(struct pipe_context *pcontext,
+ struct pipe_transfer *transfer)
+{
+ struct tegra_vde_resource *resource = to_tegra_vde_resource(transfer->resource);
+
+ debug_printf("> %s(pcontext=%p, transfer=%p)\n", __func__, pcontext, transfer);
+
+ drm_tegra_bo_unmap(resource->bo);
+
+ debug_printf("< %s()\n", __func__);
+}
+
+static void
+tegra_vde_texture_subdata(struct pipe_context *pcontext,
+ struct pipe_resource *presource,
+ unsigned int level, unsigned int usage,
+ const struct pipe_box *box,
+ const void *data,
+ unsigned int stride,
+ unsigned int layer_stride)
+{
+ debug_printf("> %s(pcontext=%p, presource=%p, level=%u, usage=%x, box=%p, data=%p, stride=%u, layer_stride=%u)\n",
+ __func__, pcontext, presource, level, usage, box, data,
+ stride, layer_stride);
+
+ u_default_texture_subdata(pcontext, presource, level, usage, box, data,
+ stride, layer_stride);
+
+ debug_printf("< %s()\n", __func__);
+}
+
+static struct pipe_sampler_view *
+tegra_vde_create_sampler_view(struct pipe_context *pcontext,
+ struct pipe_resource *texture,
+ const struct pipe_sampler_view *template)
+{
+ struct tegra_vde_sampler_view *view;
+
+ debug_printf("> %s(pcontext=%p, texture=%p, template=%p)\n", __func__,
+ pcontext, texture, template);
+
+ view = calloc(1, sizeof(*view));
+ if (!view)
+ goto out;
+
+ view->base = *template;
+ view->base.context = pcontext;
+
+ pipe_reference_init(&view->base.reference, 1);
+ pipe_resource_reference(&view->base.texture, texture);
+
+out:
+ debug_printf("< %s() = %p\n", __func__, view);
+ return view ? &view->base : NULL;
+}
+
+static void
+tegra_vde_sampler_view_destroy(struct pipe_context *pcontext,
+ struct pipe_sampler_view *pview)
+{
+ struct tegra_vde_sampler_view *view = to_tegra_vde_sampler_view(pview);
+
+ debug_printf("> %s(pcontext=%p, pview=%p)\n", __func__, pcontext, pview);
+
+ free(view);
+
+ debug_printf("< %s()\n", __func__);
+}
+
+static struct pipe_surface *
+tegra_vde_create_surface(struct pipe_context *pcontext,
+ struct pipe_resource *presource,
+ const struct pipe_surface *template)
+{
+ struct tegra_vde_surface *surface;
+
+ debug_printf("> %s(pcontext=%p, presource=%p, template=%p)\n", __func__,
+ pcontext, presource, template);
+
+ surface = calloc(1, sizeof(*surface));
+ if (!surface)
+ goto out;
+
+ pipe_reference_init(&surface->base.reference, 1);
+ pipe_resource_reference(&surface->base.texture, presource);
+
+ surface->base.context = pcontext;
+ surface->base.format = template->format;
+ surface->base.writable = template->writable;
+ surface->base.width = presource->width0;
+ surface->base.height = presource->height0;
+
+out:
+ debug_printf("< %s() = %p\n", __func__, surface);
+ return surface ? &surface->base : NULL;
+}
+
+static void
+tegra_vde_surface_destroy(struct pipe_context *pcontext,
+ struct pipe_surface *psurface)
+{
+ struct tegra_vde_surface *surface = to_tegra_vde_surface(psurface);
+
+ debug_printf("> %s(pcontext=%p, psurface=%p)\n", __func__, pcontext,
+ psurface);
+
+ free(surface);
+
+ debug_printf("< %s()\n", __func__);
+}
+
+static struct pipe_context *
+tegra_vde_context_create(struct pipe_screen *pscreen, void *priv,
+ unsigned flags)
+{
+ struct tegra_vde_screen *screen = to_tegra_vde_screen(pscreen);
+ struct tegra_vde_context *context;
+
+ debug_printf("> %s(pscreen=%p, priv=%p, flags=%x)\n", __func__, pscreen,
+ priv, flags);
+
+ context = calloc(1, sizeof(*context));
+ if (!context)
+ goto out;
+
+ context->base.screen = pscreen;
+ context->base.priv = priv;
+
+ context->gpu = screen->gpu->context_create(screen->gpu, NULL, 0);
+ if (!context->gpu) {
+ free(context);
+ goto out;
+ }
+
+ context->base.stream_uploader = u_upload_create_default(&context->base);
+ if (!context->base.stream_uploader) {
+ context->gpu->destroy(context->gpu);
+ free(context);
+ goto out;
+ }
+
+ context->base.const_uploader = context->base.stream_uploader;
+
+ context->base.destroy = tegra_vde_context_destroy;
+ context->base.draw_vbo = tegra_vde_draw_vbo;
+ context->base.create_blend_state = tegra_vde_create_blend_state;
+ context->base.bind_blend_state = tegra_vde_bind_blend_state;
+ context->base.delete_blend_state = tegra_vde_delete_blend_state;
+ context->base.create_sampler_state = tegra_vde_create_sampler_state;
+ context->base.bind_sampler_states = tegra_vde_bind_sampler_states;
+ context->base.delete_sampler_state = tegra_vde_delete_sampler_state;
+ context->base.clear_render_target = tegra_vde_clear_render_target;
+ context->base.flush = tegra_vde_flush;
+ context->base.transfer_map = tegra_vde_transfer_map;
+ context->base.transfer_flush_region = tegra_vde_transfer_flush_region;
+ context->base.transfer_unmap = tegra_vde_transfer_unmap;
+ context->base.texture_subdata = tegra_vde_texture_subdata;
+ context->base.create_sampler_view = tegra_vde_create_sampler_view;
+ context->base.sampler_view_destroy = tegra_vde_sampler_view_destroy;
+ context->base.create_rasterizer_state = tegra_vde_create_rasterizer_state;
+ context->base.bind_rasterizer_state = tegra_vde_bind_rasterizer_state;
+ context->base.delete_rasterizer_state = tegra_vde_delete_rasterizer_state;
+ context->base.create_depth_stencil_alpha_state = tegra_vde_create_depth_stencil_alpha_state;
+ context->base.bind_depth_stencil_alpha_state = tegra_vde_bind_depth_stencil_alpha_state;
+ context->base.delete_depth_stencil_alpha_state = tegra_vde_delete_depth_stencil_alpha_state;
+ context->base.create_fs_state = tegra_vde_create_fs_state;
+ context->base.bind_fs_state = tegra_vde_bind_fs_state;
+ context->base.delete_fs_state = tegra_vde_delete_fs_state;
+ context->base.create_vs_state = tegra_vde_create_vs_state;
+ context->base.bind_vs_state = tegra_vde_bind_vs_state;
+ context->base.delete_vs_state = tegra_vde_delete_vs_state;
+ context->base.create_vertex_elements_state = tegra_vde_create_vertex_elements_state;
+ context->base.bind_vertex_elements_state = tegra_vde_bind_vertex_elements_state;
+ context->base.delete_vertex_elements_state = tegra_vde_delete_vertex_elements_state;
+ context->base.set_constant_buffer = tegra_vde_set_constant_buffer;
+ context->base.set_framebuffer_state = tegra_vde_set_framebuffer_state;
+ context->base.set_scissor_states = tegra_vde_set_scissor_states;
+ context->base.set_viewport_states = tegra_vde_set_viewport_states;
+ context->base.set_sampler_views = tegra_vde_set_sampler_views;
+ context->base.set_vertex_buffers = tegra_vde_set_vertex_buffers;
+ context->base.create_surface = tegra_vde_create_surface;
+ context->base.surface_destroy = tegra_vde_surface_destroy;
+ context->base.create_video_codec = tegra_vde_create_video_codec;
+ context->base.create_video_buffer = tegra_vde_create_video_buffer;
+
+out:
+ debug_printf("< %s() = %p\n", __func__, context);
+ return context ? &context->base : NULL;
+}
+
+/*
+ * screen implementation
+ */
+
+static void tegra_vde_screen_destroy(struct pipe_screen *pscreen)
+{
+ struct tegra_vde_screen *screen = to_tegra_vde_screen(pscreen);
+
+ debug_printf("> %s(pscreen=%p)\n", __func__, pscreen);
+
+ /* XXX this recurses */
+ /*
+ if (screen->gpu)
+ screen->gpu->destroy(screen->gpu);
+ */
+
+ close(screen->fd);
+ free(screen);
+
+ debug_printf("< %s()\n", __func__);
+}
+
+static int tegra_vde_get_param(struct pipe_screen *pscreen,
+ enum pipe_cap param)
+{
+ int ret;
+
+ debug_printf("> %s(pscreen=%p, param=%d)\n", __func__, pscreen, param);
+
+ switch (param) {
+ case PIPE_CAP_NPOT_TEXTURES:
+ ret = 1;
+ break;
+
+ case PIPE_CAP_MAX_TEXTURE_2D_LEVELS:
+ ret = 12;
+ break;
+
+ case PIPE_CAP_CONSTBUF0_FLAGS:
+ ret = 0;
+ break;
+
+ default:
+ debug_printf("unknown parameter %d\n", param);
+ ret = 0;
+ break;
+ }
+
+ debug_printf("< %s()\n", __func__);
+ return ret;
+}
+
+static int tegra_vde_get_video_param(struct pipe_screen *pscreen,
+ enum pipe_video_profile profile,
+ enum pipe_video_entrypoint entrypoint,
+ enum pipe_video_cap param)
+{
+ int value = 0;
+
+ debug_printf("> %s(pscreen=%p, profile=%d, entrypoint=%d, param=%d)\n",
+ __func__, pscreen, profile, entrypoint, param);
+#ifdef DEBUG
+ debug_print_video_profile(" profile", profile);
+ debug_print_video_entrypoint(" entrypoint", entrypoint);
+ debug_print_video_cap(" param", param);
+#endif
+
+ switch (param) {
+ case PIPE_VIDEO_CAP_SUPPORTED:
+ switch (profile) {
+ case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
+ case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
+ switch (entrypoint) {
+ case PIPE_VIDEO_ENTRYPOINT_BITSTREAM:
+ value = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case PIPE_VIDEO_CAP_NPOT_TEXTURES:
+ value = 1;
+ break;
+
+ case PIPE_VIDEO_CAP_MAX_WIDTH:
+ value = 2048 - 16;
+ break;
+
+ case PIPE_VIDEO_CAP_MAX_HEIGHT:
+ value = 2048 - 16;
+ break;
+
+ case PIPE_VIDEO_CAP_PREFERED_FORMAT:
+ value = PIPE_FORMAT_YV12;
+ break;
+
+ case PIPE_VIDEO_CAP_PREFERS_INTERLACED:
+ value = 0;
+ break;
+
+ case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE:
+ value = 1;
+ break;
+
+ case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:
+ value = 0;
+ break;
+
+ case PIPE_VIDEO_CAP_MAX_LEVEL:
+ value = 0;
+ break;
+
+ case PIPE_VIDEO_CAP_STACKED_FRAMES:
+ value = 0;
+ break;
+
+ default:
+ debug_printf("unknown parameter: %d\n", param);
+ value = 0;
+ break;
+ }
+
+ debug_printf("< %s() = %d\n", __func__, value);
+ return value;
+}
+
+static boolean
+tegra_vde_is_format_supported(struct pipe_screen *pscreen,
+ enum pipe_format format,
+ enum pipe_texture_target target,
+ unsigned sample_count,
+ unsigned bindings)
+{
+ boolean ret = false;
+
+ debug_printf("> %s(pscreen=%p, format=%d, target=%d, sample_count=%u, bindings=%x)\n",
+ __func__, pscreen, format, target, sample_count, bindings);
+#ifdef DEBUG
+ debug_printf(" format: %s\n", util_format_name(format));
+#endif
+
+ switch (format) {
+ case PIPE_FORMAT_R8G8B8A8_UNORM:
+ case PIPE_FORMAT_B8G8R8A8_UNORM:
+ ret = true;
+ break;
+
+ default:
+ break;
+ }
+
+ debug_printf("< %s() = %d\n", __func__, ret);
+ return ret;
+}
+
+static boolean
+tegra_vde_is_video_format_supported(struct pipe_screen *pscreen,
+ enum pipe_format format,
+ enum pipe_video_profile profile,
+ enum pipe_video_entrypoint entrypoint)
+{
+ boolean ret = false;
+
+ debug_printf("> %s(pscreen=%p, format=%d, profile=%d, entrypoint=%d)\n",
+ __func__, pscreen, format, profile, entrypoint);
+#ifdef DEBUG
+ debug_printf(" format: %s\n", util_format_name(format));
+ debug_print_video_profile(" profile", profile);
+ debug_print_video_entrypoint(" entrypoint", entrypoint);
+#endif
+
+ switch (entrypoint) {
+ case PIPE_VIDEO_ENTRYPOINT_BITSTREAM:
+ switch (format) {
+ /*
+ case PIPE_FORMAT_UYVY:
+ case PIPE_FORMAT_YUYV:
+ */
+ case PIPE_FORMAT_YV12:
+ /*
+ case PIPE_FORMAT_NV12:
+ */
+ ret = true;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ debug_printf("< %s() = %d\n", __func__, ret);
+ return ret;
+}
+
+static boolean
+tegra_vde_can_create_resource(struct pipe_screen *pscreen,
+ const struct pipe_resource *template)
+{
+ debug_printf("> %s(pscreen=%p, template=%p)\n", __func__, pscreen, template);
+ debug_printf("< %s()\n", __func__);
+
+ return true;
+}
+
+static struct pipe_resource *
+tegra_vde_resource_create(struct pipe_screen *pscreen,
+ const struct pipe_resource *template)
+{
+ struct tegra_vde_screen *screen = to_tegra_vde_screen(pscreen);
+ struct tegra_vde_resource *resource;
+ unsigned int block_size;
+ int err;
+
+ debug_printf("> %s(pscreen=%p, template=%p)\n", __func__, pscreen, template);
+
+ resource = calloc(1, sizeof(*resource));
+ if (!resource)
+ goto out;
+
+ resource->base = *template;
+ pipe_reference_init(&resource->base.reference, 1);
+ resource->base.screen = pscreen;
+
+ block_size = util_format_get_blocksize(template->format);
+ resource->stride = align(template->width0, 16);
+ resource->pitch = resource->stride * block_size;
+ resource->size = resource->pitch * align(template->height0, 16);
+
+ debug_printf(" allocating buffer object with %zu bytes\n", resource->size);
+
+ err = drm_tegra_bo_new(&resource->bo, screen->drm, DRM_TEGRA_GEM_CONTIGUOUS,
+ resource->size);
+ if (err < 0) {
+ debug_printf("failed to allocate buffer object: %d\n", err);
+ free(resource);
+ resource = NULL;
+ goto out;
+ }
+
+out:
+ debug_printf("< %s() = %p\n", __func__, resource);
+ return resource ? &resource->base : NULL;
+}
+
+static boolean
+tegra_vde_resource_get_handle(struct pipe_screen *pscreen,
+ struct pipe_context *pcontext,
+ struct pipe_resource *presource,
+ struct winsys_handle *whandle,
+ unsigned int usage)
+{
+ struct tegra_vde_resource *resource = to_tegra_vde_resource(presource);
+ boolean ret = FALSE;
+ int err;
+
+ debug_printf("> %s(pscreen=%p, pcontext=%p, presource=%p, whandle=%p, usage=%x)\n",
+ __func__, pscreen, pcontext, presource, whandle, usage);
+
+ if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) {
+ uint32_t name;
+
+ err = drm_tegra_bo_get_name(resource->bo, &name);
+ if (err < 0)
+ goto out;
+
+ whandle->handle = name;
+ ret = TRUE;
+ } else if (whandle->type == DRM_API_HANDLE_TYPE_KMS) {
+ uint32_t handle;
+
+ err = drm_tegra_bo_get_handle(resource->bo, &handle);
+ if (err < 0)
+ goto out;
+
+ whandle->handle = handle;
+ ret = TRUE;
+ } else if (whandle->type == DRM_API_HANDLE_TYPE_FD) {
+ int fd;
+
+ fd = drm_tegra_bo_export(resource->bo, 0);
+ if (fd < 0)
+ goto out;
+
+ whandle->handle = fd;
+ ret = TRUE;
+ }
+
+out:
+ debug_printf("< %s() = %d\n", __func__, ret);
+ return ret;
+}
+
+static void tegra_vde_resource_destroy(struct pipe_screen *pscreen,
+ struct pipe_resource *presource)
+{
+ struct tegra_vde_resource *resource = to_tegra_vde_resource(presource);
+
+ debug_printf("> %s(pscreen=%p, presource=%p)\n", __func__, pscreen,
+ presource);
+
+ drm_tegra_bo_unref(resource->bo);
+ free(resource);
+
+ debug_printf("< %s()\n", __func__);
+}
+
+static void tegra_vde_flush_frontbuffer(struct pipe_screen *pscreen,
+ struct pipe_resource *presource,
+ unsigned int level,
+ unsigned int layer,
+ void *winsys_drawable_handle,
+ struct pipe_box *box)
+{
+ debug_printf("> %s(pscreen=%p, presource=%p, level=%u, layer=%u, winsys_drawable_handle=%p, box=%p)\n",
+ __func__, pscreen, presource, level, layer,
+ winsys_drawable_handle, box);
+ debug_printf("< %s()\n", __func__);
+}
+
+static void tegra_vde_fence_reference(struct pipe_screen *pscreen,
+ struct pipe_fence_handle **ptr,
+ struct pipe_fence_handle *fence)
+{
+ debug_printf("> %s(pscreen=%p, ptr=%p, fence=%p)\n", __func__, pscreen,
+ ptr, fence);
+ debug_printf("< %s()\n", __func__);
+}
+
+struct pipe_screen *tegra_vde_screen_create(struct pipe_screen *parent,
+ struct drm_tegra *drm)
+{
+ struct tegra_vde_screen *screen;
+
+ debug_printf("> %s()\n", __func__);
+
+ screen = calloc(1, sizeof(*screen));
+ if (!screen)
+ goto out;
+
+ screen->gpu = parent;
+ screen->drm = drm;
+
+ screen->base.destroy = tegra_vde_screen_destroy;
+ screen->base.get_param = tegra_vde_get_param;
+ screen->base.get_video_param = tegra_vde_get_video_param;
+ screen->base.context_create = tegra_vde_context_create;
+ screen->base.is_format_supported = tegra_vde_is_format_supported;
+ screen->base.is_video_format_supported = tegra_vde_is_video_format_supported;
+ screen->base.can_create_resource = tegra_vde_can_create_resource;
+ screen->base.resource_create = tegra_vde_resource_create;
+ screen->base.resource_get_handle = tegra_vde_resource_get_handle;
+ screen->base.resource_destroy = tegra_vde_resource_destroy;
+ screen->base.flush_frontbuffer = tegra_vde_flush_frontbuffer;
+ screen->base.fence_reference = tegra_vde_fence_reference;
+
+ screen->fd = open("/dev/tegra_vde", O_RDWR);
+ if (screen->fd < 0)
+ goto free;
+
+ debug_printf("< %s() = %p\n", __func__, screen);
+ return &screen->base;
+
+free:
+ free(screen);
+out:
+ debug_printf("< %s() = NULL\n", __func__);
+ return NULL;
+}
diff --git a/src/gallium/drivers/tegra/tegra_vde.h b/src/gallium/drivers/tegra/tegra_vde.h
new file mode 100644
index 000000000000..089618a9e2de
--- /dev/null
+++ b/src/gallium/drivers/tegra/tegra_vde.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright © 2018 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef TEGRA_VDE_H
+#define TEGRA_VDE_H
+
+struct pipe_screen;
+struct drm_tegra;
+
+struct pipe_screen *tegra_vde_screen_create(struct pipe_screen *parent,
+ struct drm_tegra *drm);
+
+#endif /* TEGRA_VDE_H */
diff --git a/src/gallium/drivers/tegra/tegra_vde_uabi.h b/src/gallium/drivers/tegra/tegra_vde_uabi.h
new file mode 100644
index 000000000000..ff7759297b78
--- /dev/null
+++ b/src/gallium/drivers/tegra/tegra_vde_uabi.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016-2017 Dmitry Osipenko <digetx@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _UAPI_TEGRA_VDE_H_
+#define _UAPI_TEGRA_VDE_H_
+
+#include <linux/types.h>
+#include <asm/ioctl.h>
+
+#define FLAG_B_FRAME (1 << 0)
+#define FLAG_REFERENCE (1 << 1)
+
+struct tegra_vde_h264_frame {
+ __s32 y_fd;
+ __s32 cb_fd;
+ __s32 cr_fd;
+ __s32 aux_fd;
+ __u32 y_offset;
+ __u32 cb_offset;
+ __u32 cr_offset;
+ __u32 aux_offset;
+ __u32 frame_num;
+ __u32 flags;
+ __u32 block_height;
+
+ __u32 reserved;
+} __attribute__((packed));
+
+struct tegra_vde_h264_decoder_ctx {
+ __s32 bitstream_data_fd;
+ __u32 bitstream_data_offset;
+
+ __s32 secure_fd;
+ __u32 secure_offset;
+
+ __u64 dpb_frames_ptr;
+ __u8 dpb_frames_nb;
+ __u8 dpb_ref_frames_with_earlier_poc_nb;
+
+ // SPS
+ __u8 baseline_profile;
+ __u8 level_idc;
+ __u8 log2_max_pic_order_cnt_lsb;
+ __u8 log2_max_frame_num;
+ __u8 pic_order_cnt_type;
+ __u8 direct_8x8_inference_flag;
+ __u8 pic_width_in_mbs;
+ __u8 pic_height_in_mbs;
+
+ // PPS
+ __u8 pic_init_qp;
+ __u8 deblocking_filter_control_present_flag;
+ __u8 constrained_intra_pred_flag;
+ __u8 chroma_qp_index_offset;
+ __u8 pic_order_present_flag;
+
+ // Slice header
+ __u8 num_ref_idx_l0_active_minus1;
+ __u8 num_ref_idx_l1_active_minus1;
+
+ __u32 reserved;
+} __attribute__((packed));
+
+#define VDE_IOCTL_BASE ('v' + 0x20)
+
+#define VDE_IO(nr) _IO(VDE_IOCTL_BASE, nr)
+#define VDE_IOR(nr, type) _IOR(VDE_IOCTL_BASE, nr, type)
+#define VDE_IOW(nr, type) _IOW(VDE_IOCTL_BASE, nr, type)
+#define VDE_IOWR(nr, type) _IOWR(VDE_IOCTL_BASE, nr, type)
+
+#define TEGRA_VDE_DECODE_H264 0x00
+
+#define TEGRA_VDE_IOCTL_DECODE_H264 \
+ VDE_IOW(TEGRA_VDE_DECODE_H264, struct tegra_vde_h264_decoder_ctx)
+
+#endif // _UAPI_TEGRA_VDE_H_