All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] tegra: Initial support
@ 2014-11-27 16:39 Thierry Reding
       [not found] ` <1417106361-705-1-git-send-email-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Thierry Reding @ 2014-11-27 16:39 UTC (permalink / raw)
  To: mesa-dev-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
  Cc: nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW

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
- implement enough support to seamlessly integrate with X
- refactor some of the code to be reusable by other drivers

Signed-off-by: Thierry Reding <treding@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
@@ -33,6 +33,7 @@ LIBDRM_INTEL_REQUIRED=2.4.52
 LIBDRM_NVVIEUX_REQUIRED=2.4.33
 LIBDRM_NOUVEAU_REQUIRED="2.4.33 libdrm >= 2.4.41"
 LIBDRM_FREEDRENO_REQUIRED=2.4.57
+LIBDRM_TEGRA_REQUIRED=2.4.58
 DRI2PROTO_REQUIRED=2.6
 DRI3PROTO_REQUIRED=1.0
 PRESENTPROTO_REQUIRED=1.0
@@ -733,7 +734,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,ilo,nouveau,r300,r600,radeonsi,freedreno,svga,swrast,vc4"
+        "i915,ilo,nouveau,r300,r600,radeonsi,freedreno,tegra,svga,swrast,vc4"
         @<:@default=r300,r600,svga,swrast@:>@])],
     [with_gallium_drivers="$withval"],
     [with_gallium_drivers="$GALLIUM_DRIVERS_DEFAULT"])
@@ -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
+            ;;
         xswrast)
             HAVE_GALLIUM_SOFTPIPE=yes
             if test "x$MESA_LLVM" = x1; then
@@ -2018,6 +2025,7 @@ AM_CONDITIONAL(HAVE_GALLIUM_RADEON_COMMON, test "x$HAVE_GALLIUM_R600" = xyes -o
                                                 "x$HAVE_GALLIUM_RADEONSI" = xyes)
 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_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_VC4, test "x$HAVE_GALLIUM_VC4" = xyes)
@@ -2159,6 +2167,7 @@ AC_CONFIG_FILES([Makefile
 		src/gallium/drivers/rbug/Makefile
 		src/gallium/drivers/softpipe/Makefile
 		src/gallium/drivers/svga/Makefile
+		src/gallium/drivers/tegra/Makefile
 		src/gallium/drivers/trace/Makefile
 		src/gallium/drivers/vc4/Makefile
 		src/gallium/drivers/vc4/kernel/Makefile
@@ -2204,6 +2213,7 @@ AC_CONFIG_FILES([Makefile
 		src/gallium/winsys/sw/wayland/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/gbm/Makefile
 		src/gbm/main/gbm.pc
diff --git a/src/gallium/Makefile.am b/src/gallium/Makefile.am
index 81840b2081b6..1e76681a7329 100644
--- a/src/gallium/Makefile.am
+++ b/src/gallium/Makefile.am
@@ -77,6 +77,11 @@ SUBDIRS += drivers/llvmpipe
 endif
 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/target-helpers/inline_drm_helper.h b/src/gallium/auxiliary/target-helpers/inline_drm_helper.h
index 81649d42582c..5808765a503e 100644
--- a/src/gallium/auxiliary/target-helpers/inline_drm_helper.h
+++ b/src/gallium/auxiliary/target-helpers/inline_drm_helper.h
@@ -58,6 +58,10 @@
 #include "vc4/drm/vc4_drm_public.h"
 #endif
 
+#if GALLIUM_TEGRA
+#include "tegra/drm/tegra_drm_public.h"
+#endif
+
 static char* driver_name = NULL;
 
 /* XXX: We need to teardown the winsys if *screen_create() fails. */
@@ -332,6 +336,27 @@ pipe_vc4_create_screen(int fd)
 }
 #endif
 
+#if defined(GALLIUM_TEGRA)
+#if defined(DRI_TARGET)
+const __DRIextension **__driDriverGetExtensions_tegra(void);
+
+PUBLIC const __DRIextension **__driDriverGetExtensions_tegra(void)
+{
+	globalDriverAPI = &galliumdrm_driver_api;
+	return galliumdrm_driver_extensions;
+}
+#endif
+
+static struct pipe_screen *pipe_tegra_create_screen(int fd)
+{
+	struct pipe_screen *screen;
+
+	screen = tegra_drm_screen_create(fd);
+
+	return screen ? debug_screen_wrap(screen) : NULL;
+}
+#endif
+
 inline struct pipe_screen *
 dd_create_screen(int fd)
 {
@@ -389,6 +414,11 @@ dd_create_screen(int fd)
    else
 #endif
 #endif
+#if defined(GALLIUM_TEGRA)
+   if (strcmp(driver_name, "tegra") == 0)
+      return pipe_tegra_create_screen(fd);
+   else
+#endif
       return NULL;
 }
 
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..eb03df9bb2ed
--- /dev/null
+++ b/src/gallium/drivers/tegra/Makefile.am
@@ -0,0 +1,17 @@
+AUTOMAKE_OPTIONS = subdir-objects
+
+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)
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
diff --git a/src/gallium/drivers/tegra/tegra_context.c b/src/gallium/drivers/tegra/tegra_context.c
new file mode 100644
index 000000000000..a7a7690ec7bb
--- /dev/null
+++ b/src/gallium/drivers/tegra/tegra_context.c
@@ -0,0 +1,699 @@
+/*
+ * 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 <stdlib.h>
+
+#include "util/u_debug.h"
+#include "util/u_inlines.h"
+
+#include "tegra/tegra_context.h"
+#include "tegra/tegra_resource.h"
+#include "tegra/tegra_screen.h"
+
+static void
+tegra_destroy(struct pipe_context *pcontext)
+{
+	struct tegra_context *context = to_tegra_context(pcontext);
+
+	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_info info;
+
+	if (pinfo && pinfo->indirect) {
+		memcpy(&info, pinfo, sizeof(info));
+		info.indirect = tegra_resource_unwrap(info.indirect);
+		pinfo = &info;
+	}
+
+	context->gpu->draw_vbo(context->gpu, pinfo);
+}
+
+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_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_constant_buffer(struct pipe_context *pcontext,
+			  uint shader,
+			  uint index,
+			  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_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_shader_resources(struct pipe_context *pcontext,
+			   unsigned start,
+			   unsigned count,
+			   struct pipe_surface **resources)
+{
+	struct tegra_context *context = to_tegra_context(pcontext);
+
+	context->gpu->set_shader_resources(context->gpu, start, count,
+					   resources);
+}
+
+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++)
+			buf[i].buffer = tegra_resource_unwrap(buf[i].buffer);
+
+		buffers = buf;
+	}
+
+	context->gpu->set_vertex_buffers(context->gpu, start_slot,
+					 num_buffers, buffers);
+}
+
+static void
+tegra_set_index_buffer(struct pipe_context *pcontext,
+		       const struct pipe_index_buffer *buffer)
+{
+	struct tegra_context *context = to_tegra_context(pcontext);
+	struct pipe_index_buffer buf;
+
+	if (buffer) {
+		memcpy(&buf, buffer, sizeof(buf));
+		buf.buffer = tegra_resource_unwrap(buf.buffer);
+		buffer = &buf;
+	}
+
+	context->gpu->set_index_buffer(context->gpu, buffer);
+}
+
+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_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_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 struct pipe_sampler_view *
+tegra_create_sampler_view(struct pipe_context *pcontext,
+			  struct pipe_resource *ptexture,
+			  const struct pipe_sampler_view *template)
+{
+	struct tegra_resource *texture = to_tegra_resource(ptexture);
+	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,
+						      texture->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, ptexture);
+	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 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_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_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_transfer_inline_write(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->transfer_inline_write(context->gpu, resource->gpu,
+					    level, usage, box, data, stride,
+					    layer_stride);
+}
+
+struct pipe_context *
+tegra_context_create(struct pipe_screen *pscreen, void *priv)
+{
+	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);
+	if (!context->gpu) {
+		debug_error("failed to create GPU context\n");
+		free(context);
+		return NULL;
+	}
+
+	context->base.screen = &screen->base;
+	context->base.priv = priv;
+
+	context->base.destroy = tegra_destroy;
+
+	context->base.draw_vbo = tegra_draw_vbo;
+
+	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_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_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_viewport_states = tegra_set_viewport_states;
+	context->base.set_sampler_views = tegra_set_sampler_views;
+
+	context->base.set_shader_resources = tegra_set_shader_resources;
+	context->base.set_vertex_buffers = tegra_set_vertex_buffers;
+	context->base.set_index_buffer = tegra_set_index_buffer;
+
+	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.blit = tegra_blit;
+	context->base.clear = tegra_clear;
+	context->base.flush = tegra_flush;
+
+	context->base.create_sampler_view = tegra_create_sampler_view;
+	context->base.sampler_view_destroy = tegra_sampler_view_destroy;
+
+	context->base.flush_resource = tegra_flush_resource;
+
+	context->base.create_surface = tegra_create_surface;
+	context->base.surface_destroy = tegra_surface_destroy;
+
+	context->base.transfer_map = tegra_transfer_map;
+	context->base.transfer_unmap = tegra_transfer_unmap;
+	context->base.transfer_inline_write = tegra_transfer_inline_write;
+
+	return &context->base;
+}
diff --git a/src/gallium/drivers/tegra/tegra_context.h b/src/gallium/drivers/tegra/tegra_context.h
new file mode 100644
index 000000000000..2a26ec6d9c63
--- /dev/null
+++ b/src/gallium/drivers/tegra/tegra_context.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#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_context_create(struct pipe_screen *pscreen,
+					  void *priv);
+
+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.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
@@ -0,0 +1,219 @@
+/*
+ * 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 <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <drm/tegra_drm.h>
+#include <xf86drm.h>
+
+#include "pipe/p_state.h"
+#include "util/u_debug.h"
+#include "util/u_format.h"
+#include "util/u_inlines.h"
+
+#include "state_tracker/drm_driver.h"
+
+#include "tegra/tegra_context.h"
+#include "tegra/tegra_resource.h"
+#include "tegra/tegra_screen.h"
+
+struct pipe_resource *
+tegra_resource_create(struct pipe_screen *pscreen,
+		      const struct pipe_resource *template)
+{
+	struct tegra_screen *screen = to_tegra_screen(pscreen);
+	struct tegra_resource *resource;
+
+	resource = calloc(1, sizeof(*resource));
+	if (!resource)
+		return NULL;
+
+	/* import scanout buffers for display */
+	if (template->bind & PIPE_BIND_SCANOUT) {
+		struct drm_tegra_gem_set_tiling args;
+		struct winsys_handle handle;
+		boolean status;
+		int fd, err;
+
+		resource->gpu = screen->gpu->resource_create(screen->gpu,
+							     template);
+		if (!resource->gpu)
+			goto free;
+
+		memset(&handle, 0, sizeof(handle));
+		handle.type = DRM_API_HANDLE_TYPE_FD;
+
+		status = screen->gpu->resource_get_handle(screen->gpu,
+							  resource->gpu,
+							  &handle);
+		if (!status)
+			goto destroy;
+
+		resource->stride = handle.stride;
+		fd = handle.handle;
+
+		err = drmPrimeFDToHandle(screen->fd, fd, &resource->handle);
+		if (err < 0) {
+			fprintf(stderr, "drmPrimeFDToHandle() failed: %s\n",
+				strerror(errno));
+			close(fd);
+			goto destroy;
+		}
+
+		close(fd);
+
+		memset(&args, 0, sizeof(args));
+		args.handle = resource->handle;
+		args.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
+		args.value = 4;
+
+		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));
+			goto destroy;
+		}
+	} else {
+		resource->gpu = screen->gpu->resource_create(screen->gpu,
+							     template);
+		if (!resource->gpu)
+			goto free;
+	}
+
+	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;
+}
+
+struct pipe_resource *
+tegra_resource_from_handle(struct pipe_screen *pscreen,
+			   const struct pipe_resource *template,
+			   struct winsys_handle *handle)
+{
+	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);
+	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;
+}
+
+boolean
+tegra_resource_get_handle(struct pipe_screen *pscreen,
+			  struct pipe_resource *presource,
+			  struct winsys_handle *handle)
+{
+	struct tegra_resource *resource = to_tegra_resource(presource);
+	struct tegra_screen *screen = to_tegra_screen(pscreen);
+	boolean ret = TRUE;
+
+	if (presource->bind & PIPE_BIND_SCANOUT) {
+		handle->handle = resource->handle;
+		handle->stride = resource->stride;
+	} else {
+		ret = screen->gpu->resource_get_handle(screen->gpu,
+						       resource->gpu,
+						       handle);
+	}
+
+	return ret;
+}
+
+void
+tegra_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);
+}
+
+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;
+}
+
+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);
+}
diff --git a/src/gallium/drivers/tegra/tegra_resource.h b/src/gallium/drivers/tegra/tegra_resource.h
new file mode 100644
index 000000000000..783fb37ec466
--- /dev/null
+++ b/src/gallium/drivers/tegra/tegra_resource.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#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;
+
+	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 pipe_resource *
+tegra_resource_create(struct pipe_screen *pscreen,
+		      const struct pipe_resource *template);
+struct pipe_resource *
+tegra_resource_from_handle(struct pipe_screen *pscreen,
+			   const struct pipe_resource *template,
+			   struct winsys_handle *handle);
+boolean
+tegra_resource_get_handle(struct pipe_screen *pscreen,
+			  struct pipe_resource *resource,
+			  struct winsys_handle *handle);
+void
+tegra_resource_destroy(struct pipe_screen *pscreen,
+		       struct pipe_resource *resource);
+
+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;
+}
+
+struct pipe_surface *
+tegra_create_surface(struct pipe_context *pcontext,
+		     struct pipe_resource *presource,
+		     const struct pipe_surface *template);
+void
+tegra_surface_destroy(struct pipe_context *pcontext,
+		      struct pipe_surface *psurface);
+
+#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..aa7bf65cb7ec
--- /dev/null
+++ b/src/gallium/drivers/tegra/tegra_screen.c
@@ -0,0 +1,311 @@
+/*
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#ifdef HAVE_LIBUDEV
+#include <libudev.h>
+#endif
+
+#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);
+
+static const char *
+tegra_get_name(struct pipe_screen *pscreen)
+{
+	return "tegra";
+}
+
+static const char *
+tegra_get_vendor(struct pipe_screen *pscreen)
+{
+	return "tegra";
+}
+
+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 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 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 void
+tegra_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_fence_signalled(struct pipe_screen *pscreen,
+		      struct pipe_fence_handle *fence)
+{
+	struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+	return screen->gpu->fence_signalled(screen->gpu, fence);
+}
+
+static boolean
+tegra_fence_finish(struct pipe_screen *pscreen,
+		   struct pipe_fence_handle *fence,
+		   uint64_t timeout)
+{
+	struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+	return screen->gpu->fence_finish(screen->gpu, fence, timeout);
+}
+
+static struct udev_device *udev_device_new_from_fd(struct udev *udev, int fd)
+{
+	struct udev_device *device;
+	struct stat stat;
+	int err;
+
+	err = fstat(fd, &stat);
+	if (err < 0) {
+		fprintf(stderr, "fstat() failed: %s\n", strerror(errno));
+		return NULL;
+	}
+
+	device = udev_device_new_from_devnum(udev, 'c', stat.st_rdev);
+	if (!device) {
+		fprintf(stderr, "udev_device_new_from_devnum() failed\n");
+		return NULL;
+	}
+
+	return device;
+}
+
+static struct udev_device *udev_device_get_root(struct udev_device *device)
+{
+	struct udev_device *parent;
+
+	while (true) {
+		parent = udev_device_get_parent(device);
+		if (!parent)
+			break;
+
+		device = parent;
+	}
+
+	return device;
+}
+
+static bool udev_device_match(struct udev_device *x, struct udev_device *y)
+{
+	const char *p1 = udev_device_get_syspath(x);
+	const char *p2 = udev_device_get_syspath(y);
+
+	return strcmp(p1, p2) == 0;
+}
+
+static int tegra_open_render_node(int fd)
+{
+	struct udev_device *display, *parent, *root;
+	struct udev_list_entry *list, *entry;
+	struct udev_enumerate *enumerate;
+	struct udev *udev;
+
+	udev = udev_new();
+	if (!udev)
+		return -ENOMEM;
+
+	display = udev_device_new_from_fd(udev, fd);
+	if (!display) {
+		udev_unref(udev);
+		return -ENODEV;
+	}
+
+	parent = udev_device_get_parent(display);
+	if (!parent) {
+		udev_device_unref(display);
+		udev_unref(udev);
+		return -ENODEV;
+	}
+
+	display = parent;
+
+	root = udev_device_get_root(display);
+	if (!root) {
+		udev_device_unref(display);
+		udev_unref(udev);
+		return -ENODEV;
+	}
+
+	enumerate = udev_enumerate_new(udev);
+	if (!enumerate) {
+		udev_device_unref(display);
+		udev_unref(udev);
+		return -ENOMEM;
+	}
+
+	udev_enumerate_add_match_subsystem(enumerate, "drm");
+	udev_enumerate_add_match_sysname(enumerate, "render*");
+	udev_enumerate_scan_devices(enumerate);
+
+	list = udev_enumerate_get_list_entry(enumerate);
+
+	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);
+			if (fd < 0)
+				fd = -errno;
+
+			break;
+		}
+	}
+
+	udev_enumerate_unref(enumerate);
+	udev_unref(udev);
+
+	return open("/dev/dri/renderD128", O_RDWR);
+}
+
+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(screen->fd);
+	if (screen->gpu_fd < 0) {
+		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.get_name = tegra_get_name;
+	screen->base.get_vendor = tegra_get_vendor;
+	screen->base.destroy = tegra_screen_destroy;
+	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.context_create = tegra_context_create;
+	screen->base.is_format_supported = tegra_screen_is_format_supported;
+
+	screen->base.resource_create = tegra_resource_create;
+	screen->base.resource_from_handle = tegra_resource_from_handle;
+	screen->base.resource_get_handle = tegra_resource_get_handle;
+	screen->base.resource_destroy = tegra_resource_destroy;
+
+	screen->base.fence_reference = tegra_fence_reference;
+	screen->base.fence_signalled = tegra_fence_signalled;
+	screen->base.fence_finish = tegra_fence_finish;
+
+	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..1fba510c241f
--- /dev/null
+++ b/src/gallium/drivers/tegra/tegra_screen.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#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/targets/dri/Makefile.am b/src/gallium/targets/dri/Makefile.am
index 3c7140d75b5c..0406eaf66537 100644
--- a/src/gallium/targets/dri/Makefile.am
+++ b/src/gallium/targets/dri/Makefile.am
@@ -83,6 +83,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/softpipe/Automake.inc
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)
+
+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/tegra_drm_public.h b/src/gallium/winsys/tegra/drm/tegra_drm_public.h
new file mode 100644
index 000000000000..45e3e006f9be
--- /dev/null
+++ b/src/gallium/winsys/tegra/drm/tegra_drm_public.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#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..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);
+
+struct pipe_screen *tegra_drm_screen_create(int fd)
+{
+	return tegra_screen_create(fd);
+}
-- 
2.1.3

_______________________________________________
Nouveau mailing list
Nouveau@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/nouveau

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [Mesa-dev] [RFC] tegra: Initial support
       [not found] ` <1417106361-705-1-git-send-email-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2014-11-27 16:51   ` Rob Clark
       [not found]     ` <CAF6AEGuf9d_U7NpS2z-4_UTk=9cY3HX+FYpS-JYv_FagZBVG5A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  2014-11-28  5:14   ` Alexandre Courbot
  1 sibling, 1 reply; 11+ messages in thread
From: Rob Clark @ 2014-11-27 16:51 UTC (permalink / raw)
  To: Thierry Reding
  Cc: mesa-dev-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org,
	nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org

On Thu, Nov 27, 2014 at 11:39 AM, Thierry Reding
<thierry.reding@gmail.com> 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
> - implement enough support to seamlessly integrate with X
> - refactor some of the code to be reusable by other drivers

I haven't looked too carefully at the implementation yet, but couldn't
you just put in src/gallium/drivers/shim ?  I guess you'd just want a
small if/else ladder where you create the *actual* screen, to create a
nouveau screen for tegra, an etnaviv screen for imx, armada, etc..?

BR,
-R

>
> Signed-off-by: Thierry Reding <treding@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
> @@ -33,6 +33,7 @@ LIBDRM_INTEL_REQUIRED=2.4.52
>  LIBDRM_NVVIEUX_REQUIRED=2.4.33
>  LIBDRM_NOUVEAU_REQUIRED="2.4.33 libdrm >= 2.4.41"
>  LIBDRM_FREEDRENO_REQUIRED=2.4.57
> +LIBDRM_TEGRA_REQUIRED=2.4.58
>  DRI2PROTO_REQUIRED=2.6
>  DRI3PROTO_REQUIRED=1.0
>  PRESENTPROTO_REQUIRED=1.0
> @@ -733,7 +734,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,ilo,nouveau,r300,r600,radeonsi,freedreno,svga,swrast,vc4"
> +        "i915,ilo,nouveau,r300,r600,radeonsi,freedreno,tegra,svga,swrast,vc4"
>          @<:@default=r300,r600,svga,swrast@:>@])],
>      [with_gallium_drivers="$withval"],
>      [with_gallium_drivers="$GALLIUM_DRIVERS_DEFAULT"])
> @@ -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
> +            ;;
>          xswrast)
>              HAVE_GALLIUM_SOFTPIPE=yes
>              if test "x$MESA_LLVM" = x1; then
> @@ -2018,6 +2025,7 @@ AM_CONDITIONAL(HAVE_GALLIUM_RADEON_COMMON, test "x$HAVE_GALLIUM_R600" = xyes -o
>                                                  "x$HAVE_GALLIUM_RADEONSI" = xyes)
>  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_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_VC4, test "x$HAVE_GALLIUM_VC4" = xyes)
> @@ -2159,6 +2167,7 @@ AC_CONFIG_FILES([Makefile
>                 src/gallium/drivers/rbug/Makefile
>                 src/gallium/drivers/softpipe/Makefile
>                 src/gallium/drivers/svga/Makefile
> +               src/gallium/drivers/tegra/Makefile
>                 src/gallium/drivers/trace/Makefile
>                 src/gallium/drivers/vc4/Makefile
>                 src/gallium/drivers/vc4/kernel/Makefile
> @@ -2204,6 +2213,7 @@ AC_CONFIG_FILES([Makefile
>                 src/gallium/winsys/sw/wayland/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/gbm/Makefile
>                 src/gbm/main/gbm.pc
> diff --git a/src/gallium/Makefile.am b/src/gallium/Makefile.am
> index 81840b2081b6..1e76681a7329 100644
> --- a/src/gallium/Makefile.am
> +++ b/src/gallium/Makefile.am
> @@ -77,6 +77,11 @@ SUBDIRS += drivers/llvmpipe
>  endif
>  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/target-helpers/inline_drm_helper.h b/src/gallium/auxiliary/target-helpers/inline_drm_helper.h
> index 81649d42582c..5808765a503e 100644
> --- a/src/gallium/auxiliary/target-helpers/inline_drm_helper.h
> +++ b/src/gallium/auxiliary/target-helpers/inline_drm_helper.h
> @@ -58,6 +58,10 @@
>  #include "vc4/drm/vc4_drm_public.h"
>  #endif
>
> +#if GALLIUM_TEGRA
> +#include "tegra/drm/tegra_drm_public.h"
> +#endif
> +
>  static char* driver_name = NULL;
>
>  /* XXX: We need to teardown the winsys if *screen_create() fails. */
> @@ -332,6 +336,27 @@ pipe_vc4_create_screen(int fd)
>  }
>  #endif
>
> +#if defined(GALLIUM_TEGRA)
> +#if defined(DRI_TARGET)
> +const __DRIextension **__driDriverGetExtensions_tegra(void);
> +
> +PUBLIC const __DRIextension **__driDriverGetExtensions_tegra(void)
> +{
> +       globalDriverAPI = &galliumdrm_driver_api;
> +       return galliumdrm_driver_extensions;
> +}
> +#endif
> +
> +static struct pipe_screen *pipe_tegra_create_screen(int fd)
> +{
> +       struct pipe_screen *screen;
> +
> +       screen = tegra_drm_screen_create(fd);
> +
> +       return screen ? debug_screen_wrap(screen) : NULL;
> +}
> +#endif
> +
>  inline struct pipe_screen *
>  dd_create_screen(int fd)
>  {
> @@ -389,6 +414,11 @@ dd_create_screen(int fd)
>     else
>  #endif
>  #endif
> +#if defined(GALLIUM_TEGRA)
> +   if (strcmp(driver_name, "tegra") == 0)
> +      return pipe_tegra_create_screen(fd);
> +   else
> +#endif
>        return NULL;
>  }
>
> 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..eb03df9bb2ed
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/Makefile.am
> @@ -0,0 +1,17 @@
> +AUTOMAKE_OPTIONS = subdir-objects
> +
> +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)
> 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
> diff --git a/src/gallium/drivers/tegra/tegra_context.c b/src/gallium/drivers/tegra/tegra_context.c
> new file mode 100644
> index 000000000000..a7a7690ec7bb
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/tegra_context.c
> @@ -0,0 +1,699 @@
> +/*
> + * 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 <stdlib.h>
> +
> +#include "util/u_debug.h"
> +#include "util/u_inlines.h"
> +
> +#include "tegra/tegra_context.h"
> +#include "tegra/tegra_resource.h"
> +#include "tegra/tegra_screen.h"
> +
> +static void
> +tegra_destroy(struct pipe_context *pcontext)
> +{
> +       struct tegra_context *context = to_tegra_context(pcontext);
> +
> +       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_info info;
> +
> +       if (pinfo && pinfo->indirect) {
> +               memcpy(&info, pinfo, sizeof(info));
> +               info.indirect = tegra_resource_unwrap(info.indirect);
> +               pinfo = &info;
> +       }
> +
> +       context->gpu->draw_vbo(context->gpu, pinfo);
> +}
> +
> +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_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_constant_buffer(struct pipe_context *pcontext,
> +                         uint shader,
> +                         uint index,
> +                         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_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_shader_resources(struct pipe_context *pcontext,
> +                          unsigned start,
> +                          unsigned count,
> +                          struct pipe_surface **resources)
> +{
> +       struct tegra_context *context = to_tegra_context(pcontext);
> +
> +       context->gpu->set_shader_resources(context->gpu, start, count,
> +                                          resources);
> +}
> +
> +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++)
> +                       buf[i].buffer = tegra_resource_unwrap(buf[i].buffer);
> +
> +               buffers = buf;
> +       }
> +
> +       context->gpu->set_vertex_buffers(context->gpu, start_slot,
> +                                        num_buffers, buffers);
> +}
> +
> +static void
> +tegra_set_index_buffer(struct pipe_context *pcontext,
> +                      const struct pipe_index_buffer *buffer)
> +{
> +       struct tegra_context *context = to_tegra_context(pcontext);
> +       struct pipe_index_buffer buf;
> +
> +       if (buffer) {
> +               memcpy(&buf, buffer, sizeof(buf));
> +               buf.buffer = tegra_resource_unwrap(buf.buffer);
> +               buffer = &buf;
> +       }
> +
> +       context->gpu->set_index_buffer(context->gpu, buffer);
> +}
> +
> +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_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_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 struct pipe_sampler_view *
> +tegra_create_sampler_view(struct pipe_context *pcontext,
> +                         struct pipe_resource *ptexture,
> +                         const struct pipe_sampler_view *template)
> +{
> +       struct tegra_resource *texture = to_tegra_resource(ptexture);
> +       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,
> +                                                     texture->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, ptexture);
> +       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 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_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_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_transfer_inline_write(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->transfer_inline_write(context->gpu, resource->gpu,
> +                                           level, usage, box, data, stride,
> +                                           layer_stride);
> +}
> +
> +struct pipe_context *
> +tegra_context_create(struct pipe_screen *pscreen, void *priv)
> +{
> +       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);
> +       if (!context->gpu) {
> +               debug_error("failed to create GPU context\n");
> +               free(context);
> +               return NULL;
> +       }
> +
> +       context->base.screen = &screen->base;
> +       context->base.priv = priv;
> +
> +       context->base.destroy = tegra_destroy;
> +
> +       context->base.draw_vbo = tegra_draw_vbo;
> +
> +       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_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_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_viewport_states = tegra_set_viewport_states;
> +       context->base.set_sampler_views = tegra_set_sampler_views;
> +
> +       context->base.set_shader_resources = tegra_set_shader_resources;
> +       context->base.set_vertex_buffers = tegra_set_vertex_buffers;
> +       context->base.set_index_buffer = tegra_set_index_buffer;
> +
> +       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.blit = tegra_blit;
> +       context->base.clear = tegra_clear;
> +       context->base.flush = tegra_flush;
> +
> +       context->base.create_sampler_view = tegra_create_sampler_view;
> +       context->base.sampler_view_destroy = tegra_sampler_view_destroy;
> +
> +       context->base.flush_resource = tegra_flush_resource;
> +
> +       context->base.create_surface = tegra_create_surface;
> +       context->base.surface_destroy = tegra_surface_destroy;
> +
> +       context->base.transfer_map = tegra_transfer_map;
> +       context->base.transfer_unmap = tegra_transfer_unmap;
> +       context->base.transfer_inline_write = tegra_transfer_inline_write;
> +
> +       return &context->base;
> +}
> diff --git a/src/gallium/drivers/tegra/tegra_context.h b/src/gallium/drivers/tegra/tegra_context.h
> new file mode 100644
> index 000000000000..2a26ec6d9c63
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/tegra_context.h
> @@ -0,0 +1,80 @@
> +/*
> + * 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.
> + */
> +
> +#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_context_create(struct pipe_screen *pscreen,
> +                                         void *priv);
> +
> +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.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
> @@ -0,0 +1,219 @@
> +/*
> + * 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 <errno.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +
> +#include <drm/tegra_drm.h>
> +#include <xf86drm.h>
> +
> +#include "pipe/p_state.h"
> +#include "util/u_debug.h"
> +#include "util/u_format.h"
> +#include "util/u_inlines.h"
> +
> +#include "state_tracker/drm_driver.h"
> +
> +#include "tegra/tegra_context.h"
> +#include "tegra/tegra_resource.h"
> +#include "tegra/tegra_screen.h"
> +
> +struct pipe_resource *
> +tegra_resource_create(struct pipe_screen *pscreen,
> +                     const struct pipe_resource *template)
> +{
> +       struct tegra_screen *screen = to_tegra_screen(pscreen);
> +       struct tegra_resource *resource;
> +
> +       resource = calloc(1, sizeof(*resource));
> +       if (!resource)
> +               return NULL;
> +
> +       /* import scanout buffers for display */
> +       if (template->bind & PIPE_BIND_SCANOUT) {
> +               struct drm_tegra_gem_set_tiling args;
> +               struct winsys_handle handle;
> +               boolean status;
> +               int fd, err;
> +
> +               resource->gpu = screen->gpu->resource_create(screen->gpu,
> +                                                            template);
> +               if (!resource->gpu)
> +                       goto free;
> +
> +               memset(&handle, 0, sizeof(handle));
> +               handle.type = DRM_API_HANDLE_TYPE_FD;
> +
> +               status = screen->gpu->resource_get_handle(screen->gpu,
> +                                                         resource->gpu,
> +                                                         &handle);
> +               if (!status)
> +                       goto destroy;
> +
> +               resource->stride = handle.stride;
> +               fd = handle.handle;
> +
> +               err = drmPrimeFDToHandle(screen->fd, fd, &resource->handle);
> +               if (err < 0) {
> +                       fprintf(stderr, "drmPrimeFDToHandle() failed: %s\n",
> +                               strerror(errno));
> +                       close(fd);
> +                       goto destroy;
> +               }
> +
> +               close(fd);
> +
> +               memset(&args, 0, sizeof(args));
> +               args.handle = resource->handle;
> +               args.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
> +               args.value = 4;
> +
> +               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));
> +                       goto destroy;
> +               }
> +       } else {
> +               resource->gpu = screen->gpu->resource_create(screen->gpu,
> +                                                            template);
> +               if (!resource->gpu)
> +                       goto free;
> +       }
> +
> +       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;
> +}
> +
> +struct pipe_resource *
> +tegra_resource_from_handle(struct pipe_screen *pscreen,
> +                          const struct pipe_resource *template,
> +                          struct winsys_handle *handle)
> +{
> +       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);
> +       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;
> +}
> +
> +boolean
> +tegra_resource_get_handle(struct pipe_screen *pscreen,
> +                         struct pipe_resource *presource,
> +                         struct winsys_handle *handle)
> +{
> +       struct tegra_resource *resource = to_tegra_resource(presource);
> +       struct tegra_screen *screen = to_tegra_screen(pscreen);
> +       boolean ret = TRUE;
> +
> +       if (presource->bind & PIPE_BIND_SCANOUT) {
> +               handle->handle = resource->handle;
> +               handle->stride = resource->stride;
> +       } else {
> +               ret = screen->gpu->resource_get_handle(screen->gpu,
> +                                                      resource->gpu,
> +                                                      handle);
> +       }
> +
> +       return ret;
> +}
> +
> +void
> +tegra_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);
> +}
> +
> +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;
> +}
> +
> +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);
> +}
> diff --git a/src/gallium/drivers/tegra/tegra_resource.h b/src/gallium/drivers/tegra/tegra_resource.h
> new file mode 100644
> index 000000000000..783fb37ec466
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/tegra_resource.h
> @@ -0,0 +1,98 @@
> +/*
> + * 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.
> + */
> +
> +#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;
> +
> +       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 pipe_resource *
> +tegra_resource_create(struct pipe_screen *pscreen,
> +                     const struct pipe_resource *template);
> +struct pipe_resource *
> +tegra_resource_from_handle(struct pipe_screen *pscreen,
> +                          const struct pipe_resource *template,
> +                          struct winsys_handle *handle);
> +boolean
> +tegra_resource_get_handle(struct pipe_screen *pscreen,
> +                         struct pipe_resource *resource,
> +                         struct winsys_handle *handle);
> +void
> +tegra_resource_destroy(struct pipe_screen *pscreen,
> +                      struct pipe_resource *resource);
> +
> +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;
> +}
> +
> +struct pipe_surface *
> +tegra_create_surface(struct pipe_context *pcontext,
> +                    struct pipe_resource *presource,
> +                    const struct pipe_surface *template);
> +void
> +tegra_surface_destroy(struct pipe_context *pcontext,
> +                     struct pipe_surface *psurface);
> +
> +#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..aa7bf65cb7ec
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/tegra_screen.c
> @@ -0,0 +1,311 @@
> +/*
> + * 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 <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +
> +#ifdef HAVE_LIBUDEV
> +#include <libudev.h>
> +#endif
> +
> +#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);
> +
> +static const char *
> +tegra_get_name(struct pipe_screen *pscreen)
> +{
> +       return "tegra";
> +}
> +
> +static const char *
> +tegra_get_vendor(struct pipe_screen *pscreen)
> +{
> +       return "tegra";
> +}
> +
> +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 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 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 void
> +tegra_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_fence_signalled(struct pipe_screen *pscreen,
> +                     struct pipe_fence_handle *fence)
> +{
> +       struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +       return screen->gpu->fence_signalled(screen->gpu, fence);
> +}
> +
> +static boolean
> +tegra_fence_finish(struct pipe_screen *pscreen,
> +                  struct pipe_fence_handle *fence,
> +                  uint64_t timeout)
> +{
> +       struct tegra_screen *screen = to_tegra_screen(pscreen);
> +
> +       return screen->gpu->fence_finish(screen->gpu, fence, timeout);
> +}
> +
> +static struct udev_device *udev_device_new_from_fd(struct udev *udev, int fd)
> +{
> +       struct udev_device *device;
> +       struct stat stat;
> +       int err;
> +
> +       err = fstat(fd, &stat);
> +       if (err < 0) {
> +               fprintf(stderr, "fstat() failed: %s\n", strerror(errno));
> +               return NULL;
> +       }
> +
> +       device = udev_device_new_from_devnum(udev, 'c', stat.st_rdev);
> +       if (!device) {
> +               fprintf(stderr, "udev_device_new_from_devnum() failed\n");
> +               return NULL;
> +       }
> +
> +       return device;
> +}
> +
> +static struct udev_device *udev_device_get_root(struct udev_device *device)
> +{
> +       struct udev_device *parent;
> +
> +       while (true) {
> +               parent = udev_device_get_parent(device);
> +               if (!parent)
> +                       break;
> +
> +               device = parent;
> +       }
> +
> +       return device;
> +}
> +
> +static bool udev_device_match(struct udev_device *x, struct udev_device *y)
> +{
> +       const char *p1 = udev_device_get_syspath(x);
> +       const char *p2 = udev_device_get_syspath(y);
> +
> +       return strcmp(p1, p2) == 0;
> +}
> +
> +static int tegra_open_render_node(int fd)
> +{
> +       struct udev_device *display, *parent, *root;
> +       struct udev_list_entry *list, *entry;
> +       struct udev_enumerate *enumerate;
> +       struct udev *udev;
> +
> +       udev = udev_new();
> +       if (!udev)
> +               return -ENOMEM;
> +
> +       display = udev_device_new_from_fd(udev, fd);
> +       if (!display) {
> +               udev_unref(udev);
> +               return -ENODEV;
> +       }
> +
> +       parent = udev_device_get_parent(display);
> +       if (!parent) {
> +               udev_device_unref(display);
> +               udev_unref(udev);
> +               return -ENODEV;
> +       }
> +
> +       display = parent;
> +
> +       root = udev_device_get_root(display);
> +       if (!root) {
> +               udev_device_unref(display);
> +               udev_unref(udev);
> +               return -ENODEV;
> +       }
> +
> +       enumerate = udev_enumerate_new(udev);
> +       if (!enumerate) {
> +               udev_device_unref(display);
> +               udev_unref(udev);
> +               return -ENOMEM;
> +       }
> +
> +       udev_enumerate_add_match_subsystem(enumerate, "drm");
> +       udev_enumerate_add_match_sysname(enumerate, "render*");
> +       udev_enumerate_scan_devices(enumerate);
> +
> +       list = udev_enumerate_get_list_entry(enumerate);
> +
> +       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);
> +                       if (fd < 0)
> +                               fd = -errno;
> +
> +                       break;
> +               }
> +       }
> +
> +       udev_enumerate_unref(enumerate);
> +       udev_unref(udev);
> +
> +       return open("/dev/dri/renderD128", O_RDWR);
> +}
> +
> +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(screen->fd);
> +       if (screen->gpu_fd < 0) {
> +               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.get_name = tegra_get_name;
> +       screen->base.get_vendor = tegra_get_vendor;
> +       screen->base.destroy = tegra_screen_destroy;
> +       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.context_create = tegra_context_create;
> +       screen->base.is_format_supported = tegra_screen_is_format_supported;
> +
> +       screen->base.resource_create = tegra_resource_create;
> +       screen->base.resource_from_handle = tegra_resource_from_handle;
> +       screen->base.resource_get_handle = tegra_resource_get_handle;
> +       screen->base.resource_destroy = tegra_resource_destroy;
> +
> +       screen->base.fence_reference = tegra_fence_reference;
> +       screen->base.fence_signalled = tegra_fence_signalled;
> +       screen->base.fence_finish = tegra_fence_finish;
> +
> +       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..1fba510c241f
> --- /dev/null
> +++ b/src/gallium/drivers/tegra/tegra_screen.h
> @@ -0,0 +1,45 @@
> +/*
> + * 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.
> + */
> +
> +#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/targets/dri/Makefile.am b/src/gallium/targets/dri/Makefile.am
> index 3c7140d75b5c..0406eaf66537 100644
> --- a/src/gallium/targets/dri/Makefile.am
> +++ b/src/gallium/targets/dri/Makefile.am
> @@ -83,6 +83,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/softpipe/Automake.inc
> 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)
> +
> +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/tegra_drm_public.h b/src/gallium/winsys/tegra/drm/tegra_drm_public.h
> new file mode 100644
> index 000000000000..45e3e006f9be
> --- /dev/null
> +++ b/src/gallium/winsys/tegra/drm/tegra_drm_public.h
> @@ -0,0 +1,31 @@
> +/*
> + * 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.
> + */
> +
> +#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..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);
> +
> +struct pipe_screen *tegra_drm_screen_create(int fd)
> +{
> +       return tegra_screen_create(fd);
> +}
> --
> 2.1.3
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
_______________________________________________
Nouveau mailing list
Nouveau@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/nouveau

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] tegra: Initial support
       [not found] ` <1417106361-705-1-git-send-email-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2014-11-27 16:51   ` [Mesa-dev] " Rob Clark
@ 2014-11-28  5:14   ` Alexandre Courbot
       [not found]     ` <547804B0.4020603-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  1 sibling, 1 reply; 11+ messages in thread
From: Alexandre Courbot @ 2014-11-28  5:14 UTC (permalink / raw)
  To: Thierry Reding, mesa-dev-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
  Cc: nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW

On 11/28/2014 01:39 AM, 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.

Tested with kmscube and Weston and I can confirm this works. However, 
EGL clients inside Weston have their window filled with garbage (they 
seem to run fine otherwise). Do you also experience this?
_______________________________________________
Nouveau mailing list
Nouveau@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/nouveau

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] tegra: Initial support
  2014-11-27 16:39 [RFC] tegra: Initial support Thierry Reding
       [not found] ` <1417106361-705-1-git-send-email-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2014-11-28  5:32 ` Ilia Mirkin
  2014-11-28  9:17   ` Thierry Reding
  2014-11-28 16:26 ` Emil Velikov
  2 siblings, 1 reply; 11+ messages in thread
From: Ilia Mirkin @ 2014-11-28  5:32 UTC (permalink / raw)
  To: Thierry Reding
  Cc: mesa-dev@lists.freedesktop.org, nouveau@lists.freedesktop.org

On Thu, Nov 27, 2014 at 11:39 AM, Thierry Reding
<thierry.reding@gmail.com> 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
> - implement enough support to seamlessly integrate with X
> - refactor some of the code to be reusable by other drivers
>
> Signed-off-by: Thierry Reding <treding@nvidia.com>

With the exception of resource creation, I don't see anything
tegra-specific in here. Is there perhaps something that could be done
to abstract that a little more, e.g. a wrapper driver, or...
something? This is a situation that several mobile GPU's are in,
AFAIK, and it may be nice to make it work for them as well.

Also, can you explain why it's advantageous for the setup to appear as
though it is a single device? i.e. what's wrong with just using
nouveau as a render node or whatever? [The answer may be simple, but
I'm very unfamiliar with a lot of that stuff, and perhaps others are
in a similar predicament.]

> 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)

oops?

> +
> +noinst_LTLIBRARIES = libtegradrm.la
> +
> +libtegradrm_la_SOURCES = $(C_SOURCES)
_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Mesa-dev] [RFC] tegra: Initial support
       [not found]     ` <CAF6AEGuf9d_U7NpS2z-4_UTk=9cY3HX+FYpS-JYv_FagZBVG5A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2014-11-28  8:46       ` Thierry Reding
  0 siblings, 0 replies; 11+ messages in thread
From: Thierry Reding @ 2014-11-28  8:46 UTC (permalink / raw)
  To: Rob Clark
  Cc: mesa-dev-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org,
	nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org


[-- Attachment #1.1: Type: text/plain, Size: 2581 bytes --]

On Thu, Nov 27, 2014 at 11:51:08AM -0500, Rob Clark wrote:
> On Thu, Nov 27, 2014 at 11:39 AM, Thierry Reding
> <thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 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
> > - implement enough support to seamlessly integrate with X
> > - refactor some of the code to be reusable by other drivers
> 
> I haven't looked too carefully at the implementation yet, but couldn't
> you just put in src/gallium/drivers/shim ?  I guess you'd just want a
> small if/else ladder where you create the *actual* screen, to create a
> nouveau screen for tegra, an etnaviv screen for imx, armada, etc..?

That's not how Mesa's loader works. Typically only a file descriptor is
passed in and helpers determine a name for the driver to load, then the
DRI code will load <name>_dri.so. I don't see how this could be made to
work with a single Gallium driver.

There's also the fact that these drivers need to become very HW-specific
at some point, so sharing a single driver will likely just cause an
explosion of conditionals to special-case for each and everyone of the
drivers.

Lastly, Tegra is also somewhat special in this regard because earlier
generations did have a GPU that's controlled via the same DRM device as
the display part. If ever a Mesa driver shows up for that older GPU we
are going to have a conflict between the shim and the Tegra driver that
isn't going to be easy to untangle. With a separate driver we can use
SoC-specific knowledge to determine whether the driver is running on an
old SoC generation or Tegra K1 and later.

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 819 bytes --]

[-- Attachment #2: Type: text/plain, Size: 153 bytes --]

_______________________________________________
Nouveau mailing list
Nouveau@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/nouveau

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] tegra: Initial support
       [not found]     ` <547804B0.4020603-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2014-11-28  8:48       ` Thierry Reding
  2014-11-28  8:52         ` Alexandre Courbot
  0 siblings, 1 reply; 11+ messages in thread
From: Thierry Reding @ 2014-11-28  8:48 UTC (permalink / raw)
  To: Alexandre Courbot
  Cc: mesa-dev-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW


[-- Attachment #1.1: Type: text/plain, Size: 1483 bytes --]

On Fri, Nov 28, 2014 at 02:14:24PM +0900, Alexandre Courbot wrote:
> On 11/28/2014 01:39 AM, 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.
> 
> Tested with kmscube and Weston and I can confirm this works. However, EGL
> clients inside Weston have their window filled with garbage (they seem to
> run fine otherwise). Do you also experience this?

To be honest, that wasn't part of my set of test cases. I had assumed
that since Weston could composite buffers into a final scan out buffer
everything else would just work as well. Do you have any particular
demos that aren't working?

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 819 bytes --]

[-- Attachment #2: Type: text/plain, Size: 153 bytes --]

_______________________________________________
Nouveau mailing list
Nouveau@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/nouveau

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] tegra: Initial support
  2014-11-28  8:48       ` Thierry Reding
@ 2014-11-28  8:52         ` Alexandre Courbot
  2014-11-28  9:19           ` [Nouveau] " Thierry Reding
  0 siblings, 1 reply; 11+ messages in thread
From: Alexandre Courbot @ 2014-11-28  8:52 UTC (permalink / raw)
  To: Thierry Reding
  Cc: mesa-dev-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org

On Fri, Nov 28, 2014 at 5:48 PM, Thierry Reding
<thierry.reding@gmail.com> wrote:
> On Fri, Nov 28, 2014 at 02:14:24PM +0900, Alexandre Courbot wrote:
>> On 11/28/2014 01:39 AM, 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.
>>
>> Tested with kmscube and Weston and I can confirm this works. However, EGL
>> clients inside Weston have their window filled with garbage (they seem to
>> run fine otherwise). Do you also experience this?
>
> To be honest, that wasn't part of my set of test cases. I had assumed
> that since Weston could composite buffers into a final scan out buffer
> everything else would just work as well. Do you have any particular
> demos that aren't working?

Anything using EGL under Wayland - the simplest case would be
weston-simple-egl. glmark2 also displays a broken window, but then
crashes shortly after. With weston-simpe-egl I get the framerate
feedback and can see the GPU performance counters moving as expected,
indicating that the app is rendering correctly but that Weston gets
the wrong buffer to display.
_______________________________________________
Nouveau mailing list
Nouveau@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/nouveau

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] tegra: Initial support
  2014-11-28  5:32 ` Ilia Mirkin
@ 2014-11-28  9:17   ` Thierry Reding
  2014-11-28 15:54     ` [Mesa-dev] " Daniel Stone
  0 siblings, 1 reply; 11+ messages in thread
From: Thierry Reding @ 2014-11-28  9:17 UTC (permalink / raw)
  To: Ilia Mirkin; +Cc: mesa-dev@lists.freedesktop.org, nouveau@lists.freedesktop.org


[-- Attachment #1.1: Type: text/plain, Size: 5242 bytes --]

On Fri, Nov 28, 2014 at 12:32:43AM -0500, Ilia Mirkin wrote:
> On Thu, Nov 27, 2014 at 11:39 AM, Thierry Reding
> <thierry.reding@gmail.com> 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
> > - implement enough support to seamlessly integrate with X
> > - refactor some of the code to be reusable by other drivers
> >
> > Signed-off-by: Thierry Reding <treding@nvidia.com>
> 
> With the exception of resource creation, I don't see anything
> tegra-specific in here. Is there perhaps something that could be done
> to abstract that a little more, e.g. a wrapper driver, or...
> something? This is a situation that several mobile GPU's are in,
> AFAIK, and it may be nice to make it work for them as well.

I think it might be possible to factor out some things to reduce some
amount of boilerplate, but I don't expect it to be very much. There is
likely going to be hardware-specific details in each of these drivers
that will be hard to abstract out.

Given that this is the first driver of this sort I have no idea what
other drivers will require, so it doesn't seem wise for me to make this
any more generic. It's very likely to turn out completely wrong. Hence
why I opted for just a straight implementation that would work on Tegra.

That said, if it turns out that drivers for other SoCs need to duplicate
a lot of the code in this driver I'm sure we can find ways to alleviate
some of that. But like I already said in my reply to Rob, I don't think
a common wrapper driver is going to cut it. Perhaps something like the
u_transfer abstraction could work, but there is potential for that to
turn into a midlayer of sorts and actually make things more difficult.

The bottom-line is that the vast majority of the code is really just a
skeleton driver, so it's not unlike any of the existing drivers.
Requiring this particular driver to be common for all "mobile" SoCs is a
little like saying that Radeon and Nouveau should share code because
they both use PCI as the transport.

> Also, can you explain why it's advantageous for the setup to appear as
> though it is a single device? i.e. what's wrong with just using
> nouveau as a render node or whatever? [The answer may be simple, but
> I'm very unfamiliar with a lot of that stuff, and perhaps others are
> in a similar predicament.]

There are two reasons. For one, pretty much every software out there
that runs on the "bare metal" (i.e. GBM) uses the same initialization
sequence and it doesn't involve opening two DRM devices. So in order to
support Tegra and other SoCs with a similar architecture, each of these
applications would need to be patched. Now typically a lot of the
applications would run under X or Wayland, so the number of applications
that need patching is somewhat reduced. However, it would still mean
that every Wayland compositor would need to be patched in order to
support this, and each of them would use a mostly identical copy of that
code.

The second reason derives from the first. One of the issues I ran into
when I prototyped the dual-fd code for kmscube was that the code to
share these buffers between GPU and display is in fact highly hardware-
specific. At least on Tegra it is, because we can take advantage of the
tight coupling between GPU and display by directly scanning out block-
linear buffers. For that to work we need to make assumptions and that
just doesn't work generically.

So we need to solve two problems: reduce code duplication and hide the
hardware specific details. The natural solution for these two problems
is to move the code into a library. But we already have that library:
Mesa/GBM.

> > 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)
> 
> oops?

Yes, I wanted to make it obvious from where I copied. =) Good catch,
thanks.

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 819 bytes --]

[-- Attachment #2: Type: text/plain, Size: 156 bytes --]

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Nouveau] [RFC] tegra: Initial support
  2014-11-28  8:52         ` Alexandre Courbot
@ 2014-11-28  9:19           ` Thierry Reding
  0 siblings, 0 replies; 11+ messages in thread
From: Thierry Reding @ 2014-11-28  9:19 UTC (permalink / raw)
  To: Alexandre Courbot; +Cc: mesa-dev, nouveau@lists.freedesktop.org


[-- Attachment #1.1: Type: text/plain, Size: 2180 bytes --]

On Fri, Nov 28, 2014 at 05:52:26PM +0900, Alexandre Courbot wrote:
> On Fri, Nov 28, 2014 at 5:48 PM, Thierry Reding
> <thierry.reding@gmail.com> wrote:
> > On Fri, Nov 28, 2014 at 02:14:24PM +0900, Alexandre Courbot wrote:
> >> On 11/28/2014 01:39 AM, 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.
> >>
> >> Tested with kmscube and Weston and I can confirm this works. However, EGL
> >> clients inside Weston have their window filled with garbage (they seem to
> >> run fine otherwise). Do you also experience this?
> >
> > To be honest, that wasn't part of my set of test cases. I had assumed
> > that since Weston could composite buffers into a final scan out buffer
> > everything else would just work as well. Do you have any particular
> > demos that aren't working?
> 
> Anything using EGL under Wayland - the simplest case would be
> weston-simple-egl. glmark2 also displays a broken window, but then
> crashes shortly after. With weston-simpe-egl I get the framerate
> feedback and can see the GPU performance counters moving as expected,
> indicating that the app is rendering correctly but that Weston gets
> the wrong buffer to display.

Okay, I'll need to look into this more closely. Thanks for reporting.

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 819 bytes --]

[-- Attachment #2: Type: text/plain, Size: 156 bytes --]

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Mesa-dev] [RFC] tegra: Initial support
  2014-11-28  9:17   ` Thierry Reding
@ 2014-11-28 15:54     ` Daniel Stone
  0 siblings, 0 replies; 11+ messages in thread
From: Daniel Stone @ 2014-11-28 15:54 UTC (permalink / raw)
  To: Thierry Reding
  Cc: mesa-dev-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org,
	nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org


[-- Attachment #1.1: Type: text/plain, Size: 2032 bytes --]

Hi,

On 28 November 2014 at 09:17, Thierry Reding <thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
wrote:

> On Fri, Nov 28, 2014 at 12:32:43AM -0500, Ilia Mirkin wrote:> Also, can
> you explain why it's advantageous for the setup to appear as
> > though it is a single device? i.e. what's wrong with just using
> > nouveau as a render node or whatever? [The answer may be simple, but
> > I'm very unfamiliar with a lot of that stuff, and perhaps others are
> > in a similar predicament.]
>
> There are two reasons. For one, pretty much every software out there
> that runs on the "bare metal" (i.e. GBM) uses the same initialization
> sequence and it doesn't involve opening two DRM devices. So in order to
> support Tegra and other SoCs with a similar architecture, each of these
> applications would need to be patched. Now typically a lot of the
> applications would run under X or Wayland, so the number of applications
> that need patching is somewhat reduced. However, it would still mean
> that every Wayland compositor would need to be patched in order to
> support this, and each of them would use a mostly identical copy of that
> code.
>

More specifically, the gbm/EGL API works thusly:
  drm_fd = drmOpen("display_controller");
  gbm_dev = gbm_create_device(drm_fd);
  egl_dpy = eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_EXT, gbm_dev, NULL);

So in the last stage, you have to magically infer a relationship between
your display controller's device and your GPU's. On most mobile devices you
can just work this out (there's only one GPU), but it also breaks in the
multi-GPU case.

The best idea I've come up with to fix this in the long term, is to use
EGL_EXT_device_base to enumerate the GPUs and then feed the device ID you
get from that as a new attrib to eglGetPlatformDisplayEXT. It's either
that, or a new gbm_device_create_multi(display_controller_fd, gpu_fd)
entrypoint.

Of course, the first complication in all of this is that Weston doesn't
support platform_base at all anyway ...

Cheers,
Daniel

[-- Attachment #1.2: Type: text/html, Size: 2719 bytes --]

[-- Attachment #2: Type: text/plain, Size: 153 bytes --]

_______________________________________________
Nouveau mailing list
Nouveau@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/nouveau

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC] tegra: Initial support
  2014-11-27 16:39 [RFC] tegra: Initial support Thierry Reding
       [not found] ` <1417106361-705-1-git-send-email-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2014-11-28  5:32 ` Ilia Mirkin
@ 2014-11-28 16:26 ` Emil Velikov
  2 siblings, 0 replies; 11+ messages in thread
From: Emil Velikov @ 2014-11-28 16:26 UTC (permalink / raw)
  To: Thierry Reding, mesa-dev; +Cc: nouveau, emil.l.velikov

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@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

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2014-11-28 16:26 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-27 16:39 [RFC] tegra: Initial support Thierry Reding
     [not found] ` <1417106361-705-1-git-send-email-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2014-11-27 16:51   ` [Mesa-dev] " Rob Clark
     [not found]     ` <CAF6AEGuf9d_U7NpS2z-4_UTk=9cY3HX+FYpS-JYv_FagZBVG5A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-11-28  8:46       ` Thierry Reding
2014-11-28  5:14   ` Alexandre Courbot
     [not found]     ` <547804B0.4020603-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2014-11-28  8:48       ` Thierry Reding
2014-11-28  8:52         ` Alexandre Courbot
2014-11-28  9:19           ` [Nouveau] " Thierry Reding
2014-11-28  5:32 ` Ilia Mirkin
2014-11-28  9:17   ` Thierry Reding
2014-11-28 15:54     ` [Mesa-dev] " Daniel Stone
2014-11-28 16:26 ` Emil Velikov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.