[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