summaryrefslogtreecommitdiffstats
path: root/src/gallium
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium')
-rw-r--r--src/gallium/Makefile.am5
-rw-r--r--src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c7
-rw-r--r--src/gallium/auxiliary/target-helpers/drm_helper.h23
-rw-r--r--src/gallium/auxiliary/target-helpers/drm_helper_public.h3
-rw-r--r--src/gallium/drivers/tegra/Automake.inc11
-rw-r--r--src/gallium/drivers/tegra/Makefile.am14
-rw-r--r--src/gallium/drivers/tegra/Makefile.sources6
-rw-r--r--src/gallium/drivers/tegra/meson.build41
-rw-r--r--src/gallium/drivers/tegra/tegra_context.c1384
-rw-r--r--src/gallium/drivers/tegra/tegra_context.h81
-rw-r--r--src/gallium/drivers/tegra/tegra_resource.h76
-rw-r--r--src/gallium/drivers/tegra/tegra_screen.c688
-rw-r--r--src/gallium/drivers/tegra/tegra_screen.h45
-rw-r--r--src/gallium/meson.build6
-rw-r--r--src/gallium/targets/dri/Makefile.am2
-rw-r--r--src/gallium/targets/dri/meson.build4
-rw-r--r--src/gallium/targets/dri/target.c4
-rw-r--r--src/gallium/targets/vdpau/Makefile.am2
-rw-r--r--src/gallium/winsys/tegra/drm/Makefile.am13
-rw-r--r--src/gallium/winsys/tegra/drm/Makefile.sources2
-rw-r--r--src/gallium/winsys/tegra/drm/meson.build33
-rw-r--r--src/gallium/winsys/tegra/drm/tegra_drm_public.h31
-rw-r--r--src/gallium/winsys/tegra/drm/tegra_drm_winsys.c49
23 files changed, 2528 insertions, 2 deletions
diff --git a/src/gallium/Makefile.am b/src/gallium/Makefile.am
index 2c66064f79f..8170c9043da 100644
--- a/src/gallium/Makefile.am
+++ b/src/gallium/Makefile.am
@@ -89,6 +89,11 @@ if HAVE_GALLIUM_SWR
SUBDIRS += drivers/swr
endif
+## tegra
+if HAVE_GALLIUM_TEGRA
+SUBDIRS += drivers/tegra winsys/tegra/drm
+endif
+
## vc4/rpi
if HAVE_GALLIUM_VC4
SUBDIRS += drivers/vc4 winsys/vc4/drm
diff --git a/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c b/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c
index 810542101ed..b6be1b4f127 100644
--- a/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c
+++ b/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c
@@ -134,7 +134,12 @@ static const struct drm_driver_descriptor driver_descriptors[] = {
.driver_name = "imx-drm",
.create_screen = pipe_imx_drm_create_screen,
.configuration = pipe_default_configuration_query,
- }
+ },
+ {
+ .driver_name = "tegra",
+ .create_screen = pipe_tegra_create_screen,
+ .configuration = pipe_default_configuration_query,
+ },
};
#endif
diff --git a/src/gallium/auxiliary/target-helpers/drm_helper.h b/src/gallium/auxiliary/target-helpers/drm_helper.h
index 7aea83b8842..7dc2497c087 100644
--- a/src/gallium/auxiliary/target-helpers/drm_helper.h
+++ b/src/gallium/auxiliary/target-helpers/drm_helper.h
@@ -379,5 +379,28 @@ pipe_imx_drm_create_screen(int fd, const struct pipe_screen_config *config)
#endif
+#ifdef GALLIUM_TEGRA
+#include "tegra/drm/tegra_drm_public.h"
+
+struct pipe_screen *
+pipe_tegra_create_screen(int fd, const struct pipe_screen_config *config)
+{
+ struct pipe_screen *screen;
+
+ screen = tegra_drm_screen_create(fd);
+
+ return screen ? debug_screen_wrap(screen) : NULL;
+}
+
+#else
+
+struct pipe_screen *
+pipe_tegra_create_screen(int fd, const struct pipe_screen_config *config)
+{
+ fprintf(stderr, "tegra: driver missing\n");
+ return NULL;
+}
+
+#endif
#endif /* DRM_HELPER_H */
diff --git a/src/gallium/auxiliary/target-helpers/drm_helper_public.h b/src/gallium/auxiliary/target-helpers/drm_helper_public.h
index e21ea32fabe..c1a7bf4e252 100644
--- a/src/gallium/auxiliary/target-helpers/drm_helper_public.h
+++ b/src/gallium/auxiliary/target-helpers/drm_helper_public.h
@@ -51,6 +51,9 @@ pipe_etna_create_screen(int fd, const struct pipe_screen_config *config);
struct pipe_screen *
pipe_imx_drm_create_screen(int fd, const struct pipe_screen_config *config);
+struct pipe_screen *
+pipe_tegra_create_screen(int fd, const struct pipe_screen_config *config);
+
const struct drm_conf_ret *
pipe_default_configuration_query(enum drm_conf conf);
diff --git a/src/gallium/drivers/tegra/Automake.inc b/src/gallium/drivers/tegra/Automake.inc
new file mode 100644
index 00000000000..f6528191624
--- /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 00000000000..1347d2548dc
--- /dev/null
+++ b/src/gallium/drivers/tegra/Makefile.am
@@ -0,0 +1,14 @@
+include Makefile.sources
+include $(top_srcdir)/src/gallium/Automake.inc
+
+AM_CFLAGS = \
+ -I$(top_srcdir)/include/drm-uapi \
+ $(GALLIUM_DRIVER_CFLAGS)
+
+noinst_LTLIBRARIES = libtegra.la
+
+libtegra_la_SOURCES = \
+ $(C_SOURCES)
+
+EXTRA_DIST = \
+ meson.build
diff --git a/src/gallium/drivers/tegra/Makefile.sources b/src/gallium/drivers/tegra/Makefile.sources
new file mode 100644
index 00000000000..af4ff838c7c
--- /dev/null
+++ b/src/gallium/drivers/tegra/Makefile.sources
@@ -0,0 +1,6 @@
+C_SOURCES := \
+ tegra_context.c \
+ tegra_context.h \
+ tegra_resource.h \
+ tegra_screen.c \
+ tegra_screen.h
diff --git a/src/gallium/drivers/tegra/meson.build b/src/gallium/drivers/tegra/meson.build
new file mode 100644
index 00000000000..79ccd143f29
--- /dev/null
+++ b/src/gallium/drivers/tegra/meson.build
@@ -0,0 +1,41 @@
+# Copyright © 2018 NVIDIA CORPORATION
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+files_tegra = files(
+ 'tegra_context.c',
+ 'tegra_context.h',
+ 'tegra_resource.h',
+ 'tegra_screen.c',
+)
+
+libtegra = static_library(
+ 'tegra',
+ files_tegra,
+ c_args : [c_vis_args],
+ include_directories : [
+ inc_include, inc_src, inc_gallium, inc_gallium_aux, inc_gallium_drivers,
+ inc_gallium_winsys, inc_drm_uapi
+ ],
+)
+
+driver_tegra = declare_dependency(
+ compile_args : '-DGALLIUM_TEGRA',
+ link_with : [libtegra, libtegradrm],
+)
diff --git a/src/gallium/drivers/tegra/tegra_context.c b/src/gallium/drivers/tegra/tegra_context.c
new file mode 100644
index 00000000000..bbc03628336
--- /dev/null
+++ b/src/gallium/drivers/tegra/tegra_context.c
@@ -0,0 +1,1384 @@
+/*
+ * Copyright © 2014-2018 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include "util/u_debug.h"
+#include "util/u_inlines.h"
+#include "util/u_upload_mgr.h"
+
+#include "tegra_context.h"
+#include "tegra_resource.h"
+#include "tegra_screen.h"
+
+static void
+tegra_destroy(struct pipe_context *pcontext)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ if (context->base.stream_uploader)
+ u_upload_destroy(context->base.stream_uploader);
+
+ context->gpu->destroy(context->gpu);
+ free(context);
+}
+
+static void
+tegra_draw_vbo(struct pipe_context *pcontext,
+ const struct pipe_draw_info *pinfo)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+ struct pipe_draw_indirect_info indirect;
+ struct pipe_draw_info info;
+
+ if (pinfo && (pinfo->indirect || pinfo->index_size)) {
+ memcpy(&info, pinfo, sizeof(info));
+
+ if (pinfo->indirect) {
+ memcpy(&indirect, pinfo->indirect, sizeof(indirect));
+ indirect.buffer = tegra_resource_unwrap(info.indirect->buffer);
+ info.indirect = &indirect;
+ }
+
+ if (pinfo->index_size && !pinfo->has_user_indices)
+ info.index.resource = tegra_resource_unwrap(info.index.resource);
+
+ pinfo = &info;
+ }
+
+ context->gpu->draw_vbo(context->gpu, pinfo);
+}
+
+static void
+tegra_render_condition(struct pipe_context *pcontext,
+ struct pipe_query *query,
+ boolean condition,
+ unsigned int mode)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->render_condition(context->gpu, query, condition, mode);
+}
+
+static struct pipe_query *
+tegra_create_query(struct pipe_context *pcontext, unsigned int query_type,
+ unsigned int index)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_query(context->gpu, query_type, index);
+}
+
+static struct pipe_query *
+tegra_create_batch_query(struct pipe_context *pcontext,
+ unsigned int num_queries,
+ unsigned int *queries)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_batch_query(context->gpu, num_queries,
+ queries);
+}
+
+static void
+tegra_destroy_query(struct pipe_context *pcontext, struct pipe_query *query)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->destroy_query(context->gpu, query);
+}
+
+static boolean
+tegra_begin_query(struct pipe_context *pcontext, struct pipe_query *query)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->begin_query(context->gpu, query);
+}
+
+static bool
+tegra_end_query(struct pipe_context *pcontext, struct pipe_query *query)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->end_query(context->gpu, query);
+}
+
+static boolean
+tegra_get_query_result(struct pipe_context *pcontext,
+ struct pipe_query *query,
+ boolean wait,
+ union pipe_query_result *result)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->get_query_result(context->gpu, query, wait,
+ result);
+}
+
+static void
+tegra_get_query_result_resource(struct pipe_context *pcontext,
+ struct pipe_query *query,
+ boolean wait,
+ enum pipe_query_value_type result_type,
+ int index,
+ struct pipe_resource *resource,
+ unsigned int offset)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->get_query_result_resource(context->gpu, query, wait,
+ result_type, index, resource,
+ offset);
+}
+
+static void
+tegra_set_active_query_state(struct pipe_context *pcontext, boolean enable)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->set_active_query_state(context->gpu, enable);
+}
+
+static void *
+tegra_create_blend_state(struct pipe_context *pcontext,
+ const struct pipe_blend_state *cso)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_blend_state(context->gpu, cso);
+}
+
+static void
+tegra_bind_blend_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->bind_blend_state(context->gpu, so);
+}
+
+static void
+tegra_delete_blend_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->delete_blend_state(context->gpu, so);
+}
+
+static void *
+tegra_create_sampler_state(struct pipe_context *pcontext,
+ const struct pipe_sampler_state *cso)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_sampler_state(context->gpu, cso);
+}
+
+static void
+tegra_bind_sampler_states(struct pipe_context *pcontext, unsigned shader,
+ unsigned start_slot, unsigned num_samplers,
+ void **samplers)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->bind_sampler_states(context->gpu, shader, start_slot,
+ num_samplers, samplers);
+}
+
+static void
+tegra_delete_sampler_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->delete_sampler_state(context->gpu, so);
+}
+
+static void *
+tegra_create_rasterizer_state(struct pipe_context *pcontext,
+ const struct pipe_rasterizer_state *cso)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_rasterizer_state(context->gpu, cso);
+}
+
+static void
+tegra_bind_rasterizer_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->bind_rasterizer_state(context->gpu, so);
+}
+
+static void
+tegra_delete_rasterizer_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->delete_rasterizer_state(context->gpu, so);
+}
+
+static void *
+tegra_create_depth_stencil_alpha_state(struct pipe_context *pcontext,
+ const struct pipe_depth_stencil_alpha_state *cso)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_depth_stencil_alpha_state(context->gpu, cso);
+}
+
+static void
+tegra_bind_depth_stencil_alpha_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->bind_depth_stencil_alpha_state(context->gpu, so);
+}
+
+static void
+tegra_delete_depth_stencil_alpha_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->delete_depth_stencil_alpha_state(context->gpu, so);
+}
+
+static void *
+tegra_create_fs_state(struct pipe_context *pcontext,
+ const struct pipe_shader_state *cso)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_fs_state(context->gpu, cso);
+}
+
+static void
+tegra_bind_fs_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->bind_fs_state(context->gpu, so);
+}
+
+static void
+tegra_delete_fs_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->delete_fs_state(context->gpu, so);
+}
+
+static void *
+tegra_create_vs_state(struct pipe_context *pcontext,
+ const struct pipe_shader_state *cso)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_vs_state(context->gpu, cso);
+}
+
+static void
+tegra_bind_vs_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->bind_vs_state(context->gpu, so);
+}
+
+static void
+tegra_delete_vs_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->delete_vs_state(context->gpu, so);
+}
+
+static void *
+tegra_create_gs_state(struct pipe_context *pcontext,
+ const struct pipe_shader_state *cso)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_gs_state(context->gpu, cso);
+}
+
+static void
+tegra_bind_gs_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->bind_gs_state(context->gpu, so);
+}
+
+static void
+tegra_delete_gs_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->delete_gs_state(context->gpu, so);
+}
+
+static void *
+tegra_create_tcs_state(struct pipe_context *pcontext,
+ const struct pipe_shader_state *cso)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_tcs_state(context->gpu, cso);
+}
+
+static void
+tegra_bind_tcs_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->bind_tcs_state(context->gpu, so);
+}
+
+static void
+tegra_delete_tcs_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->delete_tcs_state(context->gpu, so);
+}
+
+static void *
+tegra_create_tes_state(struct pipe_context *pcontext,
+ const struct pipe_shader_state *cso)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_tes_state(context->gpu, cso);
+}
+
+static void
+tegra_bind_tes_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->bind_tes_state(context->gpu, so);
+}
+
+static void
+tegra_delete_tes_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->delete_tes_state(context->gpu, so);
+}
+
+static void *
+tegra_create_vertex_elements_state(struct pipe_context *pcontext,
+ unsigned num_elements,
+ const struct pipe_vertex_element *elements)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_vertex_elements_state(context->gpu,
+ num_elements,
+ elements);
+}
+
+static void
+tegra_bind_vertex_elements_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->bind_vertex_elements_state(context->gpu, so);
+}
+
+static void
+tegra_delete_vertex_elements_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->delete_vertex_elements_state(context->gpu, so);
+}
+
+static void
+tegra_set_blend_color(struct pipe_context *pcontext,
+ const struct pipe_blend_color *color)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->set_blend_color(context->gpu, color);
+}
+
+static void
+tegra_set_stencil_ref(struct pipe_context *pcontext,
+ const struct pipe_stencil_ref *ref)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->set_stencil_ref(context->gpu, ref);
+}
+
+static void
+tegra_set_sample_mask(struct pipe_context *pcontext, unsigned int mask)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->set_sample_mask(context->gpu, mask);
+}
+
+static void
+tegra_set_min_samples(struct pipe_context *pcontext, unsigned int samples)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->set_min_samples(context->gpu, samples);
+}
+
+static void
+tegra_set_clip_state(struct pipe_context *pcontext,
+ const struct pipe_clip_state *state)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->set_clip_state(context->gpu, state);
+}
+
+static void
+tegra_set_constant_buffer(struct pipe_context *pcontext, unsigned int shader,
+ unsigned int index,
+ const struct pipe_constant_buffer *buf)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+ struct pipe_constant_buffer buffer;
+
+ if (buf && buf->buffer) {
+ memcpy(&buffer, buf, sizeof(buffer));
+ buffer.buffer = tegra_resource_unwrap(buffer.buffer);
+ buf = &buffer;
+ }
+
+ context->gpu->set_constant_buffer(context->gpu, shader, index, buf);
+}
+
+static void
+tegra_set_framebuffer_state(struct pipe_context *pcontext,
+ const struct pipe_framebuffer_state *fb)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+ struct pipe_framebuffer_state state;
+ unsigned i;
+
+ if (fb) {
+ memcpy(&state, fb, sizeof(state));
+
+ for (i = 0; i < fb->nr_cbufs; i++)
+ state.cbufs[i] = tegra_surface_unwrap(fb->cbufs[i]);
+
+ while (i < PIPE_MAX_COLOR_BUFS)
+ state.cbufs[i++] = NULL;
+
+ state.zsbuf = tegra_surface_unwrap(fb->zsbuf);
+
+ fb = &state;
+ }
+
+ context->gpu->set_framebuffer_state(context->gpu, fb);
+}
+
+static void
+tegra_set_polygon_stipple(struct pipe_context *pcontext,
+ const struct pipe_poly_stipple *stipple)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->set_polygon_stipple(context->gpu, stipple);
+}
+
+static void
+tegra_set_scissor_states(struct pipe_context *pcontext, unsigned start_slot,
+ unsigned num_scissors,
+ const struct pipe_scissor_state *scissors)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->set_scissor_states(context->gpu, start_slot, num_scissors,
+ scissors);
+}
+
+static void
+tegra_set_window_rectangles(struct pipe_context *pcontext, boolean include,
+ unsigned int num_rectangles,
+ const struct pipe_scissor_state *rectangles)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->set_window_rectangles(context->gpu, include, num_rectangles,
+ rectangles);
+}
+
+static void
+tegra_set_viewport_states(struct pipe_context *pcontext, unsigned start_slot,
+ unsigned num_viewports,
+ const struct pipe_viewport_state *viewports)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->set_viewport_states(context->gpu, start_slot, num_viewports,
+ viewports);
+}
+
+static void
+tegra_set_sampler_views(struct pipe_context *pcontext, unsigned shader,
+ unsigned start_slot, unsigned num_views,
+ struct pipe_sampler_view **pviews)
+{
+ struct pipe_sampler_view *views[PIPE_MAX_SHADER_SAMPLER_VIEWS];
+ struct tegra_context *context = to_tegra_context(pcontext);
+ unsigned i;
+
+ for (i = 0; i < num_views; i++)
+ views[i] = tegra_sampler_view_unwrap(pviews[i]);
+
+ context->gpu->set_sampler_views(context->gpu, shader, start_slot,
+ num_views, views);
+}
+
+static void
+tegra_set_tess_state(struct pipe_context *pcontext,
+ const float default_outer_level[4],
+ const float default_inner_level[2])
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->set_tess_state(context->gpu, default_outer_level,
+ default_inner_level);
+}
+
+static void
+tegra_set_debug_callback(struct pipe_context *pcontext,
+ const struct pipe_debug_callback *callback)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->set_debug_callback(context->gpu, callback);
+}
+
+static void
+tegra_set_shader_buffers(struct pipe_context *pcontext, unsigned int shader,
+ unsigned start, unsigned count,
+ const struct pipe_shader_buffer *buffers)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->set_shader_buffers(context->gpu, shader, start, count,
+ buffers);
+}
+
+static void
+tegra_set_shader_images(struct pipe_context *pcontext, unsigned int shader,
+ unsigned start, unsigned count,
+ const struct pipe_image_view *images)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->set_shader_images(context->gpu, shader, start, count,
+ images);
+}
+
+static void
+tegra_set_vertex_buffers(struct pipe_context *pcontext, unsigned start_slot,
+ unsigned num_buffers,
+ const struct pipe_vertex_buffer *buffers)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+ struct pipe_vertex_buffer buf[PIPE_MAX_SHADER_INPUTS];
+ unsigned i;
+
+ if (num_buffers && buffers) {
+ memcpy(buf, buffers, num_buffers * sizeof(struct pipe_vertex_buffer));
+
+ for (i = 0; i < num_buffers; i++) {
+ if (!buf[i].is_user_buffer)
+ buf[i].buffer.resource = tegra_resource_unwrap(buf[i].buffer.resource);
+ }
+
+ buffers = buf;
+ }
+
+ context->gpu->set_vertex_buffers(context->gpu, start_slot, num_buffers,
+ buffers);
+}
+
+static struct pipe_stream_output_target *
+tegra_create_stream_output_target(struct pipe_context *pcontext,
+ struct pipe_resource *presource,
+ unsigned buffer_offset,
+ unsigned buffer_size)
+{
+ struct tegra_resource *resource = to_tegra_resource(presource);
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_stream_output_target(context->gpu,
+ resource->gpu,
+ buffer_offset,
+ buffer_size);
+}
+
+static void
+tegra_stream_output_target_destroy(struct pipe_context *pcontext,
+ struct pipe_stream_output_target *target)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->stream_output_target_destroy(context->gpu, target);
+}
+
+static void
+tegra_set_stream_output_targets(struct pipe_context *pcontext,
+ unsigned num_targets,
+ struct pipe_stream_output_target **targets,
+ const unsigned *offsets)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->set_stream_output_targets(context->gpu, num_targets,
+ targets, offsets);
+}
+
+static void
+tegra_resource_copy_region(struct pipe_context *pcontext,
+ struct pipe_resource *pdst,
+ unsigned int dst_level,
+ unsigned int dstx,
+ unsigned int dsty,
+ unsigned int dstz,
+ struct pipe_resource *psrc,
+ unsigned int src_level,
+ const struct pipe_box *src_box)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+ struct tegra_resource *dst = to_tegra_resource(pdst);
+ struct tegra_resource *src = to_tegra_resource(psrc);
+
+ context->gpu->resource_copy_region(context->gpu, dst->gpu, dst_level, dstx,
+ dsty, dstz, src->gpu, src_level,
+ src_box);
+}
+
+static void
+tegra_blit(struct pipe_context *pcontext, const struct pipe_blit_info *pinfo)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+ struct pipe_blit_info info;
+
+ if (pinfo) {
+ memcpy(&info, pinfo, sizeof(info));
+ info.dst.resource = tegra_resource_unwrap(info.dst.resource);
+ info.src.resource = tegra_resource_unwrap(info.src.resource);
+ pinfo = &info;
+ }
+
+ context->gpu->blit(context->gpu, pinfo);
+}
+
+static void
+tegra_clear(struct pipe_context *pcontext, unsigned buffers,
+ const union pipe_color_union *color, double depth,
+ unsigned stencil)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->clear(context->gpu, buffers, color, depth, stencil);
+}
+
+static void
+tegra_clear_render_target(struct pipe_context *pcontext,
+ struct pipe_surface *pdst,
+ const union pipe_color_union *color,
+ unsigned int dstx,
+ unsigned int dsty,
+ unsigned int width,
+ unsigned int height,
+ bool render_condition)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+ struct tegra_surface *dst = to_tegra_surface(pdst);
+
+ context->gpu->clear_render_target(context->gpu, dst->gpu, color, dstx,
+ dsty, width, height, render_condition);
+}
+
+static void
+tegra_clear_depth_stencil(struct pipe_context *pcontext,
+ struct pipe_surface *pdst,
+ unsigned int flags,
+ double depth,
+ unsigned int stencil,
+ unsigned int dstx,
+ unsigned int dsty,
+ unsigned int width,
+ unsigned int height,
+ bool render_condition)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+ struct tegra_surface *dst = to_tegra_surface(pdst);
+
+ context->gpu->clear_depth_stencil(context->gpu, dst->gpu, flags, depth,
+ stencil, dstx, dsty, width, height,
+ render_condition);
+}
+
+static void
+tegra_clear_texture(struct pipe_context *pcontext,
+ struct pipe_resource *presource,
+ unsigned int level,
+ const struct pipe_box *box,
+ const void *data)
+{
+ struct tegra_resource *resource = to_tegra_resource(presource);
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->clear_texture(context->gpu, resource->gpu, level, box, data);
+}
+
+static void
+tegra_clear_buffer(struct pipe_context *pcontext,
+ struct pipe_resource *presource,
+ unsigned int offset,
+ unsigned int size,
+ const void *value,
+ int value_size)
+{
+ struct tegra_resource *resource = to_tegra_resource(presource);
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->clear_buffer(context->gpu, resource->gpu, offset, size,
+ value, value_size);
+}
+
+static void
+tegra_flush(struct pipe_context *pcontext, struct pipe_fence_handle **fence,
+ unsigned flags)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->flush(context->gpu, fence, flags);
+}
+
+static void
+tegra_create_fence_fd(struct pipe_context *pcontext,
+ struct pipe_fence_handle **fence,
+ int fd, enum pipe_fd_type type)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ assert(type == PIPE_FD_TYPE_NATIVE_SYNC);
+ context->gpu->create_fence_fd(context->gpu, fence, fd, type);
+}
+
+static void
+tegra_fence_server_sync(struct pipe_context *pcontext,
+ struct pipe_fence_handle *fence)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->fence_server_sync(context->gpu, fence);
+}
+
+static struct pipe_sampler_view *
+tegra_create_sampler_view(struct pipe_context *pcontext,
+ struct pipe_resource *presource,
+ const struct pipe_sampler_view *template)
+{
+ struct tegra_resource *resource = to_tegra_resource(presource);
+ struct tegra_context *context = to_tegra_context(pcontext);
+ struct tegra_sampler_view *view;
+
+ view = calloc(1, sizeof(*view));
+ if (!view)
+ return NULL;
+
+ view->gpu = context->gpu->create_sampler_view(context->gpu, resource->gpu,
+ template);
+ memcpy(&view->base, view->gpu, sizeof(*view->gpu));
+ /* overwrite to prevent reference from being released */
+ view->base.texture = NULL;
+
+ pipe_reference_init(&view->base.reference, 1);
+ pipe_resource_reference(&view->base.texture, presource);
+ view->base.context = pcontext;
+
+ return &view->base;
+}
+
+static void
+tegra_sampler_view_destroy(struct pipe_context *pcontext,
+ struct pipe_sampler_view *pview)
+{
+ struct tegra_sampler_view *view = to_tegra_sampler_view(pview);
+
+ pipe_resource_reference(&view->base.texture, NULL);
+ pipe_sampler_view_reference(&view->gpu, NULL);
+ free(view);
+}
+
+static struct pipe_surface *
+tegra_create_surface(struct pipe_context *pcontext,
+ struct pipe_resource *presource,
+ const struct pipe_surface *template)
+{
+ struct tegra_resource *resource = to_tegra_resource(presource);
+ struct tegra_context *context = to_tegra_context(pcontext);
+ struct tegra_surface *surface;
+
+ surface = calloc(1, sizeof(*surface));
+ if (!surface)
+ return NULL;
+
+ surface->gpu = context->gpu->create_surface(context->gpu, resource->gpu,
+ template);
+ if (!surface->gpu) {
+ free(surface);
+ return NULL;
+ }
+
+ memcpy(&surface->base, surface->gpu, sizeof(*surface->gpu));
+ /* overwrite to prevent reference from being released */
+ surface->base.texture = NULL;
+
+ pipe_reference_init(&surface->base.reference, 1);
+ pipe_resource_reference(&surface->base.texture, presource);
+ surface->base.context = &context->base;
+
+ return &surface->base;
+}
+
+static void
+tegra_surface_destroy(struct pipe_context *pcontext,
+ struct pipe_surface *psurface)
+{
+ struct tegra_surface *surface = to_tegra_surface(psurface);
+
+ pipe_resource_reference(&surface->base.texture, NULL);
+ pipe_surface_reference(&surface->gpu, NULL);
+ free(surface);
+}
+
+static void *
+tegra_transfer_map(struct pipe_context *pcontext,
+ struct pipe_resource *presource,
+ unsigned level, unsigned usage,
+ const struct pipe_box *box,
+ struct pipe_transfer **ptransfer)
+{
+ struct tegra_resource *resource = to_tegra_resource(presource);
+ struct tegra_context *context = to_tegra_context(pcontext);
+ struct tegra_transfer *transfer;
+
+ transfer = calloc(1, sizeof(*transfer));
+ if (!transfer)
+ return NULL;
+
+ transfer->map = context->gpu->transfer_map(context->gpu, resource->gpu,
+ level, usage, box,
+ &transfer->gpu);
+ memcpy(&transfer->base, transfer->gpu, sizeof(*transfer->gpu));
+ transfer->base.resource = NULL;
+ pipe_resource_reference(&transfer->base.resource, presource);
+
+ *ptransfer = &transfer->base;
+
+ return transfer->map;
+}
+
+static void
+tegra_transfer_flush_region(struct pipe_context *pcontext,
+ struct pipe_transfer *ptransfer,
+ const struct pipe_box *box)
+{
+ struct tegra_transfer *transfer = to_tegra_transfer(ptransfer);
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->transfer_flush_region(context->gpu, transfer->gpu, box);
+}
+
+static void
+tegra_transfer_unmap(struct pipe_context *pcontext,
+ struct pipe_transfer *ptransfer)
+{
+ struct tegra_transfer *transfer = to_tegra_transfer(ptransfer);
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->transfer_unmap(context->gpu, transfer->gpu);
+ pipe_resource_reference(&transfer->base.resource, NULL);
+ free(transfer);
+}
+
+static void
+tegra_buffer_subdata(struct pipe_context *pcontext,
+ struct pipe_resource *presource,
+ unsigned usage, unsigned offset,
+ unsigned size, const void *data)
+{
+ struct tegra_resource *resource = to_tegra_resource(presource);
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->buffer_subdata(context->gpu, resource->gpu, usage, offset,
+ size, data);
+}
+
+static void
+tegra_texture_subdata(struct pipe_context *pcontext,
+ struct pipe_resource *presource,
+ unsigned level,
+ unsigned usage,
+ const struct pipe_box *box,
+ const void *data,
+ unsigned stride,
+ unsigned layer_stride)
+{
+ struct tegra_resource *resource = to_tegra_resource(presource);
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->texture_subdata(context->gpu, resource->gpu, level, usage,
+ box, data, stride, layer_stride);
+}
+
+static void
+tegra_texture_barrier(struct pipe_context *pcontext, unsigned int flags)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->texture_barrier(context->gpu, flags);
+}
+
+static void
+tegra_memory_barrier(struct pipe_context *pcontext, unsigned int flags)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->memory_barrier(context->gpu, flags);
+}
+
+static struct pipe_video_codec *
+tegra_create_video_codec(struct pipe_context *pcontext,
+ const struct pipe_video_codec *template)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_video_codec(context->gpu, template);
+}
+
+static struct pipe_video_buffer *
+tegra_create_video_buffer(struct pipe_context *pcontext,
+ const struct pipe_video_buffer *template)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_video_buffer(context->gpu, template);
+}
+
+static void *
+tegra_create_compute_state(struct pipe_context *pcontext,
+ const struct pipe_compute_state *template)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_compute_state(context->gpu, template);
+}
+
+static void
+tegra_bind_compute_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->bind_compute_state(context->gpu, so);
+}
+
+static void
+tegra_delete_compute_state(struct pipe_context *pcontext, void *so)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->delete_compute_state(context->gpu, so);
+}
+
+static void
+tegra_set_compute_resources(struct pipe_context *pcontext,
+ unsigned int start, unsigned int count,
+ struct pipe_surface **resources)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ /* XXX unwrap resources */
+
+ context->gpu->set_compute_resources(context->gpu, start, count, resources);
+}
+
+static void
+tegra_set_global_binding(struct pipe_context *pcontext, unsigned int first,
+ unsigned int count, struct pipe_resource **resources,
+ uint32_t **handles)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ /* XXX unwrap resources */
+
+ context->gpu->set_global_binding(context->gpu, first, count, resources,
+ handles);
+}
+
+static void
+tegra_launch_grid(struct pipe_context *pcontext,
+ const struct pipe_grid_info *info)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ /* XXX unwrap info->indirect? */
+
+ context->gpu->launch_grid(context->gpu, info);
+}
+
+static void
+tegra_get_sample_position(struct pipe_context *pcontext, unsigned int count,
+ unsigned int index, float *value)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->get_sample_position(context->gpu, count, index, value);
+}
+
+static uint64_t
+tegra_get_timestamp(struct pipe_context *pcontext)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->get_timestamp(context->gpu);
+}
+
+static void
+tegra_flush_resource(struct pipe_context *pcontext,
+ struct pipe_resource *presource)
+{
+ struct tegra_resource *resource = to_tegra_resource(presource);
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->flush_resource(context->gpu, resource->gpu);
+}
+
+static void
+tegra_invalidate_resource(struct pipe_context *pcontext,
+ struct pipe_resource *presource)
+{
+ struct tegra_resource *resource = to_tegra_resource(presource);
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->invalidate_resource(context->gpu, resource->gpu);
+}
+
+static enum pipe_reset_status
+tegra_get_device_reset_status(struct pipe_context *pcontext)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->get_device_reset_status(context->gpu);
+}
+
+static void
+tegra_set_device_reset_callback(struct pipe_context *pcontext,
+ const struct pipe_device_reset_callback *cb)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->set_device_reset_callback(context->gpu, cb);
+}
+
+static void
+tegra_dump_debug_state(struct pipe_context *pcontext, FILE *stream,
+ unsigned int flags)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->dump_debug_state(context->gpu, stream, flags);
+}
+
+static void
+tegra_emit_string_marker(struct pipe_context *pcontext, const char *string,
+ int length)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->emit_string_marker(context->gpu, string, length);
+}
+
+static boolean
+tegra_generate_mipmap(struct pipe_context *pcontext,
+ struct pipe_resource *presource,
+ enum pipe_format format,
+ unsigned int base_level,
+ unsigned int last_level,
+ unsigned int first_layer,
+ unsigned int last_layer)
+{
+ struct tegra_resource *resource = to_tegra_resource(presource);
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->generate_mipmap(context->gpu, resource->gpu, format,
+ base_level, last_level, first_layer,
+ last_layer);
+}
+
+static uint64_t
+tegra_create_texture_handle(struct pipe_context *pcontext,
+ struct pipe_sampler_view *view,
+ const struct pipe_sampler_state *state)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_texture_handle(context->gpu, view, state);
+}
+
+static void tegra_delete_texture_handle(struct pipe_context *pcontext,
+ uint64_t handle)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->delete_texture_handle(context->gpu, handle);
+}
+
+static void tegra_make_texture_handle_resident(struct pipe_context *pcontext,
+ uint64_t handle, bool resident)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->make_texture_handle_resident(context->gpu, handle, resident);
+}
+
+static uint64_t tegra_create_image_handle(struct pipe_context *pcontext,
+ const struct pipe_image_view *image)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ return context->gpu->create_image_handle(context->gpu, image);
+}
+
+static void tegra_delete_image_handle(struct pipe_context *pcontext,
+ uint64_t handle)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->delete_image_handle(context->gpu, handle);
+}
+
+static void tegra_make_image_handle_resident(struct pipe_context *pcontext,
+ uint64_t handle, unsigned access,
+ bool resident)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+
+ context->gpu->make_image_handle_resident(context->gpu, handle, access,
+ resident);
+}
+
+struct pipe_context *
+tegra_screen_context_create(struct pipe_screen *pscreen, void *priv,
+ unsigned int flags)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+ struct tegra_context *context;
+
+ context = calloc(1, sizeof(*context));
+ if (!context)
+ return NULL;
+
+ context->gpu = screen->gpu->context_create(screen->gpu, priv, flags);
+ if (!context->gpu) {
+ debug_error("failed to create GPU context\n");
+ goto free;
+ }
+
+ context->base.screen = &screen->base;
+ context->base.priv = priv;
+
+ /*
+ * Create custom stream and const uploaders. Note that technically nouveau
+ * already creates uploaders that could be reused, but that would make the
+ * resource unwrapping rather complicate. The reason for that is that both
+ * uploaders create resources based on the context that they were created
+ * from, which means that nouveau's uploader will use the nouveau context
+ * which means that those resources must not be unwrapped. So before each
+ * resource is unwrapped, the code would need to check that it does not
+ * correspond to the uploaders' buffers.
+ *
+ * However, duplicating the uploaders here sounds worse than it is. The
+ * default implementation that nouveau uses allocates buffers lazily, and
+ * since it is never used, no buffers will every be allocated and the only
+ * memory wasted is that occupied by the nouveau uploader itself.
+ */
+ context->base.stream_uploader = u_upload_create_default(&context->base);
+ if (!context->base.stream_uploader)
+ goto destroy;
+
+ context->base.const_uploader = context->base.stream_uploader;
+
+ context->base.destroy = tegra_destroy;
+
+ context->base.draw_vbo = tegra_draw_vbo;
+
+ context->base.render_condition = tegra_render_condition;
+
+ context->base.create_query = tegra_create_query;
+ context->base.create_batch_query = tegra_create_batch_query;
+ context->base.destroy_query = tegra_destroy_query;
+ context->base.begin_query = tegra_begin_query;
+ context->base.end_query = tegra_end_query;
+ context->base.get_query_result = tegra_get_query_result;
+ context->base.get_query_result_resource = tegra_get_query_result_resource;
+ context->base.set_active_query_state = tegra_set_active_query_state;
+
+ context->base.create_blend_state = tegra_create_blend_state;
+ context->base.bind_blend_state = tegra_bind_blend_state;
+ context->base.delete_blend_state = tegra_delete_blend_state;
+
+ context->base.create_sampler_state = tegra_create_sampler_state;
+ context->base.bind_sampler_states = tegra_bind_sampler_states;
+ context->base.delete_sampler_state = tegra_delete_sampler_state;
+
+ context->base.create_rasterizer_state = tegra_create_rasterizer_state;
+ context->base.bind_rasterizer_state = tegra_bind_rasterizer_state;
+ context->base.delete_rasterizer_state = tegra_delete_rasterizer_state;
+
+ context->base.create_depth_stencil_alpha_state = tegra_create_depth_stencil_alpha_state;
+ context->base.bind_depth_stencil_alpha_state = tegra_bind_depth_stencil_alpha_state;
+ context->base.delete_depth_stencil_alpha_state = tegra_delete_depth_stencil_alpha_state;
+
+ context->base.create_fs_state = tegra_create_fs_state;
+ context->base.bind_fs_state = tegra_bind_fs_state;
+ context->base.delete_fs_state = tegra_delete_fs_state;
+
+ context->base.create_vs_state = tegra_create_vs_state;
+ context->base.bind_vs_state = tegra_bind_vs_state;
+ context->base.delete_vs_state = tegra_delete_vs_state;
+
+ context->base.create_gs_state = tegra_create_gs_state;
+ context->base.bind_gs_state = tegra_bind_gs_state;
+ context->base.delete_gs_state = tegra_delete_gs_state;
+
+ context->base.create_tcs_state = tegra_create_tcs_state;
+ context->base.bind_tcs_state = tegra_bind_tcs_state;
+ context->base.delete_tcs_state = tegra_delete_tcs_state;
+
+ context->base.create_tes_state = tegra_create_tes_state;
+ context->base.bind_tes_state = tegra_bind_tes_state;
+ context->base.delete_tes_state = tegra_delete_tes_state;
+
+ context->base.create_vertex_elements_state = tegra_create_vertex_elements_state;
+ context->base.bind_vertex_elements_state = tegra_bind_vertex_elements_state;
+ context->base.delete_vertex_elements_state = tegra_delete_vertex_elements_state;
+
+ context->base.set_blend_color = tegra_set_blend_color;
+ context->base.set_stencil_ref = tegra_set_stencil_ref;
+ context->base.set_sample_mask = tegra_set_sample_mask;
+ context->base.set_min_samples = tegra_set_min_samples;
+ context->base.set_clip_state = tegra_set_clip_state;
+
+ context->base.set_constant_buffer = tegra_set_constant_buffer;
+ context->base.set_framebuffer_state = tegra_set_framebuffer_state;
+ context->base.set_polygon_stipple = tegra_set_polygon_stipple;
+ context->base.set_scissor_states = tegra_set_scissor_states;
+ context->base.set_window_rectangles = tegra_set_window_rectangles;
+ context->base.set_viewport_states = tegra_set_viewport_states;
+ context->base.set_sampler_views = tegra_set_sampler_views;
+ context->base.set_tess_state = tegra_set_tess_state;
+
+ context->base.set_debug_callback = tegra_set_debug_callback;
+
+ context->base.set_shader_buffers = tegra_set_shader_buffers;
+ context->base.set_shader_images = tegra_set_shader_images;
+ context->base.set_vertex_buffers = tegra_set_vertex_buffers;
+
+ context->base.create_stream_output_target = tegra_create_stream_output_target;
+ context->base.stream_output_target_destroy = tegra_stream_output_target_destroy;
+ context->base.set_stream_output_targets = tegra_set_stream_output_targets;
+
+ context->base.resource_copy_region = tegra_resource_copy_region;
+ context->base.blit = tegra_blit;
+ context->base.clear = tegra_clear;
+ context->base.clear_render_target = tegra_clear_render_target;
+ context->base.clear_depth_stencil = tegra_clear_depth_stencil;
+ context->base.clear_texture = tegra_clear_texture;
+ context->base.clear_buffer = tegra_clear_buffer;
+ context->base.flush = tegra_flush;
+
+ context->base.create_fence_fd = tegra_create_fence_fd;
+ context->base.fence_server_sync = tegra_fence_server_sync;
+
+ context->base.create_sampler_view = tegra_create_sampler_view;
+ context->base.sampler_view_destroy = tegra_sampler_view_destroy;
+
+ context->base.create_surface = tegra_create_surface;
+ context->base.surface_destroy = tegra_surface_destroy;
+
+ context->base.transfer_map = tegra_transfer_map;
+ context->base.transfer_flush_region = tegra_transfer_flush_region;
+ context->base.transfer_unmap = tegra_transfer_unmap;
+ context->base.buffer_subdata = tegra_buffer_subdata;
+ context->base.texture_subdata = tegra_texture_subdata;
+
+ context->base.texture_barrier = tegra_texture_barrier;
+ context->base.memory_barrier = tegra_memory_barrier;
+
+ context->base.create_video_codec = tegra_create_video_codec;
+ context->base.create_video_buffer = tegra_create_video_buffer;
+
+ context->base.create_compute_state = tegra_create_compute_state;
+ context->base.bind_compute_state = tegra_bind_compute_state;
+ context->base.delete_compute_state = tegra_delete_compute_state;
+ context->base.set_compute_resources = tegra_set_compute_resources;
+ context->base.set_global_binding = tegra_set_global_binding;
+ context->base.launch_grid = tegra_launch_grid;
+ context->base.get_sample_position = tegra_get_sample_position;
+ context->base.get_timestamp = tegra_get_timestamp;
+
+ context->base.flush_resource = tegra_flush_resource;
+ context->base.invalidate_resource = tegra_invalidate_resource;
+
+ context->base.get_device_reset_status = tegra_get_device_reset_status;
+ context->base.set_device_reset_callback = tegra_set_device_reset_callback;
+ context->base.dump_debug_state = tegra_dump_debug_state;
+ context->base.emit_string_marker = tegra_emit_string_marker;
+
+ context->base.generate_mipmap = tegra_generate_mipmap;
+
+ context->base.create_texture_handle = tegra_create_texture_handle;
+ context->base.delete_texture_handle = tegra_delete_texture_handle;
+ context->base.make_texture_handle_resident = tegra_make_texture_handle_resident;
+ context->base.create_image_handle = tegra_create_image_handle;
+ context->base.delete_image_handle = tegra_delete_image_handle;
+ context->base.make_image_handle_resident = tegra_make_image_handle_resident;
+
+ return &context->base;
+
+destroy:
+ context->gpu->destroy(context->gpu);
+free:
+ free(context);
+ return NULL;
+}
diff --git a/src/gallium/drivers/tegra/tegra_context.h b/src/gallium/drivers/tegra/tegra_context.h
new file mode 100644
index 00000000000..4869b0913a6
--- /dev/null
+++ b/src/gallium/drivers/tegra/tegra_context.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright © 2014-2018 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef TEGRA_CONTEXT_H
+#define TEGRA_CONTEXT_H
+
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+
+struct tegra_screen;
+
+struct tegra_context {
+ struct pipe_context base;
+ struct pipe_context *gpu;
+};
+
+static inline struct tegra_context *
+to_tegra_context(struct pipe_context *context)
+{
+ return (struct tegra_context *)context;
+}
+
+struct pipe_context *
+tegra_screen_context_create(struct pipe_screen *pscreen, void *priv,
+ unsigned int flags);
+
+struct tegra_sampler_view {
+ struct pipe_sampler_view base;
+ struct pipe_sampler_view *gpu;
+};
+
+static inline struct tegra_sampler_view *
+to_tegra_sampler_view(struct pipe_sampler_view *view)
+{
+ return (struct tegra_sampler_view *)view;
+}
+
+static inline struct pipe_sampler_view *
+tegra_sampler_view_unwrap(struct pipe_sampler_view *view)
+{
+ if (!view)
+ return NULL;
+
+ return to_tegra_sampler_view(view)->gpu;
+}
+
+struct tegra_transfer {
+ struct pipe_transfer base;
+ struct pipe_transfer *gpu;
+
+ unsigned int count;
+ void *map;
+};
+
+static inline struct tegra_transfer *
+to_tegra_transfer(struct pipe_transfer *transfer)
+{
+ return (struct tegra_transfer *)transfer;
+}
+
+#endif /* TEGRA_SCREEN_H */
diff --git a/src/gallium/drivers/tegra/tegra_resource.h b/src/gallium/drivers/tegra/tegra_resource.h
new file mode 100644
index 00000000000..67507d64590
--- /dev/null
+++ b/src/gallium/drivers/tegra/tegra_resource.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright © 2014-2018 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef TEGRA_RESOURCE_H
+#define TEGRA_RESOURCE_H
+
+#include "pipe/p_state.h"
+
+struct winsys_handle;
+
+struct tegra_resource {
+ struct pipe_resource base;
+ struct pipe_resource *gpu;
+
+ uint64_t modifier;
+ uint32_t stride;
+ uint32_t handle;
+ size_t size;
+};
+
+static inline struct tegra_resource *
+to_tegra_resource(struct pipe_resource *resource)
+{
+ return (struct tegra_resource *)resource;
+}
+
+static inline struct pipe_resource *
+tegra_resource_unwrap(struct pipe_resource *resource)
+{
+ if (!resource)
+ return NULL;
+
+ return to_tegra_resource(resource)->gpu;
+}
+
+struct tegra_surface {
+ struct pipe_surface base;
+ struct pipe_surface *gpu;
+};
+
+static inline struct tegra_surface *
+to_tegra_surface(struct pipe_surface *surface)
+{
+ return (struct tegra_surface *)surface;
+}
+
+static inline struct pipe_surface *
+tegra_surface_unwrap(struct pipe_surface *surface)
+{
+ if (!surface)
+ return NULL;
+
+ return to_tegra_surface(surface)->gpu;
+}
+
+#endif /* TEGRA_RESOURCE_H */
diff --git a/src/gallium/drivers/tegra/tegra_screen.c b/src/gallium/drivers/tegra/tegra_screen.c
new file mode 100644
index 00000000000..669f22a1944
--- /dev/null
+++ b/src/gallium/drivers/tegra/tegra_screen.c
@@ -0,0 +1,688 @@
+/*
+ * Copyright © 2014-2018 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+
+#include <sys/stat.h>
+
+#include <drm_fourcc.h>
+#include <tegra_drm.h>
+#include <xf86drm.h>
+
+#include "pipe/p_state.h"
+#include "util/u_debug.h"
+#include "util/u_inlines.h"
+
+#include "state_tracker/drm_driver.h"
+
+#include "nouveau/drm/nouveau_drm_public.h"
+
+#include "tegra_context.h"
+#include "tegra_resource.h"
+#include "tegra_screen.h"
+
+static void tegra_screen_destroy(struct pipe_screen *pscreen)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ screen->gpu->destroy(screen->gpu);
+ free(pscreen);
+}
+
+static const char *
+tegra_screen_get_name(struct pipe_screen *pscreen)
+{
+ return "tegra";
+}
+
+static const char *
+tegra_screen_get_vendor(struct pipe_screen *pscreen)
+{
+ return "NVIDIA";
+}
+
+static const char *
+tegra_screen_get_device_vendor(struct pipe_screen *pscreen)
+{
+ return "NVIDIA";
+}
+
+static int
+tegra_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ return screen->gpu->get_param(screen->gpu, param);
+}
+
+static float
+tegra_screen_get_paramf(struct pipe_screen *pscreen, enum pipe_capf param)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ return screen->gpu->get_paramf(screen->gpu, param);
+}
+
+static int
+tegra_screen_get_shader_param(struct pipe_screen *pscreen, unsigned shader,
+ enum pipe_shader_cap param)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ return screen->gpu->get_shader_param(screen->gpu, shader, param);
+}
+
+static int
+tegra_screen_get_video_param(struct pipe_screen *pscreen,
+ enum pipe_video_profile profile,
+ enum pipe_video_entrypoint entrypoint,
+ enum pipe_video_cap param)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ return screen->gpu->get_video_param(screen->gpu, profile, entrypoint,
+ param);
+}
+
+static int
+tegra_screen_get_compute_param(struct pipe_screen *pscreen,
+ enum pipe_shader_ir ir_type,
+ enum pipe_compute_cap param,
+ void *retp)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ return screen->gpu->get_compute_param(screen->gpu, ir_type, param,
+ retp);
+}
+
+static uint64_t
+tegra_screen_get_timestamp(struct pipe_screen *pscreen)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ return screen->gpu->get_timestamp(screen->gpu);
+}
+
+static boolean
+tegra_screen_is_format_supported(struct pipe_screen *pscreen,
+ enum pipe_format format,
+ enum pipe_texture_target target,
+ unsigned sample_count,
+ unsigned usage)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ return screen->gpu->is_format_supported(screen->gpu, format, target,
+ sample_count, usage);
+}
+
+static boolean
+tegra_screen_is_video_format_supported(struct pipe_screen *pscreen,
+ enum pipe_format format,
+ enum pipe_video_profile profile,
+ enum pipe_video_entrypoint entrypoint)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ return screen->gpu->is_video_format_supported(screen->gpu, format, profile,
+ entrypoint);
+}
+
+static boolean
+tegra_screen_can_create_resource(struct pipe_screen *pscreen,
+ const struct pipe_resource *template)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ return screen->gpu->can_create_resource(screen->gpu, template);
+}
+
+static int tegra_open_render_node(void)
+{
+ drmDevicePtr *devices, device;
+ int err, render = -ENOENT, fd;
+ unsigned int num, i;
+
+ err = drmGetDevices2(0, NULL, 0);
+ if (err < 0)
+ return err;
+
+ num = err;
+
+ devices = calloc(num, sizeof(*devices));
+ if (!devices)
+ return -ENOMEM;
+
+ err = drmGetDevices2(0, devices, num);
+ if (err < 0) {
+ render = err;
+ goto free;
+ }
+
+ for (i = 0; i < num; i++) {
+ device = devices[i];
+
+ if ((device->available_nodes & (1 << DRM_NODE_RENDER)) &&
+ (device->bustype == DRM_BUS_PLATFORM)) {
+ drmVersionPtr version;
+
+ fd = open(device->nodes[DRM_NODE_RENDER], O_RDWR | O_CLOEXEC);
+ if (fd < 0)
+ continue;
+
+ version = drmGetVersion(fd);
+ if (!version) {
+ close(fd);
+ continue;
+ }
+
+ if (strcmp(version->name, "nouveau") != 0) {
+ close(fd);
+ continue;
+ }
+
+ drmFreeVersion(version);
+ render = fd;
+ break;
+ }
+ }
+
+ drmFreeDevices(devices, num);
+
+free:
+ free(devices);
+ return render;
+}
+
+static int tegra_screen_import_resource(struct tegra_screen *screen,
+ struct tegra_resource *resource,
+ bool has_modifiers)
+{
+ unsigned usage = PIPE_HANDLE_USAGE_READ;
+ struct drm_tegra_gem_set_tiling args;
+ struct winsys_handle handle;
+ boolean status;
+ int fd, err;
+
+ memset(&handle, 0, sizeof(handle));
+ handle.modifier = DRM_FORMAT_MOD_INVALID;
+ handle.type = DRM_API_HANDLE_TYPE_FD;
+
+ status = screen->gpu->resource_get_handle(screen->gpu, NULL, resource->gpu,
+ &handle, usage);
+ if (!status)
+ return -EINVAL;
+
+ assert(handle.modifier != DRM_FORMAT_MOD_INVALID);
+
+ if (handle.modifier == DRM_FORMAT_MOD_INVALID) {
+ close(handle.handle);
+ return -EINVAL;
+ }
+
+ resource->modifier = handle.modifier;
+ resource->stride = handle.stride;
+ fd = handle.handle;
+
+ err = drmPrimeFDToHandle(screen->fd, fd, &resource->handle);
+ if (err < 0)
+ err = -errno;
+
+ close(fd);
+
+ if (!has_modifiers) {
+ memset(&args, 0, sizeof(args));
+ args.handle = resource->handle;
+
+ switch (handle.modifier) {
+ case DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED:
+ args.mode = DRM_TEGRA_GEM_TILING_MODE_TILED;
+ break;
+
+ case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_ONE_GOB:
+ args.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
+ args.value = 0;
+ break;
+
+ case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_TWO_GOB:
+ args.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
+ args.value = 1;
+ break;
+
+ case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_FOUR_GOB:
+ args.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
+ args.value = 2;
+ break;
+
+ case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_EIGHT_GOB:
+ args.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
+ args.value = 3;
+ break;
+
+ case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_SIXTEEN_GOB:
+ args.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
+ args.value = 4;
+ break;
+
+ case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_THIRTYTWO_GOB:
+ args.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK;
+ args.value = 5;
+ break;
+
+ default:
+ debug_printf("unsupported modifier %" PRIx64 ", assuming linear\n",
+ handle.modifier);
+ /* fall-through */
+
+ case DRM_FORMAT_MOD_LINEAR:
+ args.mode = DRM_TEGRA_GEM_TILING_MODE_PITCH;
+ break;
+ }
+
+ err = drmIoctl(screen->fd, DRM_IOCTL_TEGRA_GEM_SET_TILING, &args);
+ if (err < 0) {
+ fprintf(stderr, "failed to set tiling parameters: %s\n",
+ strerror(errno));
+ err = -errno;
+ goto out;
+ }
+ }
+
+ return 0;
+
+out:
+ return err;
+}
+
+static struct pipe_resource *
+tegra_screen_resource_create(struct pipe_screen *pscreen,
+ const struct pipe_resource *template)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+ struct tegra_resource *resource;
+ int err;
+
+ resource = calloc(1, sizeof(*resource));
+ if (!resource)
+ return NULL;
+
+ resource->gpu = screen->gpu->resource_create(screen->gpu, template);
+ if (!resource->gpu)
+ goto free;
+
+ /* import scanout buffers for display */
+ if (template->bind & PIPE_BIND_SCANOUT) {
+ err = tegra_screen_import_resource(screen, resource, false);
+ if (err < 0)
+ goto destroy;
+ }
+
+ memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
+ pipe_reference_init(&resource->base.reference, 1);
+ resource->base.screen = &screen->base;
+
+ return &resource->base;
+
+destroy:
+ screen->gpu->resource_destroy(screen->gpu, resource->gpu);
+free:
+ free(resource);
+ return NULL;
+}
+
+/* XXX */
+static struct pipe_resource *
+tegra_screen_resource_create_front(struct pipe_screen *pscreen,
+ const struct pipe_resource *template,
+ const void *map_front_private)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+ struct pipe_resource *resource;
+
+ resource = screen->gpu->resource_create_front(screen->gpu, template,
+ map_front_private);
+ if (resource)
+ resource->screen = pscreen;
+
+ return resource;
+}
+
+static struct pipe_resource *
+tegra_screen_resource_from_handle(struct pipe_screen *pscreen,
+ const struct pipe_resource *template,
+ struct winsys_handle *handle,
+ unsigned usage)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+ struct tegra_resource *resource;
+
+ resource = calloc(1, sizeof(*resource));
+ if (!resource)
+ return NULL;
+
+ resource->gpu = screen->gpu->resource_from_handle(screen->gpu, template,
+ handle, usage);
+ if (!resource->gpu) {
+ free(resource);
+ return NULL;
+ }
+
+ memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
+ pipe_reference_init(&resource->base.reference, 1);
+ resource->base.screen = &screen->base;
+
+ return &resource->base;
+}
+
+/* XXX */
+static struct pipe_resource *
+tegra_screen_resource_from_user_memory(struct pipe_screen *pscreen,
+ const struct pipe_resource *template,
+ void *buffer)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+ struct pipe_resource *resource;
+
+ resource = screen->gpu->resource_from_user_memory(screen->gpu, template,
+ buffer);
+ if (resource)
+ resource->screen = pscreen;
+
+ return resource;
+}
+
+static boolean
+tegra_screen_resource_get_handle(struct pipe_screen *pscreen,
+ struct pipe_context *pcontext,
+ struct pipe_resource *presource,
+ struct winsys_handle *handle,
+ unsigned usage)
+{
+ struct tegra_resource *resource = to_tegra_resource(presource);
+ struct tegra_context *context = to_tegra_context(pcontext);
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+ boolean ret = TRUE;
+
+ /*
+ * Assume that KMS handles for scanout resources will only ever be used
+ * to pass buffers into Tegra DRM for display. In all other cases, return
+ * the Nouveau handle, assuming they will be used for sharing in DRI2/3.
+ */
+ if (handle->type == DRM_API_HANDLE_TYPE_KMS &&
+ presource->bind & PIPE_BIND_SCANOUT) {
+ handle->modifier = resource->modifier;
+ handle->handle = resource->handle;
+ handle->stride = resource->stride;
+ } else {
+ ret = screen->gpu->resource_get_handle(screen->gpu,
+ context ? context->gpu : NULL,
+ resource->gpu, handle, usage);
+ }
+
+ return ret;
+}
+
+static void
+tegra_screen_resource_destroy(struct pipe_screen *pscreen,
+ struct pipe_resource *presource)
+{
+ struct tegra_resource *resource = to_tegra_resource(presource);
+
+ pipe_resource_reference(&resource->gpu, NULL);
+ free(resource);
+}
+
+static void
+tegra_screen_flush_frontbuffer(struct pipe_screen *pscreen,
+ struct pipe_resource *resource,
+ unsigned int level,
+ unsigned int layer,
+ void *winsys_drawable_handle,
+ struct pipe_box *box)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ screen->gpu->flush_frontbuffer(screen->gpu, resource, level, layer,
+ winsys_drawable_handle, box);
+}
+
+static void
+tegra_screen_fence_reference(struct pipe_screen *pscreen,
+ struct pipe_fence_handle **ptr,
+ struct pipe_fence_handle *fence)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ screen->gpu->fence_reference(screen->gpu, ptr, fence);
+}
+
+static boolean
+tegra_screen_fence_finish(struct pipe_screen *pscreen,
+ struct pipe_context *pcontext,
+ struct pipe_fence_handle *fence,
+ uint64_t timeout)
+{
+ struct tegra_context *context = to_tegra_context(pcontext);
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ return screen->gpu->fence_finish(screen->gpu,
+ context ? context->gpu : NULL,
+ fence, timeout);
+}
+
+static int
+tegra_screen_fence_get_fd(struct pipe_screen *pscreen,
+ struct pipe_fence_handle *fence)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ return screen->gpu->fence_get_fd(screen->gpu, fence);
+}
+
+static int
+tegra_screen_get_driver_query_info(struct pipe_screen *pscreen,
+ unsigned int index,
+ struct pipe_driver_query_info *info)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ return screen->gpu->get_driver_query_info(screen->gpu, index, info);
+}
+
+static int
+tegra_screen_get_driver_query_group_info(struct pipe_screen *pscreen,
+ unsigned int index,
+ struct pipe_driver_query_group_info *info)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ return screen->gpu->get_driver_query_group_info(screen->gpu, index, info);
+}
+
+static void
+tegra_screen_query_memory_info(struct pipe_screen *pscreen,
+ struct pipe_memory_info *info)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ screen->gpu->query_memory_info(screen->gpu, info);
+}
+
+static const void *
+tegra_screen_get_compiler_options(struct pipe_screen *pscreen,
+ enum pipe_shader_ir ir,
+ unsigned int shader)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+ const void *options = NULL;
+
+ if (screen->gpu->get_compiler_options)
+ options = screen->gpu->get_compiler_options(screen->gpu, ir, shader);
+
+ return options;
+}
+
+static struct disk_cache *
+tegra_screen_get_disk_shader_cache(struct pipe_screen *pscreen)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ return screen->gpu->get_disk_shader_cache(screen->gpu);
+}
+
+static struct pipe_resource *
+tegra_screen_resource_create_with_modifiers(struct pipe_screen *pscreen,
+ const struct pipe_resource *template,
+ const uint64_t *modifiers,
+ int count)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+ struct tegra_resource *resource;
+ int err;
+
+ resource = calloc(1, sizeof(*resource));
+ if (!resource)
+ return NULL;
+
+ resource->gpu = screen->gpu->resource_create_with_modifiers(screen->gpu,
+ template,
+ modifiers,
+ count);
+ if (!resource->gpu)
+ goto free;
+
+ err = tegra_screen_import_resource(screen, resource, true);
+ if (err < 0)
+ goto destroy;
+
+ memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
+ pipe_reference_init(&resource->base.reference, 1);
+ resource->base.screen = &screen->base;
+
+ return &resource->base;
+
+destroy:
+ screen->gpu->resource_destroy(screen->gpu, resource->gpu);
+free:
+ free(resource);
+ return NULL;
+}
+
+static void tegra_screen_query_dmabuf_modifiers(struct pipe_screen *pscreen,
+ enum pipe_format format,
+ int max, uint64_t *modifiers,
+ unsigned int *external_only,
+ int *count)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ screen->gpu->query_dmabuf_modifiers(screen->gpu, format, max, modifiers,
+ external_only, count);
+}
+
+static struct pipe_memory_object *
+tegra_screen_memobj_create_from_handle(struct pipe_screen *pscreen,
+ struct winsys_handle *handle,
+ bool dedicated)
+{
+ struct tegra_screen *screen = to_tegra_screen(pscreen);
+
+ return screen->gpu->memobj_create_from_handle(screen->gpu, handle,
+ dedicated);
+}
+
+struct pipe_screen *
+tegra_screen_create(int fd)
+{
+ struct tegra_screen *screen;
+
+ screen = calloc(1, sizeof(*screen));
+ if (!screen)
+ return NULL;
+
+ screen->fd = fd;
+
+ screen->gpu_fd = tegra_open_render_node();
+ if (screen->gpu_fd < 0) {
+ if (errno != ENOENT)
+ fprintf(stderr, "failed to open GPU device: %s\n", strerror(errno));
+
+ free(screen);
+ return NULL;
+ }
+
+ screen->gpu = nouveau_drm_screen_create(screen->gpu_fd);
+ if (!screen->gpu) {
+ fprintf(stderr, "failed to create GPU screen\n");
+ close(screen->gpu_fd);
+ free(screen);
+ return NULL;
+ }
+
+ screen->base.destroy = tegra_screen_destroy;
+ screen->base.get_name = tegra_screen_get_name;
+ screen->base.get_vendor = tegra_screen_get_vendor;
+ screen->base.get_device_vendor = tegra_screen_get_device_vendor;
+ screen->base.get_param = tegra_screen_get_param;
+ screen->base.get_paramf = tegra_screen_get_paramf;
+ screen->base.get_shader_param = tegra_screen_get_shader_param;
+ screen->base.get_video_param = tegra_screen_get_video_param;
+ screen->base.get_compute_param = tegra_screen_get_compute_param;
+ screen->base.get_timestamp = tegra_screen_get_timestamp;
+ screen->base.context_create = tegra_screen_context_create;
+ screen->base.is_format_supported = tegra_screen_is_format_supported;
+ screen->base.is_video_format_supported = tegra_screen_is_video_format_supported;
+
+ /* allow fallback implementation if GPU driver doesn't implement it */
+ if (screen->gpu->can_create_resource)
+ screen->base.can_create_resource = tegra_screen_can_create_resource;
+
+ screen->base.resource_create = tegra_screen_resource_create;
+ screen->base.resource_create_front = tegra_screen_resource_create_front;
+ screen->base.resource_from_handle = tegra_screen_resource_from_handle;
+ screen->base.resource_from_user_memory = tegra_screen_resource_from_user_memory;
+ screen->base.resource_get_handle = tegra_screen_resource_get_handle;
+ screen->base.resource_destroy = tegra_screen_resource_destroy;
+
+ screen->base.flush_frontbuffer = tegra_screen_flush_frontbuffer;
+ screen->base.fence_reference = tegra_screen_fence_reference;
+ screen->base.fence_finish = tegra_screen_fence_finish;
+ screen->base.fence_get_fd = tegra_screen_fence_get_fd;
+
+ screen->base.get_driver_query_info = tegra_screen_get_driver_query_info;
+ screen->base.get_driver_query_group_info = tegra_screen_get_driver_query_group_info;
+ screen->base.query_memory_info = tegra_screen_query_memory_info;
+
+ screen->base.get_compiler_options = tegra_screen_get_compiler_options;
+ screen->base.get_disk_shader_cache = tegra_screen_get_disk_shader_cache;
+
+ screen->base.resource_create_with_modifiers = tegra_screen_resource_create_with_modifiers;
+ screen->base.query_dmabuf_modifiers = tegra_screen_query_dmabuf_modifiers;
+ screen->base.memobj_create_from_handle = tegra_screen_memobj_create_from_handle;
+
+ return &screen->base;
+}
diff --git a/src/gallium/drivers/tegra/tegra_screen.h b/src/gallium/drivers/tegra/tegra_screen.h
new file mode 100644
index 00000000000..558d22f2f99
--- /dev/null
+++ b/src/gallium/drivers/tegra/tegra_screen.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2014-2018 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef TEGRA_SCREEN_H
+#define TEGRA_SCREEN_H
+
+#include "pipe/p_screen.h"
+
+struct tegra_screen {
+ struct pipe_screen base;
+ int fd;
+
+ struct pipe_screen *gpu;
+ int gpu_fd;
+};
+
+static inline struct tegra_screen *
+to_tegra_screen(struct pipe_screen *pscreen)
+{
+ return (struct tegra_screen *)pscreen;
+}
+
+struct pipe_screen *tegra_screen_create(int fd);
+
+#endif /* TEGRA_SCREEN_H */
diff --git a/src/gallium/meson.build b/src/gallium/meson.build
index 108234ad322..c9bfc0b7298 100644
--- a/src/gallium/meson.build
+++ b/src/gallium/meson.build
@@ -119,6 +119,12 @@ if with_gallium_imx
else
driver_imx = declare_dependency()
endif
+if with_gallium_tegra
+ subdir('winsys/tegra/drm')
+ subdir('drivers/tegra')
+else
+ driver_tegra = declare_dependency()
+endif
if with_gallium_i915
subdir('winsys/i915/drm')
subdir('drivers/i915')
diff --git a/src/gallium/targets/dri/Makefile.am b/src/gallium/targets/dri/Makefile.am
index 1d05d91a610..73bb71db0c4 100644
--- a/src/gallium/targets/dri/Makefile.am
+++ b/src/gallium/targets/dri/Makefile.am
@@ -82,6 +82,8 @@ include $(top_srcdir)/src/gallium/drivers/svga/Automake.inc
include $(top_srcdir)/src/gallium/drivers/freedreno/Automake.inc
+include $(top_srcdir)/src/gallium/drivers/tegra/Automake.inc
+
include $(top_srcdir)/src/gallium/drivers/vc4/Automake.inc
include $(top_srcdir)/src/gallium/drivers/vc5/Automake.inc
include $(top_srcdir)/src/gallium/drivers/pl111/Automake.inc
diff --git a/src/gallium/targets/dri/meson.build b/src/gallium/targets/dri/meson.build
index a4326227f0f..34402975386 100644
--- a/src/gallium/targets/dri/meson.build
+++ b/src/gallium/targets/dri/meson.build
@@ -62,7 +62,8 @@ libgallium_dri = shared_library(
dep_selinux, dep_expat, dep_libdrm, dep_llvm, dep_thread,
driver_swrast, driver_r300, driver_r600, driver_radeonsi, driver_nouveau,
driver_pl111, driver_vc4, driver_vc5, driver_freedreno, driver_etnaviv,
- driver_imx, driver_i915, driver_svga, driver_virgl, driver_swr,
+ driver_imx, driver_tegra, driver_i915, driver_svga, driver_virgl,
+ driver_swr,
],
)
@@ -76,6 +77,7 @@ foreach d : [[with_gallium_pl111, 'pl111_dri.so'],
[with_gallium_vc5, 'vc5_dri.so'],
[with_gallium_etnaviv, 'etnaviv_dri.so'],
[with_gallium_imx, 'imx-drm_dri.so'],
+ [with_gallium_tegra, 'tegra_dri.so'],
[with_gallium_i915, 'i915_dri.so'],
[with_gallium_r300, 'r300_dri.so'],
[with_gallium_r600, 'r600_dri.so'],
diff --git a/src/gallium/targets/dri/target.c b/src/gallium/targets/dri/target.c
index 5ee1761fdba..e09e7768711 100644
--- a/src/gallium/targets/dri/target.c
+++ b/src/gallium/targets/dri/target.c
@@ -86,3 +86,7 @@ DEFINE_LOADER_DRM_ENTRYPOINT(vc5)
DEFINE_LOADER_DRM_ENTRYPOINT(imx_drm)
DEFINE_LOADER_DRM_ENTRYPOINT(etnaviv)
#endif
+
+#if defined(GALLIUM_TEGRA)
+DEFINE_LOADER_DRM_ENTRYPOINT(tegra);
+#endif
diff --git a/src/gallium/targets/vdpau/Makefile.am b/src/gallium/targets/vdpau/Makefile.am
index 2742c7acd44..cd05a024451 100644
--- a/src/gallium/targets/vdpau/Makefile.am
+++ b/src/gallium/targets/vdpau/Makefile.am
@@ -57,6 +57,8 @@ include $(top_srcdir)/src/gallium/drivers/r300/Automake.inc
include $(top_srcdir)/src/gallium/drivers/r600/Automake.inc
include $(top_srcdir)/src/gallium/drivers/radeonsi/Automake.inc
+include $(top_srcdir)/src/gallium/drivers/tegra/Automake.inc
+
if HAVE_GALLIUM_STATIC_TARGETS
libvdpau_gallium_la_SOURCES += target.c
diff --git a/src/gallium/winsys/tegra/drm/Makefile.am b/src/gallium/winsys/tegra/drm/Makefile.am
new file mode 100644
index 00000000000..9a8169889cf
--- /dev/null
+++ b/src/gallium/winsys/tegra/drm/Makefile.am
@@ -0,0 +1,13 @@
+include Makefile.sources
+include $(top_srcdir)/src/gallium/Automake.inc
+
+AM_CFLAGS = \
+ -I$(top_srcdir)/src/gallium/drivers \
+ $(GALLIUM_WINSYS_CFLAGS)
+
+noinst_LTLIBRARIES = libtegradrm.la
+
+libtegradrm_la_SOURCES = $(C_SOURCES)
+
+EXTRA_DIST = \
+ meson.build
diff --git a/src/gallium/winsys/tegra/drm/Makefile.sources b/src/gallium/winsys/tegra/drm/Makefile.sources
new file mode 100644
index 00000000000..fe0d5c42e72
--- /dev/null
+++ b/src/gallium/winsys/tegra/drm/Makefile.sources
@@ -0,0 +1,2 @@
+C_SOURCES := \
+ tegra_drm_winsys.c
diff --git a/src/gallium/winsys/tegra/drm/meson.build b/src/gallium/winsys/tegra/drm/meson.build
new file mode 100644
index 00000000000..46a6ab782a5
--- /dev/null
+++ b/src/gallium/winsys/tegra/drm/meson.build
@@ -0,0 +1,33 @@
+# Copyright © 2018 NVIDIA CORPORATION
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+libtegradrm = static_library(
+ 'tegradrm',
+ 'tegra_drm_winsys.c',
+ include_directories : [
+ inc_include, inc_src, inc_gallium, inc_gallium_aux, inc_gallium_drivers,
+ inc_gallium_winsys
+ ],
+)
+
+driver_tegra = declare_dependency(
+ compile_args : '-DGALLIUM_TEGRA',
+ link_with : libtegradrm,
+)
diff --git a/src/gallium/winsys/tegra/drm/tegra_drm_public.h b/src/gallium/winsys/tegra/drm/tegra_drm_public.h
new file mode 100644
index 00000000000..8105180003f
--- /dev/null
+++ b/src/gallium/winsys/tegra/drm/tegra_drm_public.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright © 2014-2018 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __TEGRA_DRM_PUBLIC_H__
+#define __TEGRA_DRM_PUBLIC_H__
+
+struct pipe_screen;
+
+struct pipe_screen *tegra_drm_screen_create(int fd);
+
+#endif /* __TEGRA_DRM_PUBLIC_H__ */
diff --git a/src/gallium/winsys/tegra/drm/tegra_drm_winsys.c b/src/gallium/winsys/tegra/drm/tegra_drm_winsys.c
new file mode 100644
index 00000000000..e2a8efb0f63
--- /dev/null
+++ b/src/gallium/winsys/tegra/drm/tegra_drm_winsys.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2014-2018 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <fcntl.h>
+
+#include "util/u_debug.h"
+
+#include "tegra/tegra_screen.h"
+
+struct pipe_screen *tegra_drm_screen_create(int fd);
+
+struct pipe_screen *tegra_drm_screen_create(int fd)
+{
+ struct pipe_screen *screen;
+
+ /*
+ * NOTE: There are reportedly issues with reusing the file descriptor
+ * as-is related to Xinerama. Duplicate it to side-step any issues.
+ */
+ fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
+ if (fd < 0)
+ return NULL;
+
+ screen = tegra_screen_create(fd);
+ if (!screen)
+ close(fd);
+
+ return screen;
+}