[Nouveau] [RFC] tegra: Initial support

Thierry Reding thierry.reding at gmail.com
Thu Nov 27 08:39:21 PST 2014


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 at nvidia.com>
---
 configure.ac                                       |  12 +-
 src/gallium/Makefile.am                            |   5 +
 .../auxiliary/target-helpers/inline_drm_helper.h   |  30 +
 src/gallium/drivers/tegra/Automake.inc             |  11 +
 src/gallium/drivers/tegra/Makefile.am              |  17 +
 src/gallium/drivers/tegra/Makefile.sources         |   4 +
 src/gallium/drivers/tegra/tegra_context.c          | 699 +++++++++++++++++++++
 src/gallium/drivers/tegra/tegra_context.h          |  80 +++
 src/gallium/drivers/tegra/tegra_resource.c         | 219 +++++++
 src/gallium/drivers/tegra/tegra_resource.h         |  98 +++
 src/gallium/drivers/tegra/tegra_screen.c           | 311 +++++++++
 src/gallium/drivers/tegra/tegra_screen.h           |  45 ++
 src/gallium/targets/dri/Makefile.am                |   2 +
 src/gallium/winsys/tegra/drm/Makefile.am           |  11 +
 src/gallium/winsys/tegra/drm/Makefile.sources      |   2 +
 src/gallium/winsys/tegra/drm/tegra_drm_public.h    |  31 +
 src/gallium/winsys/tegra/drm/tegra_drm_winsys.c    |  33 +
 17 files changed, 1609 insertions(+), 1 deletion(-)
 create mode 100644 src/gallium/drivers/tegra/Automake.inc
 create mode 100644 src/gallium/drivers/tegra/Makefile.am
 create mode 100644 src/gallium/drivers/tegra/Makefile.sources
 create mode 100644 src/gallium/drivers/tegra/tegra_context.c
 create mode 100644 src/gallium/drivers/tegra/tegra_context.h
 create mode 100644 src/gallium/drivers/tegra/tegra_resource.c
 create mode 100644 src/gallium/drivers/tegra/tegra_resource.h
 create mode 100644 src/gallium/drivers/tegra/tegra_screen.c
 create mode 100644 src/gallium/drivers/tegra/tegra_screen.h
 create mode 100644 src/gallium/winsys/tegra/drm/Makefile.am
 create mode 100644 src/gallium/winsys/tegra/drm/Makefile.sources
 create mode 100644 src/gallium/winsys/tegra/drm/tegra_drm_public.h
 create mode 100644 src/gallium/winsys/tegra/drm/tegra_drm_winsys.c

diff --git a/configure.ac b/configure.ac
index 1d9d015481ec..ae50bec95339 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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



More information about the Nouveau mailing list