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

Rob Clark robdclark at gmail.com
Thu Nov 27 08:51:08 PST 2014


On Thu, Nov 27, 2014 at 11:39 AM, Thierry Reding
<thierry.reding at 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 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
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev


More information about the mesa-dev mailing list