[Mesa-dev] [RFC] tegra: Initial support

Emil Velikov emil.l.velikov at gmail.com
Fri Nov 28 08:26:36 PST 2014


Hi Thierry,

Must admit that I really prefer this idea over modifying existing
applications/users [1] because:
 - Most of these setups are tightly coupled (imx+vivante, tegra+nouveau)
and pushing this down to the driver prevents duplication, and hardware
specific details in the users.
 - Removes the need (at least temporary) to have an arbiter and policies
about which devices can and how they should be coupled.

Hope your trip through the build/target helpers did not leave you
tearing your hairs out :)

[1] xserver's libglx and everyone else whole deals with gbm or dri
modules directly.

On 27/11/14 16:39, 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.
> 
> TODO:
> - use Nouveau headers to get at the prototype for creating a screen
I've addressed those inline for you :)

> - implement enough support to seamlessly integrate with X
> - refactor some of the code to be reusable by other drivers
I think this topic will be open for debate for a while. Especially since
tegra is only one driver (for now) that uses this type on
stacking/wrapping thus it's not so easy to predict if others won't need
anything extra.

> 
> Signed-off-by: Thierry Reding <treding at nvidia.com>
> ---
>  configure.ac                                       |  12 +-
>  src/gallium/Makefile.am                            |   5 +
>  .../auxiliary/target-helpers/inline_drm_helper.h   |  30 +
>  src/gallium/drivers/tegra/Automake.inc             |  11 +
>  src/gallium/drivers/tegra/Makefile.am              |  17 +
>  src/gallium/drivers/tegra/Makefile.sources         |   4 +
>  src/gallium/drivers/tegra/tegra_context.c          | 699 +++++++++++++++++++++
>  src/gallium/drivers/tegra/tegra_context.h          |  80 +++
>  src/gallium/drivers/tegra/tegra_resource.c         | 219 +++++++
>  src/gallium/drivers/tegra/tegra_resource.h         |  98 +++
>  src/gallium/drivers/tegra/tegra_screen.c           | 311 +++++++++
>  src/gallium/drivers/tegra/tegra_screen.h           |  45 ++
>  src/gallium/targets/dri/Makefile.am                |   2 +
>  src/gallium/winsys/tegra/drm/Makefile.am           |  11 +
>  src/gallium/winsys/tegra/drm/Makefile.sources      |   2 +
>  src/gallium/winsys/tegra/drm/tegra_drm_public.h    |  31 +
>  src/gallium/winsys/tegra/drm/tegra_drm_winsys.c    |  33 +
>  17 files changed, 1609 insertions(+), 1 deletion(-)
>  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/tegra_context.c
>  create mode 100644 src/gallium/drivers/tegra/tegra_context.h
>  create mode 100644 src/gallium/drivers/tegra/tegra_resource.c
>  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/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 1d9d015481ec..ae50bec95339 100644
> --- a/configure.ac
> +++ b/configure.ac
[...]
> @@ -1937,6 +1938,12 @@ if test -n "$with_gallium_drivers"; then
>              gallium_require_drm "freedreno"
>              gallium_require_drm_loader
>              ;;
> +        xtegra)
> +            HAVE_GALLIUM_TEGRA=yes
> +            PKG_CHECK_MODULES([TEGRA], [libdrm_tegra >= $LIBDRM_TEGRA_REQUIRED])
> +            gallium_require_drm "tegra"
> +            gallium_require_drm_loader
> +            ;;
You might want to have something like the following further down.
Admittedly it's not perfect (it will create a nouveau_dri.so hardlink)
but it'll avoid the manual case for nouveau dependencies.


if test "x$HAVE_GALLIUM_NOUVEAU" != xyes -a
   test "x$HAVE_GALLIUM_TEGRA" = xyes; then
   AC_ERROR([Building with tegra requires that nouveau])
fi


[...]
> diff --git a/src/gallium/drivers/tegra/Makefile.am b/src/gallium/drivers/tegra/Makefile.am
> new file mode 100644
> index 000000000000..eb03df9bb2ed
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/Makefile.am
> @@ -0,0 +1,17 @@
> +AUTOMAKE_OPTIONS = subdir-objects
> +
Don't think you need the AUTOMAKE_OPTIONS here.

> +include Makefile.sources
> +include $(top_srcdir)/src/gallium/Automake.inc
> +
> +AM_CFLAGS = \
> +	$(GALLIUM_DRIVER_CFLAGS) \
> +	$(LIBUDEV_CFLAGS) \
> +	$(TEGRA_CFLAGS)
> +
> +noinst_LTLIBRARIES = libtegra.la
> +
> +libtegra_la_SOURCES = \
> +	$(C_SOURCES)
> +
> +libtegra_la_LIBADD = \
> +	$(LIBUDEV_LIBS)
Here comes the big question:
Can we do something to avoid the link against libudev ? If we _do_ need
to go through libudev, can we please dlopen/dlsym it.

> diff --git a/src/gallium/drivers/tegra/Makefile.sources b/src/gallium/drivers/tegra/Makefile.sources
> new file mode 100644
> index 000000000000..978dd14667f5
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/Makefile.sources
> @@ -0,0 +1,4 @@
> +C_SOURCES := \
> +	tegra_context.c \
> +	tegra_resource.c \
> +	tegra_screen.c
Please add the headers to the above list. It will help automake pick
them up in the distribution tarball.

[...]
> diff --git a/src/gallium/drivers/tegra/tegra_resource.c b/src/gallium/drivers/tegra/tegra_resource.c
> new file mode 100644
> index 000000000000..8c5b7d4e41fc
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/tegra_resource.c
[...]
> +#include <drm/tegra_drm.h>
Please drop the "drm/" part.

> diff --git a/src/gallium/drivers/tegra/tegra_screen.c b/src/gallium/drivers/tegra/tegra_screen.c
> new file mode 100644
> index 000000000000..aa7bf65cb7ec
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/tegra_screen.c
[...]
> +#ifdef HAVE_LIBUDEV
> +#include <libudev.h>
> +#endif
> +
You might as well drop the #ifdef here. Afaics you're using udev API
explicitly below.

> +#include "util/u_debug.h"
> +
> +#include "tegra/tegra_context.h"
> +#include "tegra/tegra_resource.h"
> +#include "tegra/tegra_screen.h"
> +
> +/* TODO: obtain from include file */
> +struct pipe_screen *nouveau_drm_screen_create(int fd);
> +
#include "nouveau/drm/nouveau_drm_public.h" ?

> +static const char *
> +tegra_get_name(struct pipe_screen *pscreen)
> +{
> +	return "tegra";
For nouveau/radeons we add the chipset name so I guess doing similar
thing here wouldn't be a bad idea. Additionally for combined/stacked
drivers we might want to return both the base + gpu's get_name(). It
will provide nice feedback about the actual rendering device + programs
which use device name hacks will continue working :)

> +}
> +
> +static const char *
> +tegra_get_vendor(struct pipe_screen *pscreen)
> +{
> +	return "tegra";
Provide both vendors similar to above ? "NVIDIA Corp + nouveau" :P

[...]
> +static int tegra_open_render_node(int fd)
> +{
[...]
> +	udev_list_entry_foreach(entry, list) {
> +		const char *path = udev_list_entry_get_name(entry);
> +		struct udev_device *device, *bus;
> +
> +		device = udev_device_new_from_syspath(udev, path);
> +		if (!device)
> +			continue;
> +
> +		path = udev_device_get_devnode(device);
> +
> +		parent = udev_device_get_parent(device);
> +		if (!parent) {
> +			udev_device_unref(device);
> +			continue;
> +		}
> +
> +		/* do not match if the render nodes shares the same parent */
> +		if (udev_device_match(parent, display)) {
> +			udev_device_unref(parent);
> +			udev_device_unref(device);
> +			continue;
> +		}
> +
> +		bus = udev_device_get_root(device);
> +		if (!bus) {
> +			udev_device_unref(parent);
> +			udev_device_unref(device);
> +			continue;
> +		}
> +
> +		/* both devices need to be on the same bus, though */
> +		if (udev_device_match(bus, root)) {
> +			fd = open(path, O_RDWR);
open(path) only to ignore it and return open("renderD128") below ? Seems
like something is missing here.

> +			if (fd < 0)
> +				fd = -errno;
> +
> +			break;
> +		}
> +	}
> +
> +	udev_enumerate_unref(enumerate);
> +	udev_unref(udev);
> +
> +	return open("/dev/dri/renderD128", O_RDWR);
> +}
> +

[...]
> diff --git a/src/gallium/winsys/tegra/drm/Makefile.am b/src/gallium/winsys/tegra/drm/Makefile.am
> new file mode 100644
> index 000000000000..8e3685ee20e8
> --- /dev/null
> +++ b/src/gallium/winsys/tegra/drm/Makefile.am
> @@ -0,0 +1,11 @@
> +include Makefile.sources
> +include $(top_srcdir)/src/gallium/Automake.inc
> +
> +AM_CFLAGS = \
> +	-I$(top_srcdir)/src/gallium/drivers \
> +	$(GALLIUM_WINSYS_CFLAGS) \
> +	$(FREEDRENO_CFLAGS)
> +
Do we even need FREEDRENO/TEGRA_CFLAGS here ?

> +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
Please add tegra_drm_public.h to the list.

[...]
> 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..99b0e1649026
> --- /dev/null
> +++ b/src/gallium/winsys/tegra/drm/tegra_drm_winsys.c
> @@ -0,0 +1,33 @@
> +/*
> + * Copyright © 2014 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 "util/u_debug.h"
> +
> +#include "tegra/tegra_screen.h"
> +
> +struct pipe_screen *tegra_drm_screen_create(int fd);
> +
util/u_debug.h is not be needed so the following should suffice.

#include "tegra_drm_public.h"
#include "tegra/tegra_screen.h"


Thanks
Emil



More information about the mesa-dev mailing list