[Mesa-dev] [PATCH v3 5/6] tegra: Initial support

Dmitry Osipenko digetx at gmail.com
Sun Mar 4 21:27:16 UTC 2018


On 01.03.2018 16:54, Thierry Reding wrote:
> Tegra K1 and later use a GPU that can be driven by the Nouveau driver.
> But the GPU is a pure render node and has no display engine, hence the
> scanout needs to happen on the Tegra display hardware. The GPU and the
> display engine each have a separate DRM device node exposed by the
> kernel.
> 
> To make the setup appear as a single device, this driver instantiates
> a Nouveau screen with each instance of a Tegra screen and forwards GPU
> requests to the Nouveau screen. For purposes of scanout it will import
> buffers created on the GPU into the display driver. Handles that
> userspace requests are those of the display driver so that they can be
> used to create framebuffers.
> 
> This has been tested with some GBM test programs, as well as kmscube and
> weston. All of those run without modifications, but I'm sure there is a
> lot that can be improved.
> 
> Some fixes contributed by Hector Martin <marcan at marcan.st>.
> 
> Changes in v2:
> - duplicate file descriptor in winsys to avoid potential issues
> - require nouveau when building the tegra driver
> - check for nouveau driver name on render node
> - remove unneeded dependency on libdrm_tegra
> - remove zombie references to libudev
> - add missing headers to C_SOURCES variable
> - drop unneeded tegra/ prefix for includes
> - open device files with O_CLOEXEC
> - update copyrights
> 
> Changes in v3:
> - properly unwrap resources in ->resource_copy_region()
> - support vertex buffers passed by user pointer
> - allocate custom stream and const uploader
> - silence error message on pre-Tegra124
> - support X without explicit PRIME
> 
> Reviewed-by: Emil Velikov <emil.velikov at collabora.com>
> Acked-by: Emil Velikov <emil.velikov at collabora.com>
> Tested-by: Andre Heider <a.heider at gmail.com>
> Signed-off-by: Thierry Reding <treding at nvidia.com>
> ---
>  configure.ac                                       |   12 +-
>  include/drm-uapi/tegra_drm.h                       |  225 ++++
>  meson.build                                        |    7 +-
>  src/gallium/Makefile.am                            |    5 +
>  .../auxiliary/pipe-loader/pipe_loader_drm.c        |    7 +-
>  src/gallium/auxiliary/target-helpers/drm_helper.h  |   23 +
>  .../auxiliary/target-helpers/drm_helper_public.h   |    3 +
>  src/gallium/drivers/tegra/Automake.inc             |   11 +
>  src/gallium/drivers/tegra/Makefile.am              |   11 +
>  src/gallium/drivers/tegra/Makefile.sources         |    6 +
>  src/gallium/drivers/tegra/meson.build              |   41 +
>  src/gallium/drivers/tegra/tegra_context.c          | 1325 ++++++++++++++++++++
>  src/gallium/drivers/tegra/tegra_context.h          |   81 ++
>  src/gallium/drivers/tegra/tegra_resource.h         |   76 ++
>  src/gallium/drivers/tegra/tegra_screen.c           |  688 ++++++++++
>  src/gallium/drivers/tegra/tegra_screen.h           |   45 +
>  src/gallium/meson.build                            |    6 +
>  src/gallium/targets/dri/Makefile.am                |    2 +
>  src/gallium/targets/dri/meson.build                |    4 +-
>  src/gallium/targets/dri/target.c                   |    4 +
>  src/gallium/targets/vdpau/Makefile.am              |    2 +
>  src/gallium/winsys/tegra/drm/Makefile.am           |   10 +
>  src/gallium/winsys/tegra/drm/Makefile.sources      |    2 +
>  src/gallium/winsys/tegra/drm/meson.build           |   33 +
>  src/gallium/winsys/tegra/drm/tegra_drm_public.h    |   31 +
>  src/gallium/winsys/tegra/drm/tegra_drm_winsys.c    |   49 +
>  26 files changed, 2705 insertions(+), 4 deletions(-)
>  create mode 100644 include/drm-uapi/tegra_drm.h
>  create mode 100644 src/gallium/drivers/tegra/Automake.inc
>  create mode 100644 src/gallium/drivers/tegra/Makefile.am
>  create mode 100644 src/gallium/drivers/tegra/Makefile.sources
>  create mode 100644 src/gallium/drivers/tegra/meson.build
>  create mode 100644 src/gallium/drivers/tegra/tegra_context.c
>  create mode 100644 src/gallium/drivers/tegra/tegra_context.h
>  create mode 100644 src/gallium/drivers/tegra/tegra_resource.h
>  create mode 100644 src/gallium/drivers/tegra/tegra_screen.c
>  create mode 100644 src/gallium/drivers/tegra/tegra_screen.h
>  create mode 100644 src/gallium/winsys/tegra/drm/Makefile.am
>  create mode 100644 src/gallium/winsys/tegra/drm/Makefile.sources
>  create mode 100644 src/gallium/winsys/tegra/drm/meson.build
>  create mode 100644 src/gallium/winsys/tegra/drm/tegra_drm_public.h
>  create mode 100644 src/gallium/winsys/tegra/drm/tegra_drm_winsys.c
> 
> diff --git a/configure.ac b/configure.ac
> index d8093597dd04..27528181b73e 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -1351,7 +1351,7 @@ GALLIUM_DRIVERS_DEFAULT="r300,r600,svga,swrast"
>  AC_ARG_WITH([gallium-drivers],
>      [AS_HELP_STRING([--with-gallium-drivers@<:@=DIRS...@:>@],
>          [comma delimited Gallium drivers list, e.g.
> -        "i915,nouveau,r300,r600,radeonsi,freedreno,pl111,svga,swrast,swr,vc4,vc5,virgl,etnaviv,imx"
> +        "i915,nouveau,r300,r600,radeonsi,freedreno,pl111,svga,swrast,swr,tegra,vc4,vc5,virgl,etnaviv,imx"
>          @<:@default=r300,r600,svga,swrast@:>@])],
>      [with_gallium_drivers="$withval"],
>      [with_gallium_drivers="$GALLIUM_DRIVERS_DEFAULT"])
> @@ -2590,6 +2590,10 @@ if test -n "$with_gallium_drivers"; then
>         ximx)
>              HAVE_GALLIUM_IMX=yes
>              ;;
> +        xtegra)
> +            HAVE_GALLIUM_TEGRA=yes
> +            require_libdrm "tegra"
> +            ;;
>          xswrast)
>              HAVE_GALLIUM_SOFTPIPE=yes
>              if test "x$enable_llvm" = xyes; then
> @@ -2714,6 +2718,9 @@ if test "x$HAVE_GALLIUM_VC4" != xyes -a "x$HAVE_GALLIUM_PL111" = xyes  ; then
>      AC_MSG_ERROR([Building with pl111 requires vc4])
>  fi
>  
> +if test "x$HAVE_GALLIUM_NOUVEAU" != xyes -a "x$HAVE_GALLIUM_TEGRA" = xyes; then
> +    AC_MSG_ERROR([Building with tegra requires nouveau])
> +fi
>  
>  detect_old_buggy_llvm() {
>      dnl llvm-config may not give the right answer when llvm is a built as a
> @@ -2813,6 +2820,7 @@ AM_CONDITIONAL(HAVE_GALLIUM_NOUVEAU, test "x$HAVE_GALLIUM_NOUVEAU" = xyes)
>  AM_CONDITIONAL(HAVE_GALLIUM_FREEDRENO, test "x$HAVE_GALLIUM_FREEDRENO" = xyes)
>  AM_CONDITIONAL(HAVE_GALLIUM_ETNAVIV, test "x$HAVE_GALLIUM_ETNAVIV" = xyes)
>  AM_CONDITIONAL(HAVE_GALLIUM_IMX, test "x$HAVE_GALLIUM_IMX" = xyes)
> +AM_CONDITIONAL(HAVE_GALLIUM_TEGRA, test "x$HAVE_GALLIUM_TEGRA" = xyes)
>  AM_CONDITIONAL(HAVE_GALLIUM_SOFTPIPE, test "x$HAVE_GALLIUM_SOFTPIPE" = xyes)
>  AM_CONDITIONAL(HAVE_GALLIUM_LLVMPIPE, test "x$HAVE_GALLIUM_LLVMPIPE" = xyes)
>  AM_CONDITIONAL(HAVE_GALLIUM_SWR, test "x$HAVE_GALLIUM_SWR" = xyes)
> @@ -2965,6 +2973,7 @@ AC_CONFIG_FILES([Makefile
>                   src/gallium/drivers/softpipe/Makefile
>                   src/gallium/drivers/svga/Makefile
>                   src/gallium/drivers/swr/Makefile
> +                 src/gallium/drivers/tegra/Makefile
>                   src/gallium/drivers/trace/Makefile
>                   src/gallium/drivers/etnaviv/Makefile
>                   src/gallium/drivers/imx/Makefile
> @@ -3013,6 +3022,7 @@ AC_CONFIG_FILES([Makefile
>                   src/gallium/winsys/sw/null/Makefile
>                   src/gallium/winsys/sw/wrapper/Makefile
>                   src/gallium/winsys/sw/xlib/Makefile
> +                 src/gallium/winsys/tegra/drm/Makefile
>                   src/gallium/winsys/vc4/drm/Makefile
>                   src/gallium/winsys/vc5/drm/Makefile
>                   src/gallium/winsys/virgl/drm/Makefile
> diff --git a/include/drm-uapi/tegra_drm.h b/include/drm-uapi/tegra_drm.h
> new file mode 100644
> index 000000000000..910cbe02d873
> --- /dev/null
> +++ b/include/drm-uapi/tegra_drm.h
> @@ -0,0 +1,225 @@
> +/*
> + * Copyright (c) 2012-2013, NVIDIA CORPORATION.  All rights reserved.
> + *
> + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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_DRM_H_
> +#define _TEGRA_DRM_H_
> +
> +#include "drm.h"
> +
> +#if defined(__cplusplus)
> +extern "C" {
> +#endif
> +
> +#define DRM_TEGRA_GEM_CREATE_TILED     (1 << 0)
> +#define DRM_TEGRA_GEM_CREATE_BOTTOM_UP (1 << 1)
> +
> +struct drm_tegra_gem_create {
> +	__u64 size;
> +	__u32 flags;
> +	__u32 handle;
> +};
> +
> +struct drm_tegra_gem_mmap {
> +	__u32 handle;
> +	__u32 pad;
> +	__u64 offset;
> +};
> +
> +struct drm_tegra_syncpt_read {
> +	__u32 id;
> +	__u32 value;
> +};
> +
> +struct drm_tegra_syncpt_incr {
> +	__u32 id;
> +	__u32 pad;
> +};
> +
> +struct drm_tegra_syncpt_wait {
> +	__u32 id;
> +	__u32 thresh;
> +	__u32 timeout;
> +	__u32 value;
> +};
> +
> +#define DRM_TEGRA_NO_TIMEOUT	(0xffffffff)
> +
> +struct drm_tegra_open_channel {
> +	__u32 client;
> +	__u32 pad;
> +	__u64 context;
> +};
> +
> +struct drm_tegra_close_channel {
> +	__u64 context;
> +};
> +
> +struct drm_tegra_get_syncpt {
> +	__u64 context;
> +	__u32 index;
> +	__u32 id;
> +};
> +
> +struct drm_tegra_get_syncpt_base {
> +	__u64 context;
> +	__u32 syncpt;
> +	__u32 id;
> +};
> +
> +struct drm_tegra_syncpt {
> +	__u32 id;
> +	__u32 incrs;
> +};
> +
> +struct drm_tegra_cmdbuf {
> +	__u32 handle;
> +	__u32 offset;
> +	__u32 words;
> +	__u32 pad;
> +};
> +
> +struct drm_tegra_reloc {
> +	struct {
> +		__u32 handle;
> +		__u32 offset;
> +	} cmdbuf;
> +	struct {
> +		__u32 handle;
> +		__u32 offset;
> +	} target;
> +	__u32 shift;
> +	__u32 pad;
> +};
> +
> +struct drm_tegra_waitchk {
> +	__u32 handle;
> +	__u32 offset;
> +	__u32 syncpt;
> +	__u32 thresh;
> +};
> +
> +#define DRM_TEGRA_FENCE_WAIT	(1 << 0)
> +#define DRM_TEGRA_FENCE_EMIT	(1 << 1)
> +#define DRM_TEGRA_FENCE_FD	(1 << 2)
> +#define DRM_TEGRA_FENCE_FLAGS	(DRM_TEGRA_FENCE_WAIT | \
> +				 DRM_TEGRA_FENCE_EMIT | \
> +				 DRM_TEGRA_FENCE_FD)
> +
> +struct drm_tegra_fence {
> +	__u32 handle;
> +	__u32 flags;
> +};
> +
> +#define DRM_TEGRA_SUBMIT_FLAGS	0
> +
> +struct drm_tegra_submit {
> +	__u64 context;
> +	__u32 num_syncpts;
> +	__u32 num_cmdbufs;
> +	__u32 num_relocs;
> +	__u32 num_waitchks;
> +	__u32 waitchk_mask;
> +	__u32 timeout;
> +	__u64 syncpts;
> +	__u64 cmdbufs;
> +	__u64 relocs;
> +	__u64 waitchks;
> +	__u32 flags;
> +	__u32 num_fences;
> +	__u64 fences;
> +
> +	__u32 reserved[2];	/* future expansion */
> +};
> +
> +#define DRM_TEGRA_GEM_TILING_MODE_PITCH 0
> +#define DRM_TEGRA_GEM_TILING_MODE_TILED 1
> +#define DRM_TEGRA_GEM_TILING_MODE_BLOCK 2
> +
> +struct drm_tegra_gem_set_tiling {
> +	/* input */
> +	__u32 handle;
> +	__u32 mode;
> +	__u32 value;
> +	__u32 pad;
> +};
> +
> +struct drm_tegra_gem_get_tiling {
> +	/* input */
> +	__u32 handle;
> +	/* output */
> +	__u32 mode;
> +	__u32 value;
> +	__u32 pad;
> +};
> +
> +#define DRM_TEGRA_GEM_BOTTOM_UP		(1 << 0)
> +#define DRM_TEGRA_GEM_FLAGS		(DRM_TEGRA_GEM_BOTTOM_UP)
> +
> +struct drm_tegra_gem_set_flags {
> +	/* input */
> +	__u32 handle;
> +	/* output */
> +	__u32 flags;
> +};
> +
> +struct drm_tegra_gem_get_flags {
> +	/* input */
> +	__u32 handle;
> +	/* output */
> +	__u32 flags;
> +};
> +
> +#define DRM_TEGRA_GEM_CREATE		0x00
> +#define DRM_TEGRA_GEM_MMAP		0x01
> +#define DRM_TEGRA_SYNCPT_READ		0x02
> +#define DRM_TEGRA_SYNCPT_INCR		0x03
> +#define DRM_TEGRA_SYNCPT_WAIT		0x04
> +#define DRM_TEGRA_OPEN_CHANNEL		0x05
> +#define DRM_TEGRA_CLOSE_CHANNEL		0x06
> +#define DRM_TEGRA_GET_SYNCPT		0x07
> +#define DRM_TEGRA_SUBMIT		0x08
> +#define DRM_TEGRA_GET_SYNCPT_BASE	0x09
> +#define DRM_TEGRA_GEM_SET_TILING	0x0a
> +#define DRM_TEGRA_GEM_GET_TILING	0x0b
> +#define DRM_TEGRA_GEM_SET_FLAGS		0x0c
> +#define DRM_TEGRA_GEM_GET_FLAGS		0x0d
> +
> +#define DRM_IOCTL_TEGRA_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_CREATE, struct drm_tegra_gem_create)
> +#define DRM_IOCTL_TEGRA_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_MMAP, struct drm_tegra_gem_mmap)
> +#define DRM_IOCTL_TEGRA_SYNCPT_READ DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SYNCPT_READ, struct drm_tegra_syncpt_read)
> +#define DRM_IOCTL_TEGRA_SYNCPT_INCR DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SYNCPT_INCR, struct drm_tegra_syncpt_incr)
> +#define DRM_IOCTL_TEGRA_SYNCPT_WAIT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SYNCPT_WAIT, struct drm_tegra_syncpt_wait)
> +#define DRM_IOCTL_TEGRA_OPEN_CHANNEL DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_OPEN_CHANNEL, struct drm_tegra_open_channel)
> +#define DRM_IOCTL_TEGRA_CLOSE_CHANNEL DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_CLOSE_CHANNEL, struct drm_tegra_open_channel)
> +#define DRM_IOCTL_TEGRA_GET_SYNCPT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GET_SYNCPT, struct drm_tegra_get_syncpt)
> +#define DRM_IOCTL_TEGRA_SUBMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SUBMIT, struct drm_tegra_submit)
> +#define DRM_IOCTL_TEGRA_GET_SYNCPT_BASE DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GET_SYNCPT_BASE, struct drm_tegra_get_syncpt_base)
> +#define DRM_IOCTL_TEGRA_GEM_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_SET_TILING, struct drm_tegra_gem_set_tiling)
> +#define DRM_IOCTL_TEGRA_GEM_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_GET_TILING, struct drm_tegra_gem_get_tiling)
> +#define DRM_IOCTL_TEGRA_GEM_SET_FLAGS DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_SET_FLAGS, struct drm_tegra_gem_set_flags)
> +#define DRM_IOCTL_TEGRA_GEM_GET_FLAGS DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_GET_FLAGS, struct drm_tegra_gem_get_flags)
> +
> +#if defined(__cplusplus)
> +}
> +#endif
> +
> +#endif /* _TEGRA_DRM_H_ */
> diff --git a/meson.build b/meson.build
> index e9928a379313..83e06c1a4a39 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -133,6 +133,7 @@ with_gallium_vc4 = false
>  with_gallium_vc5 = false
>  with_gallium_etnaviv = false
>  with_gallium_imx = false
> +with_gallium_tegra = false
>  with_gallium_i915 = false
>  with_gallium_svga = false
>  with_gallium_virgl = false
> @@ -144,7 +145,7 @@ if _drivers == 'auto'
>      if ['x86', 'x86_64'].contains(host_machine.cpu_family())
>        _drivers = 'r300,r600,radeonsi,nouveau,virgl,svga,swrast'
>      elif ['arm', 'aarch64'].contains(host_machine.cpu_family())
> -      _drivers = 'pl111,vc4,vc5,freedreno,etnaviv,imx,virgl,svga,swrast'
> +      _drivers = 'pl111,vc4,vc5,freedreno,etnaviv,imx,nouveau,tegra,virgl,svga,swrast'
>      else
>        error('Unknown architecture. Please pass -Dgallium-drivers to set driver options. Patches gladly accepted to fix this.')
>      endif
> @@ -167,6 +168,7 @@ if _drivers != ''
>    with_gallium_vc5 = _split.contains('vc5')
>    with_gallium_etnaviv = _split.contains('etnaviv')
>    with_gallium_imx = _split.contains('imx')
> +  with_gallium_tegra = _split.contains('tegra')
>    with_gallium_i915 = _split.contains('i915')
>    with_gallium_svga = _split.contains('svga')
>    with_gallium_virgl = _split.contains('virgl')
> @@ -211,6 +213,9 @@ endif
>  if with_gallium_pl111 and not with_gallium_vc4
>    error('pl111 driver requires vc4 driver')
>  endif
> +if with_gallium_tegra and not with_gallium_nouveau
> +  error('tegra driver requires nouveau driver')
> +endif
>  
>  dep_libdrm_intel = []
>  if with_dri_i915 or with_gallium_i915
> diff --git a/src/gallium/Makefile.am b/src/gallium/Makefile.am
> index af010c89f8d9..cd1447f9e12b 100644
> --- a/src/gallium/Makefile.am
> +++ b/src/gallium/Makefile.am
> @@ -89,6 +89,11 @@ if HAVE_GALLIUM_SWR
>  SUBDIRS += drivers/swr
>  endif
>  
> +## tegra
> +if HAVE_GALLIUM_TEGRA
> +SUBDIRS += drivers/tegra winsys/tegra/drm
> +endif
> +
>  ## vc4/rpi
>  if HAVE_GALLIUM_VC4
>  SUBDIRS += drivers/vc4 winsys/vc4/drm
> diff --git a/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c b/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c
> index 810542101ede..b6be1b4f1270 100644
> --- a/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c
> +++ b/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c
> @@ -134,7 +134,12 @@ static const struct drm_driver_descriptor driver_descriptors[] = {
>          .driver_name = "imx-drm",
>          .create_screen = pipe_imx_drm_create_screen,
>          .configuration = pipe_default_configuration_query,
> -    }
> +    },
> +    {
> +        .driver_name = "tegra",
> +        .create_screen = pipe_tegra_create_screen,
> +        .configuration = pipe_default_configuration_query,
> +    },
>  };
>  #endif
>  
> diff --git a/src/gallium/auxiliary/target-helpers/drm_helper.h b/src/gallium/auxiliary/target-helpers/drm_helper.h
> index 7aea83b8842c..7dc2497c0879 100644
> --- a/src/gallium/auxiliary/target-helpers/drm_helper.h
> +++ b/src/gallium/auxiliary/target-helpers/drm_helper.h
> @@ -379,5 +379,28 @@ pipe_imx_drm_create_screen(int fd, const struct pipe_screen_config *config)
>  
>  #endif
>  
> +#ifdef GALLIUM_TEGRA
> +#include "tegra/drm/tegra_drm_public.h"
> +
> +struct pipe_screen *
> +pipe_tegra_create_screen(int fd, const struct pipe_screen_config *config)
> +{
> +   struct pipe_screen *screen;
> +
> +   screen = tegra_drm_screen_create(fd);
> +
> +   return screen ? debug_screen_wrap(screen) : NULL;
> +}
> +
> +#else
> +
> +struct pipe_screen *
> +pipe_tegra_create_screen(int fd, const struct pipe_screen_config *config)
> +{
> +   fprintf(stderr, "tegra: driver missing\n");
> +   return NULL;
> +}
> +
> +#endif
>  
>  #endif /* DRM_HELPER_H */
> diff --git a/src/gallium/auxiliary/target-helpers/drm_helper_public.h b/src/gallium/auxiliary/target-helpers/drm_helper_public.h
> index e21ea32fabe0..c1a7bf4e2520 100644
> --- a/src/gallium/auxiliary/target-helpers/drm_helper_public.h
> +++ b/src/gallium/auxiliary/target-helpers/drm_helper_public.h
> @@ -51,6 +51,9 @@ pipe_etna_create_screen(int fd, const struct pipe_screen_config *config);
>  struct pipe_screen *
>  pipe_imx_drm_create_screen(int fd, const struct pipe_screen_config *config);
>  
> +struct pipe_screen *
> +pipe_tegra_create_screen(int fd, const struct pipe_screen_config *config);
> +
>  const struct drm_conf_ret *
>  pipe_default_configuration_query(enum drm_conf conf);
>  
> diff --git a/src/gallium/drivers/tegra/Automake.inc b/src/gallium/drivers/tegra/Automake.inc
> new file mode 100644
> index 000000000000..f65281916245
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/Automake.inc
> @@ -0,0 +1,11 @@
> +if HAVE_GALLIUM_TEGRA
> +
> +TARGET_DRIVERS += tegra
> +TARGET_CPPFLAGS += -DGALLIUM_TEGRA
> +TARGET_LIB_DEPS += \
> +	$(top_builddir)/src/gallium/winsys/tegra/drm/libtegradrm.la \
> +	$(top_builddir)/src/gallium/drivers/tegra/libtegra.la \
> +	$(LIBDRM_LIBS) \
> +	$(TEGRA_LIBS)
> +
> +endif
> diff --git a/src/gallium/drivers/tegra/Makefile.am b/src/gallium/drivers/tegra/Makefile.am
> new file mode 100644
> index 000000000000..7e87ea048733
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/Makefile.am
> @@ -0,0 +1,11 @@
> +include Makefile.sources
> +include $(top_srcdir)/src/gallium/Automake.inc
> +
> +AM_CFLAGS = \
> +	-I$(top_srcdir)/include/drm-uapi \
> +	$(GALLIUM_DRIVER_CFLAGS)
> +
> +noinst_LTLIBRARIES = libtegra.la
> +
> +libtegra_la_SOURCES = \
> +	$(C_SOURCES)
> diff --git a/src/gallium/drivers/tegra/Makefile.sources b/src/gallium/drivers/tegra/Makefile.sources
> new file mode 100644
> index 000000000000..af4ff838c7ca
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/Makefile.sources
> @@ -0,0 +1,6 @@
> +C_SOURCES := \
> +	tegra_context.c \
> +	tegra_context.h \
> +	tegra_resource.h \
> +	tegra_screen.c \
> +	tegra_screen.h
> diff --git a/src/gallium/drivers/tegra/meson.build b/src/gallium/drivers/tegra/meson.build
> new file mode 100644
> index 000000000000..79ccd143f292
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/meson.build
> @@ -0,0 +1,41 @@
> +# 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 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.
> +
> +files_tegra = files(
> +  'tegra_context.c',
> +  'tegra_context.h',
> +  'tegra_resource.h',
> +  'tegra_screen.c',
> +)
> +
> +libtegra = static_library(
> +  'tegra',
> +  files_tegra,
> +  c_args : [c_vis_args],
> +  include_directories : [
> +    inc_include, inc_src, inc_gallium, inc_gallium_aux, inc_gallium_drivers,
> +    inc_gallium_winsys, inc_drm_uapi
> +  ],
> +)
> +
> +driver_tegra = declare_dependency(
> +  compile_args : '-DGALLIUM_TEGRA',
> +  link_with : [libtegra, libtegradrm],
> +)
> diff --git a/src/gallium/drivers/tegra/tegra_context.c b/src/gallium/drivers/tegra/tegra_context.c
> new file mode 100644
> index 000000000000..34ffa4cf06c5
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/tegra_context.c
> @@ -0,0 +1,1325 @@
> +/*
> + * Copyright © 2014-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 <inttypes.h>
> +#include <stdlib.h>
> +
> +#include "util/u_debug.h"
> +#include "util/u_inlines.h"
> +#include "util/u_upload_mgr.h"
> +
> +#include "tegra_context.h"
> +#include "tegra_resource.h"
> +#include "tegra_screen.h"
> +
> +static void
> +tegra_destroy(struct pipe_context *pcontext)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   if (context->base.stream_uploader)
> +      u_upload_destroy(context->base.stream_uploader);
> +
> +   context->gpu->destroy(context->gpu);
> +   free(context);
> +}
> +
> +static void
> +tegra_draw_vbo(struct pipe_context *pcontext,
> +               const struct pipe_draw_info *pinfo)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +   struct pipe_draw_indirect_info indirect;
> +   struct pipe_draw_info info;
> +
> +   if (pinfo && (pinfo->indirect || pinfo->index_size)) {
> +      memcpy(&info, pinfo, sizeof(info));
> +
> +      if (pinfo->indirect) {
> +         memcpy(&indirect, pinfo->indirect, sizeof(indirect));
> +         indirect.buffer = tegra_resource_unwrap(info.indirect->buffer);
> +         info.indirect = &indirect;
> +      }
> +
> +      if (pinfo->index_size && !pinfo->has_user_indices)
> +         info.index.resource = tegra_resource_unwrap(info.index.resource);
> +
> +      pinfo = &info;
> +   }
> +
> +   context->gpu->draw_vbo(context->gpu, pinfo);
> +}
> +
> +static void
> +tegra_render_condition(struct pipe_context *pcontext,
> +                       struct pipe_query *query,
> +                       boolean condition,
> +                       unsigned int mode)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->render_condition(context->gpu, query, condition, mode);
> +}
> +
> +static struct pipe_query *
> +tegra_create_query(struct pipe_context *pcontext, unsigned int query_type,
> +                   unsigned int index)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->create_query(context->gpu, query_type, index);
> +}
> +
> +static struct pipe_query *
> +tegra_create_batch_query(struct pipe_context *pcontext,
> +                         unsigned int num_queries,
> +                         unsigned int *queries)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->create_batch_query(context->gpu, num_queries,
> +                                           queries);
> +}
> +
> +static void
> +tegra_destroy_query(struct pipe_context *pcontext, struct pipe_query *query)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->destroy_query(context->gpu, query);
> +}
> +
> +static boolean
> +tegra_begin_query(struct pipe_context *pcontext, struct pipe_query *query)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->begin_query(context->gpu, query);
> +}
> +
> +static bool
> +tegra_end_query(struct pipe_context *pcontext, struct pipe_query *query)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->end_query(context->gpu, query);
> +}
> +
> +static boolean
> +tegra_get_query_result(struct pipe_context *pcontext,
> +                       struct pipe_query *query,
> +                       boolean wait,
> +                       union pipe_query_result *result)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->get_query_result(context->gpu, query, wait,
> +                     result);
> +}
> +
> +static void
> +tegra_get_query_result_resource(struct pipe_context *pcontext,
> +                                struct pipe_query *query,
> +                                boolean wait,
> +                                enum pipe_query_value_type result_type,
> +                                int index,
> +                                struct pipe_resource *resource,
> +                                unsigned int offset)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->get_query_result_resource(context->gpu, query, wait,
> +                                           result_type, index, resource,
> +                                           offset);
> +}
> +
> +static void
> +tegra_set_active_query_state(struct pipe_context *pcontext, boolean enable)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->set_active_query_state(context->gpu, enable);
> +}
> +
> +static void *
> +tegra_create_blend_state(struct pipe_context *pcontext,
> +                         const struct pipe_blend_state *cso)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->create_blend_state(context->gpu, cso);
> +}
> +
> +static void
> +tegra_bind_blend_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->bind_blend_state(context->gpu, so);
> +}
> +
> +static void
> +tegra_delete_blend_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->delete_blend_state(context->gpu, so);
> +}
> +
> +static void *
> +tegra_create_sampler_state(struct pipe_context *pcontext,
> +                           const struct pipe_sampler_state *cso)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->create_sampler_state(context->gpu, cso);
> +}
> +
> +static void
> +tegra_bind_sampler_states(struct pipe_context *pcontext, unsigned shader,
> +                          unsigned start_slot, unsigned num_samplers,
> +                          void **samplers)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->bind_sampler_states(context->gpu, shader, start_slot,
> +                                     num_samplers, samplers);
> +}
> +
> +static void
> +tegra_delete_sampler_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->delete_sampler_state(context->gpu, so);
> +}
> +
> +static void *
> +tegra_create_rasterizer_state(struct pipe_context *pcontext,
> +                              const struct pipe_rasterizer_state *cso)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->create_rasterizer_state(context->gpu, cso);
> +}
> +
> +static void
> +tegra_bind_rasterizer_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->bind_rasterizer_state(context->gpu, so);
> +}
> +
> +static void
> +tegra_delete_rasterizer_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->delete_rasterizer_state(context->gpu, so);
> +}
> +
> +static void *
> +tegra_create_depth_stencil_alpha_state(struct pipe_context *pcontext,
> +                                       const struct pipe_depth_stencil_alpha_state *cso)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->create_depth_stencil_alpha_state(context->gpu, cso);
> +}
> +
> +static void
> +tegra_bind_depth_stencil_alpha_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->bind_depth_stencil_alpha_state(context->gpu, so);
> +}
> +
> +static void
> +tegra_delete_depth_stencil_alpha_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->delete_depth_stencil_alpha_state(context->gpu, so);
> +}
> +
> +static void *
> +tegra_create_fs_state(struct pipe_context *pcontext,
> +                      const struct pipe_shader_state *cso)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->create_fs_state(context->gpu, cso);
> +}
> +
> +static void
> +tegra_bind_fs_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->bind_fs_state(context->gpu, so);
> +}
> +
> +static void
> +tegra_delete_fs_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->delete_fs_state(context->gpu, so);
> +}
> +
> +static void *
> +tegra_create_vs_state(struct pipe_context *pcontext,
> +                      const struct pipe_shader_state *cso)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->create_vs_state(context->gpu, cso);
> +}
> +
> +static void
> +tegra_bind_vs_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->bind_vs_state(context->gpu, so);
> +}
> +
> +static void
> +tegra_delete_vs_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->delete_vs_state(context->gpu, so);
> +}
> +
> +static void *
> +tegra_create_gs_state(struct pipe_context *pcontext,
> +                      const struct pipe_shader_state *cso)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->create_gs_state(context->gpu, cso);
> +}
> +
> +static void
> +tegra_bind_gs_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->bind_gs_state(context->gpu, so);
> +}
> +
> +static void
> +tegra_delete_gs_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->delete_gs_state(context->gpu, so);
> +}
> +
> +static void *
> +tegra_create_tcs_state(struct pipe_context *pcontext,
> +                       const struct pipe_shader_state *cso)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->create_tcs_state(context->gpu, cso);
> +}
> +
> +static void
> +tegra_bind_tcs_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->bind_tcs_state(context->gpu, so);
> +}
> +
> +static void
> +tegra_delete_tcs_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->delete_tcs_state(context->gpu, so);
> +}
> +
> +static void *
> +tegra_create_tes_state(struct pipe_context *pcontext,
> +                       const struct pipe_shader_state *cso)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->create_tes_state(context->gpu, cso);
> +}
> +
> +static void
> +tegra_bind_tes_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->bind_tes_state(context->gpu, so);
> +}
> +
> +static void
> +tegra_delete_tes_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->delete_tes_state(context->gpu, so);
> +}
> +
> +static void *
> +tegra_create_vertex_elements_state(struct pipe_context *pcontext,
> +                                   unsigned num_elements,
> +                                   const struct pipe_vertex_element *elements)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->create_vertex_elements_state(context->gpu,
> +                                                     num_elements,
> +                                                     elements);
> +}
> +
> +static void
> +tegra_bind_vertex_elements_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->bind_vertex_elements_state(context->gpu, so);
> +}
> +
> +static void
> +tegra_delete_vertex_elements_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->delete_vertex_elements_state(context->gpu, so);
> +}
> +
> +static void
> +tegra_set_blend_color(struct pipe_context *pcontext,
> +                      const struct pipe_blend_color *color)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->set_blend_color(context->gpu, color);
> +}
> +
> +static void
> +tegra_set_stencil_ref(struct pipe_context *pcontext,
> +                      const struct pipe_stencil_ref *ref)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->set_stencil_ref(context->gpu, ref);
> +}
> +
> +static void
> +tegra_set_sample_mask(struct pipe_context *pcontext, unsigned int mask)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->set_sample_mask(context->gpu, mask);
> +}
> +
> +static void
> +tegra_set_min_samples(struct pipe_context *pcontext, unsigned int samples)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->set_min_samples(context->gpu, samples);
> +}
> +
> +static void
> +tegra_set_clip_state(struct pipe_context *pcontext,
> +                     const struct pipe_clip_state *state)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->set_clip_state(context->gpu, state);
> +}
> +
> +static void
> +tegra_set_constant_buffer(struct pipe_context *pcontext, unsigned int shader,
> +                          unsigned int index,
> +                          const struct pipe_constant_buffer *buf)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +   struct pipe_constant_buffer buffer;
> +
> +   if (buf && buf->buffer) {
> +      memcpy(&buffer, buf, sizeof(buffer));
> +      buffer.buffer = tegra_resource_unwrap(buffer.buffer);
> +      buf = &buffer;
> +   }
> +
> +   context->gpu->set_constant_buffer(context->gpu, shader, index, buf);
> +}
> +
> +static void
> +tegra_set_framebuffer_state(struct pipe_context *pcontext,
> +                            const struct pipe_framebuffer_state *fb)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +   struct pipe_framebuffer_state state;
> +   unsigned i;
> +
> +   if (fb) {
> +      memcpy(&state, fb, sizeof(state));
> +
> +      for (i = 0; i < fb->nr_cbufs; i++)
> +         state.cbufs[i] = tegra_surface_unwrap(fb->cbufs[i]);
> +
> +      while (i < PIPE_MAX_COLOR_BUFS)
> +         state.cbufs[i++] = NULL;
> +
> +      state.zsbuf = tegra_surface_unwrap(fb->zsbuf);
> +
> +      fb = &state;
> +   }
> +
> +   context->gpu->set_framebuffer_state(context->gpu, fb);
> +}
> +
> +static void
> +tegra_set_polygon_stipple(struct pipe_context *pcontext,
> +                          const struct pipe_poly_stipple *stipple)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->set_polygon_stipple(context->gpu, stipple);
> +}
> +
> +static void
> +tegra_set_scissor_states(struct pipe_context *pcontext, unsigned start_slot,
> +                         unsigned num_scissors,
> +                         const struct pipe_scissor_state *scissors)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->set_scissor_states(context->gpu, start_slot, num_scissors,
> +                                    scissors);
> +}
> +
> +static void
> +tegra_set_window_rectangles(struct pipe_context *pcontext, boolean include,
> +                            unsigned int num_rectangles,
> +                            const struct pipe_scissor_state *rectangles)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->set_window_rectangles(context->gpu, include, num_rectangles,
> +                                       rectangles);
> +}
> +
> +static void
> +tegra_set_viewport_states(struct pipe_context *pcontext, unsigned start_slot,
> +                          unsigned num_viewports,
> +                          const struct pipe_viewport_state *viewports)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->set_viewport_states(context->gpu, start_slot, num_viewports,
> +                                     viewports);
> +}
> +
> +static void
> +tegra_set_sampler_views(struct pipe_context *pcontext, unsigned shader,
> +                        unsigned start_slot, unsigned num_views,
> +                        struct pipe_sampler_view **pviews)
> +{
> +   struct pipe_sampler_view *views[PIPE_MAX_SHADER_SAMPLER_VIEWS];
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +   unsigned i;
> +
> +   for (i = 0; i < num_views; i++)
> +      views[i] = tegra_sampler_view_unwrap(pviews[i]);
> +
> +   context->gpu->set_sampler_views(context->gpu, shader, start_slot,
> +                                   num_views, views);
> +}
> +
> +static void
> +tegra_set_tess_state(struct pipe_context *pcontext,
> +                     const float default_outer_level[4],
> +                     const float default_inner_level[2])
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->set_tess_state(context->gpu, default_outer_level,
> +                                default_inner_level);
> +}
> +
> +static void
> +tegra_set_debug_callback(struct pipe_context *pcontext,
> +                         const struct pipe_debug_callback *callback)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->set_debug_callback(context->gpu, callback);
> +}
> +
> +static void
> +tegra_set_shader_buffers(struct pipe_context *pcontext, unsigned int shader,
> +                         unsigned start, unsigned count,
> +                         const struct pipe_shader_buffer *buffers)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->set_shader_buffers(context->gpu, shader, start, count,
> +                                    buffers);
> +}
> +
> +static void
> +tegra_set_shader_images(struct pipe_context *pcontext, unsigned int shader,
> +                        unsigned start, unsigned count,
> +                        const struct pipe_image_view *images)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->set_shader_images(context->gpu, shader, start, count,
> +                                   images);
> +}
> +
> +static void
> +tegra_set_vertex_buffers(struct pipe_context *pcontext, unsigned start_slot,
> +                         unsigned num_buffers,
> +                         const struct pipe_vertex_buffer *buffers)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +   struct pipe_vertex_buffer buf[PIPE_MAX_SHADER_INPUTS];
> +   unsigned i;
> +
> +   if (num_buffers && buffers) {
> +      memcpy(buf, buffers, num_buffers * sizeof(struct pipe_vertex_buffer));
> +
> +      for (i = 0; i < num_buffers; i++) {
> +         if (!buf[i].is_user_buffer)
> +            buf[i].buffer.resource = tegra_resource_unwrap(buf[i].buffer.resource);
> +      }
> +
> +      buffers = buf;
> +   }
> +
> +   context->gpu->set_vertex_buffers(context->gpu, start_slot, num_buffers,
> +                                    buffers);
> +}
> +
> +static struct pipe_stream_output_target *
> +tegra_create_stream_output_target(struct pipe_context *pcontext,
> +                                  struct pipe_resource *presource,
> +                                  unsigned buffer_offset,
> +                                  unsigned buffer_size)
> +{
> +   struct tegra_resource *resource = to_tegra_resource(presource);
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->create_stream_output_target(context->gpu,
> +                                                    resource->gpu,
> +                                                    buffer_offset,
> +                                                    buffer_size);
> +}
> +
> +static void
> +tegra_stream_output_target_destroy(struct pipe_context *pcontext,
> +                                   struct pipe_stream_output_target *target)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->stream_output_target_destroy(context->gpu, target);
> +}
> +
> +static void
> +tegra_set_stream_output_targets(struct pipe_context *pcontext,
> +                                unsigned num_targets,
> +                                struct pipe_stream_output_target **targets,
> +                                const unsigned *offsets)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->set_stream_output_targets(context->gpu, num_targets,
> +                                           targets, offsets);
> +}
> +
> +static void
> +tegra_resource_copy_region(struct pipe_context *pcontext,
> +                           struct pipe_resource *pdst,
> +                           unsigned int dst_level,
> +                           unsigned int dstx,
> +                           unsigned int dsty,
> +                           unsigned int dstz,
> +                           struct pipe_resource *psrc,
> +                           unsigned int src_level,
> +                           const struct pipe_box *src_box)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +   struct tegra_resource *dst = to_tegra_resource(pdst);
> +   struct tegra_resource *src = to_tegra_resource(psrc);
> +
> +   context->gpu->resource_copy_region(context->gpu, dst->gpu, dst_level, dstx,
> +                                      dsty, dstz, src->gpu, src_level,
> +                                      src_box);
> +}
> +
> +static void
> +tegra_blit(struct pipe_context *pcontext, const struct pipe_blit_info *pinfo)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +   struct pipe_blit_info info;
> +
> +   if (pinfo) {
> +      memcpy(&info, pinfo, sizeof(info));
> +      info.dst.resource = tegra_resource_unwrap(info.dst.resource);
> +      info.src.resource = tegra_resource_unwrap(info.src.resource);
> +      pinfo = &info;
> +   }
> +
> +   context->gpu->blit(context->gpu, pinfo);
> +}
> +
> +static void
> +tegra_clear(struct pipe_context *pcontext, unsigned buffers,
> +            const union pipe_color_union *color, double depth,
> +            unsigned stencil)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->clear(context->gpu, buffers, color, depth, stencil);
> +}
> +
> +static void
> +tegra_clear_render_target(struct pipe_context *pcontext,
> +                          struct pipe_surface *pdst,
> +                          const union pipe_color_union *color,
> +                          unsigned int dstx,
> +                          unsigned int dsty,
> +                          unsigned int width,
> +                          unsigned int height,
> +                          bool render_condition)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +   struct tegra_surface *dst = to_tegra_surface(pdst);
> +
> +   context->gpu->clear_render_target(context->gpu, dst->gpu, color, dstx,
> +                                     dsty, width, height, render_condition);
> +}
> +
> +static void
> +tegra_clear_depth_stencil(struct pipe_context *pcontext,
> +                          struct pipe_surface *pdst,
> +                          unsigned int flags,
> +                          double depth,
> +                          unsigned int stencil,
> +                          unsigned int dstx,
> +                          unsigned int dsty,
> +                          unsigned int width,
> +                          unsigned int height,
> +                          bool render_condition)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +   struct tegra_surface *dst = to_tegra_surface(pdst);
> +
> +   context->gpu->clear_depth_stencil(context->gpu, dst->gpu, flags, depth,
> +                                     stencil, dstx, dsty, width, height,
> +                                     render_condition);
> +}
> +
> +static void
> +tegra_clear_texture(struct pipe_context *pcontext,
> +                    struct pipe_resource *presource,
> +                    unsigned int level,
> +                    const struct pipe_box *box,
> +                    const void *data)
> +{
> +   struct tegra_resource *resource = to_tegra_resource(presource);
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->clear_texture(context->gpu, resource->gpu, level, box, data);
> +}
> +
> +static void
> +tegra_clear_buffer(struct pipe_context *pcontext,
> +                   struct pipe_resource *presource,
> +                   unsigned int offset,
> +                   unsigned int size,
> +                   const void *value,
> +                   int value_size)
> +{
> +   struct tegra_resource *resource = to_tegra_resource(presource);
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->clear_buffer(context->gpu, resource->gpu, offset, size,
> +                              value, value_size);
> +}
> +
> +static void
> +tegra_flush(struct pipe_context *pcontext, struct pipe_fence_handle **fence,
> +            unsigned flags)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->flush(context->gpu, fence, flags);
> +}
> +
> +static void
> +tegra_create_fence_fd(struct pipe_context *pcontext,
> +                      struct pipe_fence_handle **fence,
> +                      int fd, enum pipe_fd_type type)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   assert(type == PIPE_FD_TYPE_NATIVE_SYNC);
> +   context->gpu->create_fence_fd(context->gpu, fence, fd, type);
> +}
> +
> +static void
> +tegra_fence_server_sync(struct pipe_context *pcontext,
> +                        struct pipe_fence_handle *fence)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->fence_server_sync(context->gpu, fence);
> +}
> +
> +static struct pipe_sampler_view *
> +tegra_create_sampler_view(struct pipe_context *pcontext,
> +                          struct pipe_resource *presource,
> +                          const struct pipe_sampler_view *template)
> +{
> +   struct tegra_resource *resource = to_tegra_resource(presource);
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +   struct tegra_sampler_view *view;
> +
> +   view = calloc(1, sizeof(*view));
> +   if (!view)
> +      return NULL;
> +
> +   view->gpu = context->gpu->create_sampler_view(context->gpu, resource->gpu,
> +                                                 template);
> +   memcpy(&view->base, view->gpu, sizeof(*view->gpu));
> +   /* overwrite to prevent reference from being released */
> +   view->base.texture = NULL;
> +
> +   pipe_reference_init(&view->base.reference, 1);
> +   pipe_resource_reference(&view->base.texture, presource);
> +   view->base.context = pcontext;
> +
> +   return &view->base;
> +}
> +
> +static void
> +tegra_sampler_view_destroy(struct pipe_context *pcontext,
> +                           struct pipe_sampler_view *pview)
> +{
> +   struct tegra_sampler_view *view = to_tegra_sampler_view(pview);
> +
> +   pipe_resource_reference(&view->base.texture, NULL);
> +   pipe_sampler_view_reference(&view->gpu, NULL);
> +   free(view);
> +}
> +
> +static struct pipe_surface *
> +tegra_create_surface(struct pipe_context *pcontext,
> +                     struct pipe_resource *presource,
> +                     const struct pipe_surface *template)
> +{
> +   struct tegra_resource *resource = to_tegra_resource(presource);
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +   struct tegra_surface *surface;
> +
> +   surface = calloc(1, sizeof(*surface));
> +   if (!surface)
> +      return NULL;
> +
> +   surface->gpu = context->gpu->create_surface(context->gpu, resource->gpu,
> +                                               template);
> +   if (!surface->gpu) {
> +      free(surface);
> +      return NULL;
> +   }
> +
> +   memcpy(&surface->base, surface->gpu, sizeof(*surface->gpu));
> +   /* overwrite to prevent reference from being released */
> +   surface->base.texture = NULL;
> +
> +   pipe_reference_init(&surface->base.reference, 1);
> +   pipe_resource_reference(&surface->base.texture, presource);
> +   surface->base.context = &context->base;
> +
> +   return &surface->base;
> +}
> +
> +static void
> +tegra_surface_destroy(struct pipe_context *pcontext,
> +                      struct pipe_surface *psurface)
> +{
> +   struct tegra_surface *surface = to_tegra_surface(psurface);
> +
> +   pipe_resource_reference(&surface->base.texture, NULL);
> +   pipe_surface_reference(&surface->gpu, NULL);
> +   free(surface);
> +}
> +
> +static void *
> +tegra_transfer_map(struct pipe_context *pcontext,
> +                   struct pipe_resource *presource,
> +                   unsigned level, unsigned usage,
> +                   const struct pipe_box *box,
> +                   struct pipe_transfer **ptransfer)
> +{
> +   struct tegra_resource *resource = to_tegra_resource(presource);
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +   struct tegra_transfer *transfer;
> +
> +   transfer = calloc(1, sizeof(*transfer));
> +   if (!transfer)
> +      return NULL;
> +
> +   transfer->map = context->gpu->transfer_map(context->gpu, resource->gpu,
> +                                              level, usage, box,
> +                                              &transfer->gpu);
> +   memcpy(&transfer->base, transfer->gpu, sizeof(*transfer->gpu));
> +   transfer->base.resource = NULL;
> +   pipe_resource_reference(&transfer->base.resource, presource);
> +
> +   *ptransfer = &transfer->base;
> +
> +   return transfer->map;
> +}
> +
> +static void
> +tegra_transfer_flush_region(struct pipe_context *pcontext,
> +                            struct pipe_transfer *ptransfer,
> +                            const struct pipe_box *box)
> +{
> +   struct tegra_transfer *transfer = to_tegra_transfer(ptransfer);
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->transfer_flush_region(context->gpu, transfer->gpu, box);
> +}
> +
> +static void
> +tegra_transfer_unmap(struct pipe_context *pcontext,
> +                     struct pipe_transfer *ptransfer)
> +{
> +   struct tegra_transfer *transfer = to_tegra_transfer(ptransfer);
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->transfer_unmap(context->gpu, transfer->gpu);
> +   pipe_resource_reference(&transfer->base.resource, NULL);
> +   free(transfer);
> +}
> +
> +static void
> +tegra_buffer_subdata(struct pipe_context *pcontext,
> +                     struct pipe_resource *presource,
> +                     unsigned usage, unsigned offset,
> +                     unsigned size, const void *data)
> +{
> +   struct tegra_resource *resource = to_tegra_resource(presource);
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->buffer_subdata(context->gpu, resource->gpu, usage, offset,
> +                                size, data);
> +}
> +
> +static void
> +tegra_texture_subdata(struct pipe_context *pcontext,
> +                      struct pipe_resource *presource,
> +                      unsigned level,
> +                      unsigned usage,
> +                      const struct pipe_box *box,
> +                      const void *data,
> +                      unsigned stride,
> +                      unsigned layer_stride)
> +{
> +   struct tegra_resource *resource = to_tegra_resource(presource);
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->texture_subdata(context->gpu, resource->gpu, level, usage,
> +                                 box, data, stride, layer_stride);
> +}
> +
> +static void
> +tegra_texture_barrier(struct pipe_context *pcontext, unsigned int flags)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->texture_barrier(context->gpu, flags);
> +}
> +
> +static void
> +tegra_memory_barrier(struct pipe_context *pcontext, unsigned int flags)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->memory_barrier(context->gpu, flags);
> +}
> +
> +static struct pipe_video_codec *
> +tegra_create_video_codec(struct pipe_context *pcontext,
> +                         const struct pipe_video_codec *template)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->create_video_codec(context->gpu, template);
> +}
> +
> +static struct pipe_video_buffer *
> +tegra_create_video_buffer(struct pipe_context *pcontext,
> +                          const struct pipe_video_buffer *template)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->create_video_buffer(context->gpu, template);
> +}
> +
> +static void *
> +tegra_create_compute_state(struct pipe_context *pcontext,
> +                           const struct pipe_compute_state *template)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->create_compute_state(context->gpu, template);
> +}
> +
> +static void
> +tegra_bind_compute_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->bind_compute_state(context->gpu, so);
> +}
> +
> +static void
> +tegra_delete_compute_state(struct pipe_context *pcontext, void *so)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->delete_compute_state(context->gpu, so);
> +}
> +
> +static void
> +tegra_set_compute_resources(struct pipe_context *pcontext,
> +                            unsigned int start, unsigned int count,
> +                            struct pipe_surface **resources)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   /* XXX unwrap resources */
> +
> +   context->gpu->set_compute_resources(context->gpu, start, count, resources);
> +}
> +
> +static void
> +tegra_set_global_binding(struct pipe_context *pcontext, unsigned int first,
> +                         unsigned int count, struct pipe_resource **resources,
> +                         uint32_t **handles)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   /* XXX unwrap resources */
> +
> +   context->gpu->set_global_binding(context->gpu, first, count, resources,
> +                                    handles);
> +}
> +
> +static void
> +tegra_launch_grid(struct pipe_context *pcontext,
> +                  const struct pipe_grid_info *info)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   /* XXX unwrap info->indirect? */
> +
> +   context->gpu->launch_grid(context->gpu, info);
> +}
> +
> +static void
> +tegra_get_sample_position(struct pipe_context *pcontext, unsigned int count,
> +                          unsigned int index, float *value)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->get_sample_position(context->gpu, count, index, value);
> +}
> +
> +static uint64_t
> +tegra_get_timestamp(struct pipe_context *pcontext)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->get_timestamp(context->gpu);
> +}
> +
> +static void
> +tegra_flush_resource(struct pipe_context *pcontext,
> +                     struct pipe_resource *presource)
> +{
> +   struct tegra_resource *resource = to_tegra_resource(presource);
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->flush_resource(context->gpu, resource->gpu);
> +}
> +
> +static void
> +tegra_invalidate_resource(struct pipe_context *pcontext,
> +                          struct pipe_resource *presource)
> +{
> +   struct tegra_resource *resource = to_tegra_resource(presource);
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->invalidate_resource(context->gpu, resource->gpu);
> +}
> +
> +static enum pipe_reset_status
> +tegra_get_device_reset_status(struct pipe_context *pcontext)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->get_device_reset_status(context->gpu);
> +}
> +
> +static void
> +tegra_set_device_reset_callback(struct pipe_context *pcontext,
> +                                const struct pipe_device_reset_callback *cb)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->set_device_reset_callback(context->gpu, cb);
> +}
> +
> +static void
> +tegra_dump_debug_state(struct pipe_context *pcontext, FILE *stream,
> +                       unsigned int flags)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->dump_debug_state(context->gpu, stream, flags);
> +}
> +
> +static void
> +tegra_emit_string_marker(struct pipe_context *pcontext, const char *string,
> +                         int length)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   context->gpu->emit_string_marker(context->gpu, string, length);
> +}
> +
> +static boolean
> +tegra_generate_mipmap(struct pipe_context *pcontext,
> +                      struct pipe_resource *presource,
> +                      enum pipe_format format,
> +                      unsigned int base_level,
> +                      unsigned int last_level,
> +                      unsigned int first_layer,
> +                      unsigned int last_layer)
> +{
> +   struct tegra_resource *resource = to_tegra_resource(presource);
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +
> +   return context->gpu->generate_mipmap(context->gpu, resource->gpu, format,
> +                                        base_level, last_level, first_layer,
> +                                        last_layer);
> +}
> +
> +struct pipe_context *
> +tegra_screen_context_create(struct pipe_screen *pscreen, void *priv,
> +                            unsigned int flags)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +   struct tegra_context *context;
> +
> +   context = calloc(1, sizeof(*context));
> +   if (!context)
> +      return NULL;
> +
> +   context->gpu = screen->gpu->context_create(screen->gpu, priv, flags);
> +   if (!context->gpu) {
> +      debug_error("failed to create GPU context\n");
> +      goto free;
> +   }
> +
> +   context->base.screen = &screen->base;
> +   context->base.priv = priv;
> +
> +   /*
> +    * Create custom stream and const uploaders. Note that technically nouveau
> +    * already creates uploaders that could be reused, but that would make the
> +    * resource unwrapping rather complicate. The reason for that is that both
> +    * uploaders create resources based on the context that they were created
> +    * from, which means that nouveau's uploader will use the nouveau context
> +    * which means that those resources must not be unwrapped. So before each
> +    * resource is unwrapped, the code would need to check that it does not
> +    * correspond to the uploaders' buffers.
> +    *
> +    * However, duplicating the uploaders here sounds worse than it is. The
> +    * default implementation that nouveau uses allocates buffers lazily, and
> +    * since it is never used, no buffers will every be allocated and the only
> +    * memory wasted is that occupied by the nouveau uploader itself.
> +    */
> +   context->base.stream_uploader = u_upload_create_default(&context->base);
> +   if (!context->base.stream_uploader)
> +      goto destroy;
> +
> +   context->base.const_uploader = context->base.stream_uploader;
> +
> +   context->base.destroy = tegra_destroy;
> +
> +   context->base.draw_vbo = tegra_draw_vbo;
> +
> +   context->base.render_condition = tegra_render_condition;
> +
> +   context->base.create_query = tegra_create_query;
> +   context->base.create_batch_query = tegra_create_batch_query;
> +   context->base.destroy_query = tegra_destroy_query;
> +   context->base.begin_query = tegra_begin_query;
> +   context->base.end_query = tegra_end_query;
> +   context->base.get_query_result = tegra_get_query_result;
> +   context->base.get_query_result_resource = tegra_get_query_result_resource;
> +   context->base.set_active_query_state = tegra_set_active_query_state;
> +
> +   context->base.create_blend_state = tegra_create_blend_state;
> +   context->base.bind_blend_state = tegra_bind_blend_state;
> +   context->base.delete_blend_state = tegra_delete_blend_state;
> +
> +   context->base.create_sampler_state = tegra_create_sampler_state;
> +   context->base.bind_sampler_states = tegra_bind_sampler_states;
> +   context->base.delete_sampler_state = tegra_delete_sampler_state;
> +
> +   context->base.create_rasterizer_state = tegra_create_rasterizer_state;
> +   context->base.bind_rasterizer_state = tegra_bind_rasterizer_state;
> +   context->base.delete_rasterizer_state = tegra_delete_rasterizer_state;
> +
> +   context->base.create_depth_stencil_alpha_state = tegra_create_depth_stencil_alpha_state;
> +   context->base.bind_depth_stencil_alpha_state = tegra_bind_depth_stencil_alpha_state;
> +   context->base.delete_depth_stencil_alpha_state = tegra_delete_depth_stencil_alpha_state;
> +
> +   context->base.create_fs_state = tegra_create_fs_state;
> +   context->base.bind_fs_state = tegra_bind_fs_state;
> +   context->base.delete_fs_state = tegra_delete_fs_state;
> +
> +   context->base.create_vs_state = tegra_create_vs_state;
> +   context->base.bind_vs_state = tegra_bind_vs_state;
> +   context->base.delete_vs_state = tegra_delete_vs_state;
> +
> +   context->base.create_gs_state = tegra_create_gs_state;
> +   context->base.bind_gs_state = tegra_bind_gs_state;
> +   context->base.delete_gs_state = tegra_delete_gs_state;
> +
> +   context->base.create_tcs_state = tegra_create_tcs_state;
> +   context->base.bind_tcs_state = tegra_bind_tcs_state;
> +   context->base.delete_tcs_state = tegra_delete_tcs_state;
> +
> +   context->base.create_tes_state = tegra_create_tes_state;
> +   context->base.bind_tes_state = tegra_bind_tes_state;
> +   context->base.delete_tes_state = tegra_delete_tes_state;
> +
> +   context->base.create_vertex_elements_state = tegra_create_vertex_elements_state;
> +   context->base.bind_vertex_elements_state = tegra_bind_vertex_elements_state;
> +   context->base.delete_vertex_elements_state = tegra_delete_vertex_elements_state;
> +
> +   context->base.set_blend_color = tegra_set_blend_color;
> +   context->base.set_stencil_ref = tegra_set_stencil_ref;
> +   context->base.set_sample_mask = tegra_set_sample_mask;
> +   context->base.set_min_samples = tegra_set_min_samples;
> +   context->base.set_clip_state = tegra_set_clip_state;
> +
> +   context->base.set_constant_buffer = tegra_set_constant_buffer;
> +   context->base.set_framebuffer_state = tegra_set_framebuffer_state;
> +   context->base.set_polygon_stipple = tegra_set_polygon_stipple;
> +   context->base.set_scissor_states = tegra_set_scissor_states;
> +   context->base.set_window_rectangles = tegra_set_window_rectangles;
> +   context->base.set_viewport_states = tegra_set_viewport_states;
> +   context->base.set_sampler_views = tegra_set_sampler_views;
> +   context->base.set_tess_state = tegra_set_tess_state;
> +
> +   context->base.set_debug_callback = tegra_set_debug_callback;
> +
> +   context->base.set_shader_buffers = tegra_set_shader_buffers;
> +   context->base.set_shader_images = tegra_set_shader_images;
> +   context->base.set_vertex_buffers = tegra_set_vertex_buffers;
> +
> +   context->base.create_stream_output_target = tegra_create_stream_output_target;
> +   context->base.stream_output_target_destroy = tegra_stream_output_target_destroy;
> +   context->base.set_stream_output_targets = tegra_set_stream_output_targets;
> +
> +   context->base.resource_copy_region = tegra_resource_copy_region;
> +   context->base.blit = tegra_blit;
> +   context->base.clear = tegra_clear;
> +   context->base.clear_render_target = tegra_clear_render_target;
> +   context->base.clear_depth_stencil = tegra_clear_depth_stencil;
> +   context->base.clear_texture = tegra_clear_texture;
> +   context->base.clear_buffer = tegra_clear_buffer;
> +   context->base.flush = tegra_flush;
> +
> +   context->base.create_fence_fd = tegra_create_fence_fd;
> +   context->base.fence_server_sync = tegra_fence_server_sync;
> +
> +   context->base.create_sampler_view = tegra_create_sampler_view;
> +   context->base.sampler_view_destroy = tegra_sampler_view_destroy;
> +
> +   context->base.create_surface = tegra_create_surface;
> +   context->base.surface_destroy = tegra_surface_destroy;
> +
> +   context->base.transfer_map = tegra_transfer_map;
> +   context->base.transfer_flush_region = tegra_transfer_flush_region;
> +   context->base.transfer_unmap = tegra_transfer_unmap;
> +   context->base.buffer_subdata = tegra_buffer_subdata;
> +   context->base.texture_subdata = tegra_texture_subdata;
> +
> +   context->base.texture_barrier = tegra_texture_barrier;
> +   context->base.memory_barrier = tegra_memory_barrier;
> +
> +   context->base.create_video_codec = tegra_create_video_codec;
> +   context->base.create_video_buffer = tegra_create_video_buffer;
> +
> +   context->base.create_compute_state = tegra_create_compute_state;
> +   context->base.bind_compute_state = tegra_bind_compute_state;
> +   context->base.delete_compute_state = tegra_delete_compute_state;
> +   context->base.set_compute_resources = tegra_set_compute_resources;
> +   context->base.set_global_binding = tegra_set_global_binding;
> +   context->base.launch_grid = tegra_launch_grid;
> +   context->base.get_sample_position = tegra_get_sample_position;
> +   context->base.get_timestamp = tegra_get_timestamp;
> +
> +   context->base.flush_resource = tegra_flush_resource;
> +   context->base.invalidate_resource = tegra_invalidate_resource;
> +
> +   context->base.get_device_reset_status = tegra_get_device_reset_status;
> +   context->base.set_device_reset_callback = tegra_set_device_reset_callback;
> +   context->base.dump_debug_state = tegra_dump_debug_state;
> +   context->base.emit_string_marker = tegra_emit_string_marker;
> +
> +   context->base.generate_mipmap = tegra_generate_mipmap;
> +
> +   return &context->base;
> +
> +destroy:
> +   context->gpu->destroy(context->gpu);
> +free:
> +   free(context);
> +   return NULL;
> +}
> diff --git a/src/gallium/drivers/tegra/tegra_context.h b/src/gallium/drivers/tegra/tegra_context.h
> new file mode 100644
> index 000000000000..4869b0913a6f
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/tegra_context.h
> @@ -0,0 +1,81 @@
> +/*
> + * Copyright © 2014-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_CONTEXT_H
> +#define TEGRA_CONTEXT_H
> +
> +#include "pipe/p_context.h"
> +#include "pipe/p_state.h"
> +
> +struct tegra_screen;
> +
> +struct tegra_context {
> +   struct pipe_context base;
> +   struct pipe_context *gpu;
> +};
> +
> +static inline struct tegra_context *
> +to_tegra_context(struct pipe_context *context)
> +{
> +   return (struct tegra_context *)context;
> +}
> +
> +struct pipe_context *
> +tegra_screen_context_create(struct pipe_screen *pscreen, void *priv,
> +                            unsigned int flags);
> +
> +struct tegra_sampler_view {
> +   struct pipe_sampler_view base;
> +   struct pipe_sampler_view *gpu;
> +};
> +
> +static inline struct tegra_sampler_view *
> +to_tegra_sampler_view(struct pipe_sampler_view *view)
> +{
> +   return (struct tegra_sampler_view *)view;
> +}
> +
> +static inline struct pipe_sampler_view *
> +tegra_sampler_view_unwrap(struct pipe_sampler_view *view)
> +{
> +   if (!view)
> +      return NULL;
> +
> +   return to_tegra_sampler_view(view)->gpu;
> +}
> +
> +struct tegra_transfer {
> +   struct pipe_transfer base;
> +   struct pipe_transfer *gpu;
> +
> +   unsigned int count;
> +   void *map;
> +};
> +
> +static inline struct tegra_transfer *
> +to_tegra_transfer(struct pipe_transfer *transfer)
> +{
> +   return (struct tegra_transfer *)transfer;
> +}
> +
> +#endif /* TEGRA_SCREEN_H */
> diff --git a/src/gallium/drivers/tegra/tegra_resource.h b/src/gallium/drivers/tegra/tegra_resource.h
> new file mode 100644
> index 000000000000..67507d64590d
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/tegra_resource.h
> @@ -0,0 +1,76 @@
> +/*
> + * Copyright © 2014-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_RESOURCE_H
> +#define TEGRA_RESOURCE_H
> +
> +#include "pipe/p_state.h"
> +
> +struct winsys_handle;
> +
> +struct tegra_resource {
> +   struct pipe_resource base;
> +   struct pipe_resource *gpu;
> +
> +   uint64_t modifier;
> +   uint32_t stride;
> +   uint32_t handle;
> +   size_t size;
> +};
> +
> +static inline struct tegra_resource *
> +to_tegra_resource(struct pipe_resource *resource)
> +{
> +   return (struct tegra_resource *)resource;
> +}
> +
> +static inline struct pipe_resource *
> +tegra_resource_unwrap(struct pipe_resource *resource)
> +{
> +   if (!resource)
> +      return NULL;
> +
> +   return to_tegra_resource(resource)->gpu;
> +}
> +
> +struct tegra_surface {
> +   struct pipe_surface base;
> +   struct pipe_surface *gpu;
> +};
> +
> +static inline struct tegra_surface *
> +to_tegra_surface(struct pipe_surface *surface)
> +{
> +   return (struct tegra_surface *)surface;
> +}
> +
> +static inline struct pipe_surface *
> +tegra_surface_unwrap(struct pipe_surface *surface)
> +{
> +   if (!surface)
> +      return NULL;
> +
> +   return to_tegra_surface(surface)->gpu;
> +}
> +
> +#endif /* TEGRA_RESOURCE_H */
> diff --git a/src/gallium/drivers/tegra/tegra_screen.c b/src/gallium/drivers/tegra/tegra_screen.c
> new file mode 100644
> index 000000000000..669f22a19449
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/tegra_screen.c
> @@ -0,0 +1,688 @@
> +/*
> + * Copyright © 2014-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 <inttypes.h>
> +#include <stdio.h>
> +
> +#include <sys/stat.h>
> +
> +#include <drm_fourcc.h>
> +#include <tegra_drm.h>
> +#include <xf86drm.h>
> +
> +#include "pipe/p_state.h"
> +#include "util/u_debug.h"
> +#include "util/u_inlines.h"
> +
> +#include "state_tracker/drm_driver.h"
> +
> +#include "nouveau/drm/nouveau_drm_public.h"
> +
> +#include "tegra_context.h"
> +#include "tegra_resource.h"
> +#include "tegra_screen.h"
> +
> +static void tegra_screen_destroy(struct pipe_screen *pscreen)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   screen->gpu->destroy(screen->gpu);
> +   free(pscreen);
> +}
> +
> +static const char *
> +tegra_screen_get_name(struct pipe_screen *pscreen)
> +{
> +   return "tegra";
> +}
> +
> +static const char *
> +tegra_screen_get_vendor(struct pipe_screen *pscreen)
> +{
> +   return "NVIDIA";
> +}
> +
> +static const char *
> +tegra_screen_get_device_vendor(struct pipe_screen *pscreen)
> +{
> +   return "NVIDIA";
> +}
> +
> +static int
> +tegra_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   return screen->gpu->get_param(screen->gpu, param);
> +}
> +
> +static float
> +tegra_screen_get_paramf(struct pipe_screen *pscreen, enum pipe_capf param)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   return screen->gpu->get_paramf(screen->gpu, param);
> +}
> +
> +static int
> +tegra_screen_get_shader_param(struct pipe_screen *pscreen, unsigned shader,
> +                              enum pipe_shader_cap param)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   return screen->gpu->get_shader_param(screen->gpu, shader, param);
> +}
> +
> +static int
> +tegra_screen_get_video_param(struct pipe_screen *pscreen,
> +                             enum pipe_video_profile profile,
> +                             enum pipe_video_entrypoint entrypoint,
> +                             enum pipe_video_cap param)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   return screen->gpu->get_video_param(screen->gpu, profile, entrypoint,
> +                                       param);
> +}
> +
> +static int
> +tegra_screen_get_compute_param(struct pipe_screen *pscreen,
> +                               enum pipe_shader_ir ir_type,
> +                               enum pipe_compute_cap param,
> +                               void *retp)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   return screen->gpu->get_compute_param(screen->gpu, ir_type, param,
> +                                         retp);
> +}
> +
> +static uint64_t
> +tegra_screen_get_timestamp(struct pipe_screen *pscreen)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   return screen->gpu->get_timestamp(screen->gpu);
> +}
> +
> +static boolean
> +tegra_screen_is_format_supported(struct pipe_screen *pscreen,
> +                                 enum pipe_format format,
> +                                 enum pipe_texture_target target,
> +                                 unsigned sample_count,
> +                                 unsigned usage)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   return screen->gpu->is_format_supported(screen->gpu, format, target,
> +                                           sample_count, usage);
> +}
> +
> +static boolean
> +tegra_screen_is_video_format_supported(struct pipe_screen *pscreen,
> +                                       enum pipe_format format,
> +                                       enum pipe_video_profile profile,
> +                                       enum pipe_video_entrypoint entrypoint)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   return screen->gpu->is_video_format_supported(screen->gpu, format, profile,
> +                                                 entrypoint);
> +}
> +
> +static boolean
> +tegra_screen_can_create_resource(struct pipe_screen *pscreen,
> +                                 const struct pipe_resource *template)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   return screen->gpu->can_create_resource(screen->gpu, template);
> +}
> +
> +static int tegra_open_render_node(void)
> +{
> +   drmDevicePtr *devices, device;
> +   int err, render = -ENOENT, fd;
> +   unsigned int num, i;
> +
> +   err = drmGetDevices2(0, NULL, 0);
> +   if (err < 0)
> +      return err;
> +
> +   num = err;
> +
> +   devices = calloc(num, sizeof(*devices));
> +   if (!devices)
> +      return -ENOMEM;
> +
> +   err = drmGetDevices2(0, devices, num);
> +   if (err < 0) {
> +      render = err;
> +      goto free;
> +   }
> +
> +   for (i = 0; i < num; i++) {
> +      device = devices[i];
> +
> +      if ((device->available_nodes & (1 << DRM_NODE_RENDER)) &&
> +          (device->bustype == DRM_BUS_PLATFORM)) {
> +         drmVersionPtr version;
> +
> +         fd = open(device->nodes[DRM_NODE_RENDER], O_RDWR | O_CLOEXEC);
> +         if (fd < 0)
> +            continue;
> +
> +         version = drmGetVersion(fd);
> +         if (!version) {
> +            close(fd);
> +            continue;
> +         }
> +
> +         if (strcmp(version->name, "nouveau") != 0) {
> +            close(fd);
> +            continue;
> +         }
> +
> +         drmFreeVersion(version);
> +         render = fd;
> +         break;
> +      }
> +   }
> +
> +   drmFreeDevices(devices, num);
> +
> +free:
> +   free(devices);
> +   return render;
> +}

Screen probe looks good now and the rest is also sane to me.

Reviewed-by: Dmitry Osipenko <digetx at gmail.com>

> +static int tegra_screen_import_resource(struct tegra_screen *screen,
> +                                        struct tegra_resource *resource,
> +                                        bool has_modifiers)
> +{
> +   unsigned usage = PIPE_HANDLE_USAGE_READ;
> +   struct drm_tegra_gem_set_tiling args;
> +   struct winsys_handle handle;
> +   boolean status;
> +   int fd, err;
> +
> +   memset(&handle, 0, sizeof(handle));
> +   handle.modifier = DRM_FORMAT_MOD_INVALID;
> +   handle.type = DRM_API_HANDLE_TYPE_FD;
> +
> +   status = screen->gpu->resource_get_handle(screen->gpu, NULL, resource->gpu,
> +                                             &handle, usage);
> +   if (!status)
> +      return -EINVAL;
> +
> +   assert(handle.modifier != DRM_FORMAT_MOD_INVALID);
> +
> +   if (handle.modifier == DRM_FORMAT_MOD_INVALID) {
> +      close(handle.handle);
> +      return -EINVAL;
> +   }
> +
> +   resource->modifier = handle.modifier;
> +   resource->stride = handle.stride;
> +   fd = handle.handle;
> +
> +   err = drmPrimeFDToHandle(screen->fd, fd, &resource->handle);
> +   if (err < 0)
> +      err = -errno;
> +
> +   close(fd);
> +
> +   if (!has_modifiers) {
> +      memset(&args, 0, sizeof(args));
> +      args.handle = resource->handle;
> +
> +      switch (handle.modifier) {
> +         case DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED:
> +            args.mode = DRM_TEGRA_GEM_TILING_MODE_TILED;
> +            break;
> +
> +         case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_ONE_GOB:
> +            args.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
> +            args.value = 0;
> +            break;
> +
> +         case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_TWO_GOB:
> +            args.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
> +            args.value = 1;
> +            break;
> +
> +         case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_FOUR_GOB:
> +            args.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
> +            args.value = 2;
> +            break;
> +
> +         case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_EIGHT_GOB:
> +            args.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
> +            args.value = 3;
> +            break;
> +
> +         case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_SIXTEEN_GOB:
> +            args.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
> +            args.value = 4;
> +            break;
> +
> +         case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_THIRTYTWO_GOB:
> +            args.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
> +            args.value = 5;
> +            break;
> +
> +         default:
> +            debug_printf("unsupported modifier %" PRIx64 ", assuming linear\n",
> +                         handle.modifier);
> +            /* fall-through */
> +
> +         case DRM_FORMAT_MOD_LINEAR:
> +            args.mode = DRM_TEGRA_GEM_TILING_MODE_PITCH;
> +            break;
> +      }
> +
> +      err = drmIoctl(screen->fd, DRM_IOCTL_TEGRA_GEM_SET_TILING, &args);
> +      if (err < 0) {
> +         fprintf(stderr, "failed to set tiling parameters: %s\n",
> +                 strerror(errno));
> +         err = -errno;
> +         goto out;
> +      }
> +   }
> +
> +   return 0;
> +
> +out:
> +   return err;
> +}
> +
> +static struct pipe_resource *
> +tegra_screen_resource_create(struct pipe_screen *pscreen,
> +                             const struct pipe_resource *template)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +   struct tegra_resource *resource;
> +   int err;
> +
> +   resource = calloc(1, sizeof(*resource));
> +   if (!resource)
> +      return NULL;
> +
> +   resource->gpu = screen->gpu->resource_create(screen->gpu, template);
> +   if (!resource->gpu)
> +      goto free;
> +
> +   /* import scanout buffers for display */
> +   if (template->bind & PIPE_BIND_SCANOUT) {
> +      err = tegra_screen_import_resource(screen, resource, false);
> +      if (err < 0)
> +         goto destroy;
> +   }
> +
> +   memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
> +   pipe_reference_init(&resource->base.reference, 1);
> +   resource->base.screen = &screen->base;
> +
> +   return &resource->base;
> +
> +destroy:
> +   screen->gpu->resource_destroy(screen->gpu, resource->gpu);
> +free:
> +   free(resource);
> +   return NULL;
> +}
> +
> +/* XXX */
> +static struct pipe_resource *
> +tegra_screen_resource_create_front(struct pipe_screen *pscreen,
> +                                   const struct pipe_resource *template,
> +                                   const void *map_front_private)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +   struct pipe_resource *resource;
> +
> +   resource = screen->gpu->resource_create_front(screen->gpu, template,
> +                                                 map_front_private);
> +   if (resource)
> +      resource->screen = pscreen;
> +
> +   return resource;
> +}
> +
> +static struct pipe_resource *
> +tegra_screen_resource_from_handle(struct pipe_screen *pscreen,
> +                                  const struct pipe_resource *template,
> +                                  struct winsys_handle *handle,
> +                                  unsigned usage)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +   struct tegra_resource *resource;
> +
> +   resource = calloc(1, sizeof(*resource));
> +   if (!resource)
> +      return NULL;
> +
> +   resource->gpu = screen->gpu->resource_from_handle(screen->gpu, template,
> +                                                     handle, usage);
> +   if (!resource->gpu) {
> +      free(resource);
> +      return NULL;
> +   }
> +
> +   memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
> +   pipe_reference_init(&resource->base.reference, 1);
> +   resource->base.screen = &screen->base;
> +
> +   return &resource->base;
> +}
> +
> +/* XXX */
> +static struct pipe_resource *
> +tegra_screen_resource_from_user_memory(struct pipe_screen *pscreen,
> +                                       const struct pipe_resource *template,
> +                                       void *buffer)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +   struct pipe_resource *resource;
> +
> +   resource = screen->gpu->resource_from_user_memory(screen->gpu, template,
> +                                                     buffer);
> +   if (resource)
> +      resource->screen = pscreen;
> +
> +   return resource;
> +}
> +
> +static boolean
> +tegra_screen_resource_get_handle(struct pipe_screen *pscreen,
> +                                 struct pipe_context *pcontext,
> +                                 struct pipe_resource *presource,
> +                                 struct winsys_handle *handle,
> +                                 unsigned usage)
> +{
> +   struct tegra_resource *resource = to_tegra_resource(presource);
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +   boolean ret = TRUE;
> +
> +   /*
> +    * Assume that KMS handles for scanout resources will only ever be used
> +    * to pass buffers into Tegra DRM for display. In all other cases, return
> +    * the Nouveau handle, assuming they will be used for sharing in DRI2/3.
> +    */
> +   if (handle->type == DRM_API_HANDLE_TYPE_KMS &&
> +       presource->bind & PIPE_BIND_SCANOUT) {
> +      handle->modifier = resource->modifier;
> +      handle->handle = resource->handle;
> +      handle->stride = resource->stride;
> +   } else {
> +      ret = screen->gpu->resource_get_handle(screen->gpu,
> +                                             context ? context->gpu : NULL,
> +                                             resource->gpu, handle, usage);
> +   }
> +
> +   return ret;
> +}
> +
> +static void
> +tegra_screen_resource_destroy(struct pipe_screen *pscreen,
> +                              struct pipe_resource *presource)
> +{
> +   struct tegra_resource *resource = to_tegra_resource(presource);
> +
> +   pipe_resource_reference(&resource->gpu, NULL);
> +   free(resource);
> +}
> +
> +static void
> +tegra_screen_flush_frontbuffer(struct pipe_screen *pscreen,
> +                               struct pipe_resource *resource,
> +                               unsigned int level,
> +                               unsigned int layer,
> +                               void *winsys_drawable_handle,
> +                               struct pipe_box *box)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   screen->gpu->flush_frontbuffer(screen->gpu, resource, level, layer,
> +                                  winsys_drawable_handle, box);
> +}
> +
> +static void
> +tegra_screen_fence_reference(struct pipe_screen *pscreen,
> +                             struct pipe_fence_handle **ptr,
> +                             struct pipe_fence_handle *fence)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   screen->gpu->fence_reference(screen->gpu, ptr, fence);
> +}
> +
> +static boolean
> +tegra_screen_fence_finish(struct pipe_screen *pscreen,
> +                          struct pipe_context *pcontext,
> +                          struct pipe_fence_handle *fence,
> +                          uint64_t timeout)
> +{
> +   struct tegra_context *context = to_tegra_context(pcontext);
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   return screen->gpu->fence_finish(screen->gpu,
> +                                    context ? context->gpu : NULL,
> +                                    fence, timeout);
> +}
> +
> +static int
> +tegra_screen_fence_get_fd(struct pipe_screen *pscreen,
> +                          struct pipe_fence_handle *fence)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   return screen->gpu->fence_get_fd(screen->gpu, fence);
> +}
> +
> +static int
> +tegra_screen_get_driver_query_info(struct pipe_screen *pscreen,
> +                                   unsigned int index,
> +                                   struct pipe_driver_query_info *info)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   return screen->gpu->get_driver_query_info(screen->gpu, index, info);
> +}
> +
> +static int
> +tegra_screen_get_driver_query_group_info(struct pipe_screen *pscreen,
> +                                         unsigned int index,
> +                                         struct pipe_driver_query_group_info *info)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   return screen->gpu->get_driver_query_group_info(screen->gpu, index, info);
> +}
> +
> +static void
> +tegra_screen_query_memory_info(struct pipe_screen *pscreen,
> +                               struct pipe_memory_info *info)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   screen->gpu->query_memory_info(screen->gpu, info);
> +}
> +
> +static const void *
> +tegra_screen_get_compiler_options(struct pipe_screen *pscreen,
> +                                  enum pipe_shader_ir ir,
> +                                  unsigned int shader)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +   const void *options = NULL;
> +
> +   if (screen->gpu->get_compiler_options)
> +      options = screen->gpu->get_compiler_options(screen->gpu, ir, shader);
> +
> +   return options;
> +}
> +
> +static struct disk_cache *
> +tegra_screen_get_disk_shader_cache(struct pipe_screen *pscreen)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   return screen->gpu->get_disk_shader_cache(screen->gpu);
> +}
> +
> +static struct pipe_resource *
> +tegra_screen_resource_create_with_modifiers(struct pipe_screen *pscreen,
> +                                            const struct pipe_resource *template,
> +                                            const uint64_t *modifiers,
> +                                            int count)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +   struct tegra_resource *resource;
> +   int err;
> +
> +   resource = calloc(1, sizeof(*resource));
> +   if (!resource)
> +      return NULL;
> +
> +   resource->gpu = screen->gpu->resource_create_with_modifiers(screen->gpu,
> +                                                               template,
> +                                                               modifiers,
> +                                                               count);
> +   if (!resource->gpu)
> +      goto free;
> +
> +   err = tegra_screen_import_resource(screen, resource, true);
> +   if (err < 0)
> +      goto destroy;
> +
> +   memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
> +   pipe_reference_init(&resource->base.reference, 1);
> +   resource->base.screen = &screen->base;
> +
> +   return &resource->base;
> +
> +destroy:
> +   screen->gpu->resource_destroy(screen->gpu, resource->gpu);
> +free:
> +   free(resource);
> +   return NULL;
> +}
> +
> +static void tegra_screen_query_dmabuf_modifiers(struct pipe_screen *pscreen,
> +                                                enum pipe_format format,
> +                                                int max, uint64_t *modifiers,
> +                                                unsigned int *external_only,
> +                                                int *count)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   screen->gpu->query_dmabuf_modifiers(screen->gpu, format, max, modifiers,
> +                                       external_only, count);
> +}
> +
> +static struct pipe_memory_object *
> +tegra_screen_memobj_create_from_handle(struct pipe_screen *pscreen,
> +                                       struct winsys_handle *handle,
> +                                       bool dedicated)
> +{
> +   struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +   return screen->gpu->memobj_create_from_handle(screen->gpu, handle,
> +                                                 dedicated);
> +}
> +
> +struct pipe_screen *
> +tegra_screen_create(int fd)
> +{
> +   struct tegra_screen *screen;
> +
> +   screen = calloc(1, sizeof(*screen));
> +   if (!screen)
> +      return NULL;
> +
> +   screen->fd = fd;
> +
> +   screen->gpu_fd = tegra_open_render_node();
> +   if (screen->gpu_fd < 0) {
> +      if (errno != ENOENT)
> +         fprintf(stderr, "failed to open GPU device: %s\n", strerror(errno));
> +
> +      free(screen);
> +      return NULL;
> +   }
> +
> +   screen->gpu = nouveau_drm_screen_create(screen->gpu_fd);
> +   if (!screen->gpu) {
> +      fprintf(stderr, "failed to create GPU screen\n");
> +      close(screen->gpu_fd);
> +      free(screen);
> +      return NULL;
> +   }
> +
> +   screen->base.destroy = tegra_screen_destroy;
> +   screen->base.get_name = tegra_screen_get_name;
> +   screen->base.get_vendor = tegra_screen_get_vendor;
> +   screen->base.get_device_vendor = tegra_screen_get_device_vendor;
> +   screen->base.get_param = tegra_screen_get_param;
> +   screen->base.get_paramf = tegra_screen_get_paramf;
> +   screen->base.get_shader_param = tegra_screen_get_shader_param;
> +   screen->base.get_video_param = tegra_screen_get_video_param;
> +   screen->base.get_compute_param = tegra_screen_get_compute_param;
> +   screen->base.get_timestamp = tegra_screen_get_timestamp;
> +   screen->base.context_create = tegra_screen_context_create;
> +   screen->base.is_format_supported = tegra_screen_is_format_supported;
> +   screen->base.is_video_format_supported = tegra_screen_is_video_format_supported;
> +
> +   /* allow fallback implementation if GPU driver doesn't implement it */
> +   if (screen->gpu->can_create_resource)
> +      screen->base.can_create_resource = tegra_screen_can_create_resource;
> +
> +   screen->base.resource_create = tegra_screen_resource_create;
> +   screen->base.resource_create_front = tegra_screen_resource_create_front;
> +   screen->base.resource_from_handle = tegra_screen_resource_from_handle;
> +   screen->base.resource_from_user_memory = tegra_screen_resource_from_user_memory;
> +   screen->base.resource_get_handle = tegra_screen_resource_get_handle;
> +   screen->base.resource_destroy = tegra_screen_resource_destroy;
> +
> +   screen->base.flush_frontbuffer = tegra_screen_flush_frontbuffer;
> +   screen->base.fence_reference = tegra_screen_fence_reference;
> +   screen->base.fence_finish = tegra_screen_fence_finish;
> +   screen->base.fence_get_fd = tegra_screen_fence_get_fd;
> +
> +   screen->base.get_driver_query_info = tegra_screen_get_driver_query_info;
> +   screen->base.get_driver_query_group_info = tegra_screen_get_driver_query_group_info;
> +   screen->base.query_memory_info = tegra_screen_query_memory_info;
> +
> +   screen->base.get_compiler_options = tegra_screen_get_compiler_options;
> +   screen->base.get_disk_shader_cache = tegra_screen_get_disk_shader_cache;
> +
> +   screen->base.resource_create_with_modifiers = tegra_screen_resource_create_with_modifiers;
> +   screen->base.query_dmabuf_modifiers = tegra_screen_query_dmabuf_modifiers;
> +   screen->base.memobj_create_from_handle = tegra_screen_memobj_create_from_handle;
> +
> +   return &screen->base;
> +}
> diff --git a/src/gallium/drivers/tegra/tegra_screen.h b/src/gallium/drivers/tegra/tegra_screen.h
> new file mode 100644
> index 000000000000..558d22f2f993
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/tegra_screen.h
> @@ -0,0 +1,45 @@
> +/*
> + * Copyright © 2014-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_SCREEN_H
> +#define TEGRA_SCREEN_H
> +
> +#include "pipe/p_screen.h"
> +
> +struct tegra_screen {
> +   struct pipe_screen base;
> +   int fd;
> +
> +   struct pipe_screen *gpu;
> +   int gpu_fd;
> +};
> +
> +static inline struct tegra_screen *
> +to_tegra_screen(struct pipe_screen *pscreen)
> +{
> +   return (struct tegra_screen *)pscreen;
> +}
> +
> +struct pipe_screen *tegra_screen_create(int fd);
> +
> +#endif /* TEGRA_SCREEN_H */
> diff --git a/src/gallium/meson.build b/src/gallium/meson.build
> index 320fc0176e9a..4a6b73848433 100644
> --- a/src/gallium/meson.build
> +++ b/src/gallium/meson.build
> @@ -119,6 +119,12 @@ if with_gallium_imx
>  else
>    driver_imx = declare_dependency()
>  endif
> +if with_gallium_tegra
> +  subdir('winsys/tegra/drm')
> +  subdir('drivers/tegra')
> +else
> +  driver_tegra = declare_dependency()
> +endif
>  if with_gallium_i915
>    subdir('winsys/i915/drm')
>    subdir('drivers/i915')
> diff --git a/src/gallium/targets/dri/Makefile.am b/src/gallium/targets/dri/Makefile.am
> index 1d05d91a6103..73bb71db0c4c 100644
> --- a/src/gallium/targets/dri/Makefile.am
> +++ b/src/gallium/targets/dri/Makefile.am
> @@ -82,6 +82,8 @@ include $(top_srcdir)/src/gallium/drivers/svga/Automake.inc
>  
>  include $(top_srcdir)/src/gallium/drivers/freedreno/Automake.inc
>  
> +include $(top_srcdir)/src/gallium/drivers/tegra/Automake.inc
> +
>  include $(top_srcdir)/src/gallium/drivers/vc4/Automake.inc
>  include $(top_srcdir)/src/gallium/drivers/vc5/Automake.inc
>  include $(top_srcdir)/src/gallium/drivers/pl111/Automake.inc
> diff --git a/src/gallium/targets/dri/meson.build b/src/gallium/targets/dri/meson.build
> index a4326227f0f8..34402975386d 100644
> --- a/src/gallium/targets/dri/meson.build
> +++ b/src/gallium/targets/dri/meson.build
> @@ -62,7 +62,8 @@ libgallium_dri = shared_library(
>      dep_selinux, dep_expat, dep_libdrm, dep_llvm, dep_thread,
>      driver_swrast, driver_r300, driver_r600, driver_radeonsi, driver_nouveau,
>      driver_pl111, driver_vc4, driver_vc5, driver_freedreno, driver_etnaviv,
> -    driver_imx, driver_i915, driver_svga, driver_virgl, driver_swr,
> +    driver_imx, driver_tegra, driver_i915, driver_svga, driver_virgl,
> +    driver_swr,
>    ],
>  )
>  
> @@ -76,6 +77,7 @@ foreach d : [[with_gallium_pl111, 'pl111_dri.so'],
>               [with_gallium_vc5, 'vc5_dri.so'],
>               [with_gallium_etnaviv, 'etnaviv_dri.so'],
>               [with_gallium_imx, 'imx-drm_dri.so'],
> +             [with_gallium_tegra, 'tegra_dri.so'],
>               [with_gallium_i915, 'i915_dri.so'],
>               [with_gallium_r300, 'r300_dri.so'],
>               [with_gallium_r600, 'r600_dri.so'],
> diff --git a/src/gallium/targets/dri/target.c b/src/gallium/targets/dri/target.c
> index 5ee1761fdba8..e09e77687112 100644
> --- a/src/gallium/targets/dri/target.c
> +++ b/src/gallium/targets/dri/target.c
> @@ -86,3 +86,7 @@ DEFINE_LOADER_DRM_ENTRYPOINT(vc5)
>  DEFINE_LOADER_DRM_ENTRYPOINT(imx_drm)
>  DEFINE_LOADER_DRM_ENTRYPOINT(etnaviv)
>  #endif
> +
> +#if defined(GALLIUM_TEGRA)
> +DEFINE_LOADER_DRM_ENTRYPOINT(tegra);
> +#endif
> diff --git a/src/gallium/targets/vdpau/Makefile.am b/src/gallium/targets/vdpau/Makefile.am
> index 2742c7acd44d..cd05a0244510 100644
> --- a/src/gallium/targets/vdpau/Makefile.am
> +++ b/src/gallium/targets/vdpau/Makefile.am
> @@ -57,6 +57,8 @@ include $(top_srcdir)/src/gallium/drivers/r300/Automake.inc
>  include $(top_srcdir)/src/gallium/drivers/r600/Automake.inc
>  include $(top_srcdir)/src/gallium/drivers/radeonsi/Automake.inc
>  
> +include $(top_srcdir)/src/gallium/drivers/tegra/Automake.inc
> +
>  if HAVE_GALLIUM_STATIC_TARGETS
>  
>  libvdpau_gallium_la_SOURCES += target.c
> diff --git a/src/gallium/winsys/tegra/drm/Makefile.am b/src/gallium/winsys/tegra/drm/Makefile.am
> new file mode 100644
> index 000000000000..8518dedf3fb1
> --- /dev/null
> +++ b/src/gallium/winsys/tegra/drm/Makefile.am
> @@ -0,0 +1,10 @@
> +include Makefile.sources
> +include $(top_srcdir)/src/gallium/Automake.inc
> +
> +AM_CFLAGS = \
> +	-I$(top_srcdir)/src/gallium/drivers \
> +	$(GALLIUM_WINSYS_CFLAGS)
> +
> +noinst_LTLIBRARIES = libtegradrm.la
> +
> +libtegradrm_la_SOURCES = $(C_SOURCES)
> diff --git a/src/gallium/winsys/tegra/drm/Makefile.sources b/src/gallium/winsys/tegra/drm/Makefile.sources
> new file mode 100644
> index 000000000000..fe0d5c42e72d
> --- /dev/null
> +++ b/src/gallium/winsys/tegra/drm/Makefile.sources
> @@ -0,0 +1,2 @@
> +C_SOURCES := \
> +	tegra_drm_winsys.c
> diff --git a/src/gallium/winsys/tegra/drm/meson.build b/src/gallium/winsys/tegra/drm/meson.build
> new file mode 100644
> index 000000000000..46a6ab782a51
> --- /dev/null
> +++ b/src/gallium/winsys/tegra/drm/meson.build
> @@ -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 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.
> +
> +libtegradrm = static_library(
> +  'tegradrm',
> +  'tegra_drm_winsys.c',
> +  include_directories : [
> +    inc_include, inc_src, inc_gallium, inc_gallium_aux, inc_gallium_drivers,
> +    inc_gallium_winsys
> +  ],
> +)
> +
> +driver_tegra = declare_dependency(
> +  compile_args : '-DGALLIUM_TEGRA',
> +  link_with : libtegradrm,
> +)
> diff --git a/src/gallium/winsys/tegra/drm/tegra_drm_public.h b/src/gallium/winsys/tegra/drm/tegra_drm_public.h
> new file mode 100644
> index 000000000000..8105180003f0
> --- /dev/null
> +++ b/src/gallium/winsys/tegra/drm/tegra_drm_public.h
> @@ -0,0 +1,31 @@
> +/*
> + * Copyright © 2014-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_DRM_PUBLIC_H__
> +#define __TEGRA_DRM_PUBLIC_H__
> +
> +struct pipe_screen;
> +
> +struct pipe_screen *tegra_drm_screen_create(int fd);
> +
> +#endif /* __TEGRA_DRM_PUBLIC_H__ */
> diff --git a/src/gallium/winsys/tegra/drm/tegra_drm_winsys.c b/src/gallium/winsys/tegra/drm/tegra_drm_winsys.c
> new file mode 100644
> index 000000000000..e2a8efb0f63f
> --- /dev/null
> +++ b/src/gallium/winsys/tegra/drm/tegra_drm_winsys.c
> @@ -0,0 +1,49 @@
> +/*
> + * Copyright © 2014-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 <fcntl.h>
> +
> +#include "util/u_debug.h"
> +
> +#include "tegra/tegra_screen.h"
> +
> +struct pipe_screen *tegra_drm_screen_create(int fd);
> +
> +struct pipe_screen *tegra_drm_screen_create(int fd)
> +{
> +   struct pipe_screen *screen;
> +
> +   /*
> +    * NOTE: There are reportedly issues with reusing the file descriptor
> +    * as-is related to Xinerama. Duplicate it to side-step any issues.
> +    */
> +   fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
> +   if (fd < 0)
> +      return NULL;
> +
> +   screen = tegra_screen_create(fd);
> +   if (!screen)
> +      close(fd);
> +
> +   return screen;
> +}
> 



More information about the mesa-dev mailing list