Tegra K1 and later use a GPU that can be driven by the Nouveau driver. But the GPU is a pure render node and has no display engine, hence the scanout needs to happen on the Tegra display hardware. The GPU and the display engine each have a separate DRM device node exposed by the kernel. To make the setup appear as a single device, this driver instantiates a Nouveau screen with each instance of a Tegra screen and forwards GPU requests to the Nouveau screen. For purposes of scanout it will import buffers created on the GPU into the display driver. Handles that userspace requests are those of the display driver so that they can be used to create framebuffers. This has been tested with some GBM test programs, as well as kmscube and weston. All of those run without modifications, but I'm sure there is a lot that can be improved. TODO: - use Nouveau headers to get at the prototype for creating a screen - implement enough support to seamlessly integrate with X - refactor some of the code to be reusable by other drivers Signed-off-by: Thierry Reding <treding at nvidia.com> --- configure.ac | 12 +- src/gallium/Makefile.am | 5 + .../auxiliary/target-helpers/inline_drm_helper.h | 30 + src/gallium/drivers/tegra/Automake.inc | 11 + src/gallium/drivers/tegra/Makefile.am | 17 + src/gallium/drivers/tegra/Makefile.sources | 4 + src/gallium/drivers/tegra/tegra_context.c | 699 +++++++++++++++++++++ src/gallium/drivers/tegra/tegra_context.h | 80 +++ src/gallium/drivers/tegra/tegra_resource.c | 219 +++++++ src/gallium/drivers/tegra/tegra_resource.h | 98 +++ src/gallium/drivers/tegra/tegra_screen.c | 311 +++++++++ src/gallium/drivers/tegra/tegra_screen.h | 45 ++ src/gallium/targets/dri/Makefile.am | 2 + src/gallium/winsys/tegra/drm/Makefile.am | 11 + src/gallium/winsys/tegra/drm/Makefile.sources | 2 + src/gallium/winsys/tegra/drm/tegra_drm_public.h | 31 + src/gallium/winsys/tegra/drm/tegra_drm_winsys.c | 33 + 17 files changed, 1609 insertions(+), 1 deletion(-) create mode 100644 src/gallium/drivers/tegra/Automake.inc create mode 100644 src/gallium/drivers/tegra/Makefile.am create mode 100644 src/gallium/drivers/tegra/Makefile.sources create mode 100644 src/gallium/drivers/tegra/tegra_context.c create mode 100644 src/gallium/drivers/tegra/tegra_context.h create mode 100644 src/gallium/drivers/tegra/tegra_resource.c create mode 100644 src/gallium/drivers/tegra/tegra_resource.h create mode 100644 src/gallium/drivers/tegra/tegra_screen.c create mode 100644 src/gallium/drivers/tegra/tegra_screen.h create mode 100644 src/gallium/winsys/tegra/drm/Makefile.am create mode 100644 src/gallium/winsys/tegra/drm/Makefile.sources create mode 100644 src/gallium/winsys/tegra/drm/tegra_drm_public.h create mode 100644 src/gallium/winsys/tegra/drm/tegra_drm_winsys.c diff --git a/configure.ac b/configure.ac index 1d9d015481ec..ae50bec95339 100644 --- a/configure.ac +++ b/configure.ac @@ -33,6 +33,7 @@ LIBDRM_INTEL_REQUIRED=2.4.52 LIBDRM_NVVIEUX_REQUIRED=2.4.33 LIBDRM_NOUVEAU_REQUIRED="2.4.33 libdrm >= 2.4.41" LIBDRM_FREEDRENO_REQUIRED=2.4.57 +LIBDRM_TEGRA_REQUIRED=2.4.58 DRI2PROTO_REQUIRED=2.6 DRI3PROTO_REQUIRED=1.0 PRESENTPROTO_REQUIRED=1.0 @@ -733,7 +734,7 @@ GALLIUM_DRIVERS_DEFAULT="r300,r600,svga,swrast" AC_ARG_WITH([gallium-drivers], [AS_HELP_STRING([--with-gallium-drivers@<:@=DIRS...@:>@], [comma delimited Gallium drivers list, e.g. - "i915,ilo,nouveau,r300,r600,radeonsi,freedreno,svga,swrast,vc4" + "i915,ilo,nouveau,r300,r600,radeonsi,freedreno,tegra,svga,swrast,vc4" @<:@default=r300,r600,svga,swrast@:>@])], [with_gallium_drivers="$withval"], [with_gallium_drivers="$GALLIUM_DRIVERS_DEFAULT"]) @@ -1937,6 +1938,12 @@ if test -n "$with_gallium_drivers"; then gallium_require_drm "freedreno" gallium_require_drm_loader ;; + xtegra) + HAVE_GALLIUM_TEGRA=yes + PKG_CHECK_MODULES([TEGRA], [libdrm_tegra >= $LIBDRM_TEGRA_REQUIRED]) + gallium_require_drm "tegra" + gallium_require_drm_loader + ;; xswrast) HAVE_GALLIUM_SOFTPIPE=yes if test "x$MESA_LLVM" = x1; then @@ -2018,6 +2025,7 @@ AM_CONDITIONAL(HAVE_GALLIUM_RADEON_COMMON, test "x$HAVE_GALLIUM_R600" = xyes -o "x$HAVE_GALLIUM_RADEONSI" = xyes) AM_CONDITIONAL(HAVE_GALLIUM_NOUVEAU, test "x$HAVE_GALLIUM_NOUVEAU" = xyes) AM_CONDITIONAL(HAVE_GALLIUM_FREEDRENO, test "x$HAVE_GALLIUM_FREEDRENO" = xyes) +AM_CONDITIONAL(HAVE_GALLIUM_TEGRA, test "x$HAVE_GALLIUM_TEGRA" = xyes) AM_CONDITIONAL(HAVE_GALLIUM_SOFTPIPE, test "x$HAVE_GALLIUM_SOFTPIPE" = xyes) AM_CONDITIONAL(HAVE_GALLIUM_LLVMPIPE, test "x$HAVE_GALLIUM_LLVMPIPE" = xyes) AM_CONDITIONAL(HAVE_GALLIUM_VC4, test "x$HAVE_GALLIUM_VC4" = xyes) @@ -2159,6 +2167,7 @@ AC_CONFIG_FILES([Makefile src/gallium/drivers/rbug/Makefile src/gallium/drivers/softpipe/Makefile src/gallium/drivers/svga/Makefile + src/gallium/drivers/tegra/Makefile src/gallium/drivers/trace/Makefile src/gallium/drivers/vc4/Makefile src/gallium/drivers/vc4/kernel/Makefile @@ -2204,6 +2213,7 @@ AC_CONFIG_FILES([Makefile src/gallium/winsys/sw/wayland/Makefile src/gallium/winsys/sw/wrapper/Makefile src/gallium/winsys/sw/xlib/Makefile + src/gallium/winsys/tegra/drm/Makefile src/gallium/winsys/vc4/drm/Makefile src/gbm/Makefile src/gbm/main/gbm.pc diff --git a/src/gallium/Makefile.am b/src/gallium/Makefile.am index 81840b2081b6..1e76681a7329 100644 --- a/src/gallium/Makefile.am +++ b/src/gallium/Makefile.am @@ -77,6 +77,11 @@ SUBDIRS += drivers/llvmpipe endif endif +## tegra +if HAVE_GALLIUM_TEGRA +SUBDIRS += drivers/tegra winsys/tegra/drm +endif + ## vc4/rpi if HAVE_GALLIUM_VC4 SUBDIRS += drivers/vc4 winsys/vc4/drm diff --git a/src/gallium/auxiliary/target-helpers/inline_drm_helper.h b/src/gallium/auxiliary/target-helpers/inline_drm_helper.h index 81649d42582c..5808765a503e 100644 --- a/src/gallium/auxiliary/target-helpers/inline_drm_helper.h +++ b/src/gallium/auxiliary/target-helpers/inline_drm_helper.h @@ -58,6 +58,10 @@ #include "vc4/drm/vc4_drm_public.h" #endif +#if GALLIUM_TEGRA +#include "tegra/drm/tegra_drm_public.h" +#endif + static char* driver_name = NULL; /* XXX: We need to teardown the winsys if *screen_create() fails. */ @@ -332,6 +336,27 @@ pipe_vc4_create_screen(int fd) } #endif +#if defined(GALLIUM_TEGRA) +#if defined(DRI_TARGET) +const __DRIextension **__driDriverGetExtensions_tegra(void); + +PUBLIC const __DRIextension **__driDriverGetExtensions_tegra(void) +{ + globalDriverAPI = &galliumdrm_driver_api; + return galliumdrm_driver_extensions; +} +#endif + +static struct pipe_screen *pipe_tegra_create_screen(int fd) +{ + struct pipe_screen *screen; + + screen = tegra_drm_screen_create(fd); + + return screen ? debug_screen_wrap(screen) : NULL; +} +#endif + inline struct pipe_screen * dd_create_screen(int fd) { @@ -389,6 +414,11 @@ dd_create_screen(int fd) else #endif #endif +#if defined(GALLIUM_TEGRA) + if (strcmp(driver_name, "tegra") == 0) + return pipe_tegra_create_screen(fd); + else +#endif return NULL; } diff --git a/src/gallium/drivers/tegra/Automake.inc b/src/gallium/drivers/tegra/Automake.inc new file mode 100644 index 000000000000..f65281916245 --- /dev/null +++ b/src/gallium/drivers/tegra/Automake.inc @@ -0,0 +1,11 @@ +if HAVE_GALLIUM_TEGRA + +TARGET_DRIVERS += tegra +TARGET_CPPFLAGS += -DGALLIUM_TEGRA +TARGET_LIB_DEPS += \ + $(top_builddir)/src/gallium/winsys/tegra/drm/libtegradrm.la \ + $(top_builddir)/src/gallium/drivers/tegra/libtegra.la \ + $(LIBDRM_LIBS) \ + $(TEGRA_LIBS) + +endif diff --git a/src/gallium/drivers/tegra/Makefile.am b/src/gallium/drivers/tegra/Makefile.am new file mode 100644 index 000000000000..eb03df9bb2ed --- /dev/null +++ b/src/gallium/drivers/tegra/Makefile.am @@ -0,0 +1,17 @@ +AUTOMAKE_OPTIONS = subdir-objects + +include Makefile.sources +include $(top_srcdir)/src/gallium/Automake.inc + +AM_CFLAGS = \ + $(GALLIUM_DRIVER_CFLAGS) \ + $(LIBUDEV_CFLAGS) \ + $(TEGRA_CFLAGS) + +noinst_LTLIBRARIES = libtegra.la + +libtegra_la_SOURCES = \ + $(C_SOURCES) + +libtegra_la_LIBADD = \ + $(LIBUDEV_LIBS) diff --git a/src/gallium/drivers/tegra/Makefile.sources b/src/gallium/drivers/tegra/Makefile.sources new file mode 100644 index 000000000000..978dd14667f5 --- /dev/null +++ b/src/gallium/drivers/tegra/Makefile.sources @@ -0,0 +1,4 @@ +C_SOURCES := \ + tegra_context.c \ + tegra_resource.c \ + tegra_screen.c diff --git a/src/gallium/drivers/tegra/tegra_context.c b/src/gallium/drivers/tegra/tegra_context.c new file mode 100644 index 000000000000..a7a7690ec7bb --- /dev/null +++ b/src/gallium/drivers/tegra/tegra_context.c @@ -0,0 +1,699 @@ +/* + * Copyright © 2014 NVIDIA Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <stdlib.h> + +#include "util/u_debug.h" +#include "util/u_inlines.h" + +#include "tegra/tegra_context.h" +#include "tegra/tegra_resource.h" +#include "tegra/tegra_screen.h" + +static void +tegra_destroy(struct pipe_context *pcontext) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->destroy(context->gpu); + free(context); +} + +static void +tegra_draw_vbo(struct pipe_context *pcontext, + const struct pipe_draw_info *pinfo) +{ + struct tegra_context *context = to_tegra_context(pcontext); + struct pipe_draw_info info; + + if (pinfo && pinfo->indirect) { + memcpy(&info, pinfo, sizeof(info)); + info.indirect = tegra_resource_unwrap(info.indirect); + pinfo = &info; + } + + context->gpu->draw_vbo(context->gpu, pinfo); +} + +static void * +tegra_create_blend_state(struct pipe_context *pcontext, + const struct pipe_blend_state *cso) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + return context->gpu->create_blend_state(context->gpu, cso); +} + +static void +tegra_bind_blend_state(struct pipe_context *pcontext, + void *so) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->bind_blend_state(context->gpu, so); +} + +static void +tegra_delete_blend_state(struct pipe_context *pcontext, + void *so) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->delete_blend_state(context->gpu, so); +} + +static void * +tegra_create_sampler_state(struct pipe_context *pcontext, + const struct pipe_sampler_state *cso) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + return context->gpu->create_sampler_state(context->gpu, cso); +} + +static void +tegra_bind_sampler_states(struct pipe_context *pcontext, + unsigned shader, + unsigned start_slot, + unsigned num_samplers, + void **samplers) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->bind_sampler_states(context->gpu, shader, start_slot, + num_samplers, samplers); +} + +static void +tegra_delete_sampler_state(struct pipe_context *pcontext, + void *so) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->delete_sampler_state(context->gpu, so); +} + +static void * +tegra_create_rasterizer_state(struct pipe_context *pcontext, + const struct pipe_rasterizer_state *cso) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + return context->gpu->create_rasterizer_state(context->gpu, cso); +} + +static void +tegra_bind_rasterizer_state(struct pipe_context *pcontext, + void *so) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->bind_rasterizer_state(context->gpu, so); +} + +static void +tegra_delete_rasterizer_state(struct pipe_context *pcontext, + void *so) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->delete_rasterizer_state(context->gpu, so); +} + +static void * +tegra_create_depth_stencil_alpha_state(struct pipe_context *pcontext, + const struct pipe_depth_stencil_alpha_state *cso) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + return context->gpu->create_depth_stencil_alpha_state(context->gpu, + cso); +} + +static void +tegra_bind_depth_stencil_alpha_state(struct pipe_context *pcontext, + void *so) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->bind_depth_stencil_alpha_state(context->gpu, so); +} + +static void +tegra_delete_depth_stencil_alpha_state(struct pipe_context *pcontext, + void *so) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->delete_depth_stencil_alpha_state(context->gpu, so); +} + +static void * +tegra_create_fs_state(struct pipe_context *pcontext, + const struct pipe_shader_state *cso) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + return context->gpu->create_fs_state(context->gpu, cso); +} + +static void +tegra_bind_fs_state(struct pipe_context *pcontext, + void *so) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->bind_fs_state(context->gpu, so); +} + +static void +tegra_delete_fs_state(struct pipe_context *pcontext, + void *so) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->delete_fs_state(context->gpu, so); +} + +static void * +tegra_create_vs_state(struct pipe_context *pcontext, + const struct pipe_shader_state *cso) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + return context->gpu->create_vs_state(context->gpu, cso); +} + +static void +tegra_bind_vs_state(struct pipe_context *pcontext, + void *so) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->bind_vs_state(context->gpu, so); +} + +static void +tegra_delete_vs_state(struct pipe_context *pcontext, + void *so) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->delete_vs_state(context->gpu, so); +} + +static void * +tegra_create_gs_state(struct pipe_context *pcontext, + const struct pipe_shader_state *cso) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + return context->gpu->create_gs_state(context->gpu, cso); +} + +static void +tegra_bind_gs_state(struct pipe_context *pcontext, + void *so) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->bind_gs_state(context->gpu, so); +} + +static void +tegra_delete_gs_state(struct pipe_context *pcontext, + void *so) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->delete_gs_state(context->gpu, so); +} + +static void * +tegra_create_vertex_elements_state(struct pipe_context *pcontext, + unsigned num_elements, + const struct pipe_vertex_element *elements) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + return context->gpu->create_vertex_elements_state(context->gpu, + num_elements, + elements); +} + +static void +tegra_bind_vertex_elements_state(struct pipe_context *pcontext, + void *so) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->bind_vertex_elements_state(context->gpu, so); +} + +static void +tegra_delete_vertex_elements_state(struct pipe_context *pcontext, + void *so) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->delete_vertex_elements_state(context->gpu, so); +} + +static void +tegra_set_constant_buffer(struct pipe_context *pcontext, + uint shader, + uint index, + struct pipe_constant_buffer *buf) +{ + struct tegra_context *context = to_tegra_context(pcontext); + struct pipe_constant_buffer buffer; + + if (buf && buf->buffer) { + memcpy(&buffer, buf, sizeof(buffer)); + buffer.buffer = tegra_resource_unwrap(buffer.buffer); + buf = &buffer; + } + + context->gpu->set_constant_buffer(context->gpu, shader, index, buf); +} + +static void +tegra_set_framebuffer_state(struct pipe_context *pcontext, + const struct pipe_framebuffer_state *fb) +{ + struct tegra_context *context = to_tegra_context(pcontext); + struct pipe_framebuffer_state state; + unsigned i; + + if (fb) { + memcpy(&state, fb, sizeof(state)); + + for (i = 0; i < fb->nr_cbufs; i++) + state.cbufs[i] = tegra_surface_unwrap(fb->cbufs[i]); + + while (i < PIPE_MAX_COLOR_BUFS) + state.cbufs[i++] = NULL; + + state.zsbuf = tegra_surface_unwrap(fb->zsbuf); + + fb = &state; + } + + context->gpu->set_framebuffer_state(context->gpu, fb); +} + +static void +tegra_set_polygon_stipple(struct pipe_context *pcontext, + const struct pipe_poly_stipple *stipple) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->set_polygon_stipple(context->gpu, stipple); +} + +static void +tegra_set_scissor_states(struct pipe_context *pcontext, + unsigned start_slot, + unsigned num_scissors, + const struct pipe_scissor_state *scissors) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->set_scissor_states(context->gpu, start_slot, + num_scissors, scissors); +} + +static void +tegra_set_viewport_states(struct pipe_context *pcontext, + unsigned start_slot, + unsigned num_viewports, + const struct pipe_viewport_state *viewports) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->set_viewport_states(context->gpu, start_slot, + num_viewports, viewports); +} + +static void +tegra_set_sampler_views(struct pipe_context *pcontext, + unsigned shader, + unsigned start_slot, + unsigned num_views, + struct pipe_sampler_view **pviews) +{ + struct pipe_sampler_view *views[PIPE_MAX_SHADER_SAMPLER_VIEWS]; + struct tegra_context *context = to_tegra_context(pcontext); + unsigned i; + + for (i = 0; i < num_views; i++) + views[i] = tegra_sampler_view_unwrap(pviews[i]); + + context->gpu->set_sampler_views(context->gpu, shader, start_slot, + num_views, views); +} + +static void +tegra_set_shader_resources(struct pipe_context *pcontext, + unsigned start, + unsigned count, + struct pipe_surface **resources) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->set_shader_resources(context->gpu, start, count, + resources); +} + +static void +tegra_set_vertex_buffers(struct pipe_context *pcontext, + unsigned start_slot, + unsigned num_buffers, + const struct pipe_vertex_buffer *buffers) +{ + struct tegra_context *context = to_tegra_context(pcontext); + struct pipe_vertex_buffer buf[PIPE_MAX_SHADER_INPUTS]; + unsigned i; + + if (num_buffers && buffers) { + memcpy(buf, buffers, num_buffers * sizeof(struct pipe_vertex_buffer)); + + for (i = 0; i < num_buffers; i++) + buf[i].buffer = tegra_resource_unwrap(buf[i].buffer); + + buffers = buf; + } + + context->gpu->set_vertex_buffers(context->gpu, start_slot, + num_buffers, buffers); +} + +static void +tegra_set_index_buffer(struct pipe_context *pcontext, + const struct pipe_index_buffer *buffer) +{ + struct tegra_context *context = to_tegra_context(pcontext); + struct pipe_index_buffer buf; + + if (buffer) { + memcpy(&buf, buffer, sizeof(buf)); + buf.buffer = tegra_resource_unwrap(buf.buffer); + buffer = &buf; + } + + context->gpu->set_index_buffer(context->gpu, buffer); +} + +static struct pipe_stream_output_target * +tegra_create_stream_output_target(struct pipe_context *pcontext, + struct pipe_resource *presource, + unsigned buffer_offset, + unsigned buffer_size) +{ + struct tegra_resource *resource = to_tegra_resource(presource); + struct tegra_context *context = to_tegra_context(pcontext); + + return context->gpu->create_stream_output_target(context->gpu, + resource->gpu, + buffer_offset, + buffer_size); +} + +static void +tegra_stream_output_target_destroy(struct pipe_context *pcontext, + struct pipe_stream_output_target *target) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->stream_output_target_destroy(context->gpu, target); +} + +static void +tegra_set_stream_output_targets(struct pipe_context *pcontext, + unsigned num_targets, + struct pipe_stream_output_target **targets, + const unsigned *offsets) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->set_stream_output_targets(context->gpu, num_targets, + targets, offsets); +} + +static void +tegra_blit(struct pipe_context *pcontext, + const struct pipe_blit_info *pinfo) +{ + struct tegra_context *context = to_tegra_context(pcontext); + struct pipe_blit_info info; + + if (pinfo) { + memcpy(&info, pinfo, sizeof(info)); + info.dst.resource = tegra_resource_unwrap(info.dst.resource); + info.src.resource = tegra_resource_unwrap(info.src.resource); + pinfo = &info; + } + + context->gpu->blit(context->gpu, pinfo); +} + +static void +tegra_clear(struct pipe_context *pcontext, + unsigned buffers, + const union pipe_color_union *color, + double depth, + unsigned stencil) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->clear(context->gpu, buffers, color, depth, stencil); +} + +static void +tegra_flush(struct pipe_context *pcontext, + struct pipe_fence_handle **fence, + unsigned flags) +{ + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->flush(context->gpu, fence, flags); +} + +static struct pipe_sampler_view * +tegra_create_sampler_view(struct pipe_context *pcontext, + struct pipe_resource *ptexture, + const struct pipe_sampler_view *template) +{ + struct tegra_resource *texture = to_tegra_resource(ptexture); + struct tegra_context *context = to_tegra_context(pcontext); + struct tegra_sampler_view *view; + + view = calloc(1, sizeof(*view)); + if (!view) + return NULL; + + view->gpu = context->gpu->create_sampler_view(context->gpu, + texture->gpu, + template); + memcpy(&view->base, view->gpu, sizeof(*view->gpu)); + /* overwrite to prevent reference from being released */ + view->base.texture = NULL; + + pipe_reference_init(&view->base.reference, 1); + pipe_resource_reference(&view->base.texture, ptexture); + view->base.context = pcontext; + + return &view->base; +} + +static void +tegra_sampler_view_destroy(struct pipe_context *pcontext, + struct pipe_sampler_view *pview) +{ + struct tegra_sampler_view *view = to_tegra_sampler_view(pview); + + pipe_resource_reference(&view->base.texture, NULL); + pipe_sampler_view_reference(&view->gpu, NULL); + free(view); +} + +static void +tegra_flush_resource(struct pipe_context *pcontext, + struct pipe_resource *presource) +{ + struct tegra_resource *resource = to_tegra_resource(presource); + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->flush_resource(context->gpu, resource->gpu); +} + +static void * +tegra_transfer_map(struct pipe_context *pcontext, + struct pipe_resource *presource, + unsigned level, + unsigned usage, + const struct pipe_box *box, + struct pipe_transfer **ptransfer) +{ + struct tegra_resource *resource = to_tegra_resource(presource); + struct tegra_context *context = to_tegra_context(pcontext); + struct tegra_transfer *transfer; + + transfer = calloc(1, sizeof(*transfer)); + if (!transfer) + return NULL; + + transfer->map = context->gpu->transfer_map(context->gpu, + resource->gpu, + level, + usage, + box, + &transfer->gpu); + memcpy(&transfer->base, transfer->gpu, sizeof(*transfer->gpu)); + transfer->base.resource = NULL; + pipe_resource_reference(&transfer->base.resource, presource); + + *ptransfer = &transfer->base; + + return transfer->map; +} + +static void +tegra_transfer_unmap(struct pipe_context *pcontext, + struct pipe_transfer *ptransfer) +{ + struct tegra_transfer *transfer = to_tegra_transfer(ptransfer); + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->transfer_unmap(context->gpu, transfer->gpu); + pipe_resource_reference(&transfer->base.resource, NULL); + free(transfer); +} + +static void +tegra_transfer_inline_write(struct pipe_context *pcontext, + struct pipe_resource *presource, + unsigned level, + unsigned usage, + const struct pipe_box *box, + const void *data, + unsigned stride, + unsigned layer_stride) +{ + struct tegra_resource *resource = to_tegra_resource(presource); + struct tegra_context *context = to_tegra_context(pcontext); + + context->gpu->transfer_inline_write(context->gpu, resource->gpu, + level, usage, box, data, stride, + layer_stride); +} + +struct pipe_context * +tegra_context_create(struct pipe_screen *pscreen, void *priv) +{ + struct tegra_screen *screen = to_tegra_screen(pscreen); + struct tegra_context *context; + + context = calloc(1, sizeof(*context)); + if (!context) + return NULL; + + context->gpu = screen->gpu->context_create(screen->gpu, priv); + if (!context->gpu) { + debug_error("failed to create GPU context\n"); + free(context); + return NULL; + } + + context->base.screen = &screen->base; + context->base.priv = priv; + + context->base.destroy = tegra_destroy; + + context->base.draw_vbo = tegra_draw_vbo; + + context->base.create_blend_state = tegra_create_blend_state; + context->base.bind_blend_state = tegra_bind_blend_state; + context->base.delete_blend_state = tegra_delete_blend_state; + + context->base.create_sampler_state = tegra_create_sampler_state; + context->base.bind_sampler_states = tegra_bind_sampler_states; + context->base.delete_sampler_state = tegra_delete_sampler_state; + + context->base.create_rasterizer_state = tegra_create_rasterizer_state; + context->base.bind_rasterizer_state = tegra_bind_rasterizer_state; + context->base.delete_rasterizer_state = tegra_delete_rasterizer_state; + + context->base.create_depth_stencil_alpha_state = tegra_create_depth_stencil_alpha_state; + context->base.bind_depth_stencil_alpha_state = tegra_bind_depth_stencil_alpha_state; + context->base.delete_depth_stencil_alpha_state = tegra_delete_depth_stencil_alpha_state; + + context->base.create_fs_state = tegra_create_fs_state; + context->base.bind_fs_state = tegra_bind_fs_state; + context->base.delete_fs_state = tegra_delete_fs_state; + + context->base.create_vs_state = tegra_create_vs_state; + context->base.bind_vs_state = tegra_bind_vs_state; + context->base.delete_vs_state = tegra_delete_vs_state; + + context->base.create_gs_state = tegra_create_gs_state; + context->base.bind_gs_state = tegra_bind_gs_state; + context->base.delete_gs_state = tegra_delete_gs_state; + + context->base.create_vertex_elements_state = tegra_create_vertex_elements_state; + context->base.bind_vertex_elements_state = tegra_bind_vertex_elements_state; + context->base.delete_vertex_elements_state = tegra_delete_vertex_elements_state; + + context->base.set_constant_buffer = tegra_set_constant_buffer; + context->base.set_framebuffer_state = tegra_set_framebuffer_state; + context->base.set_polygon_stipple = tegra_set_polygon_stipple; + context->base.set_scissor_states = tegra_set_scissor_states; + context->base.set_viewport_states = tegra_set_viewport_states; + context->base.set_sampler_views = tegra_set_sampler_views; + + context->base.set_shader_resources = tegra_set_shader_resources; + context->base.set_vertex_buffers = tegra_set_vertex_buffers; + context->base.set_index_buffer = tegra_set_index_buffer; + + context->base.create_stream_output_target = tegra_create_stream_output_target; + context->base.stream_output_target_destroy = tegra_stream_output_target_destroy; + context->base.set_stream_output_targets = tegra_set_stream_output_targets; + + context->base.blit = tegra_blit; + context->base.clear = tegra_clear; + context->base.flush = tegra_flush; + + context->base.create_sampler_view = tegra_create_sampler_view; + context->base.sampler_view_destroy = tegra_sampler_view_destroy; + + context->base.flush_resource = tegra_flush_resource; + + context->base.create_surface = tegra_create_surface; + context->base.surface_destroy = tegra_surface_destroy; + + context->base.transfer_map = tegra_transfer_map; + context->base.transfer_unmap = tegra_transfer_unmap; + context->base.transfer_inline_write = tegra_transfer_inline_write; + + return &context->base; +} diff --git a/src/gallium/drivers/tegra/tegra_context.h b/src/gallium/drivers/tegra/tegra_context.h new file mode 100644 index 000000000000..2a26ec6d9c63 --- /dev/null +++ b/src/gallium/drivers/tegra/tegra_context.h @@ -0,0 +1,80 @@ +/* + * Copyright © 2014 NVIDIA Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef TEGRA_CONTEXT_H +#define TEGRA_CONTEXT_H + +#include "pipe/p_context.h" +#include "pipe/p_state.h" + +struct tegra_screen; + +struct tegra_context { + struct pipe_context base; + struct pipe_context *gpu; +}; + +static inline struct tegra_context * +to_tegra_context(struct pipe_context *context) +{ + return (struct tegra_context *)context; +} + +struct pipe_context *tegra_context_create(struct pipe_screen *pscreen, + void *priv); + +struct tegra_sampler_view { + struct pipe_sampler_view base; + struct pipe_sampler_view *gpu; +}; + +static INLINE struct tegra_sampler_view * +to_tegra_sampler_view(struct pipe_sampler_view *view) +{ + return (struct tegra_sampler_view *)view; +} + +static INLINE struct pipe_sampler_view * +tegra_sampler_view_unwrap(struct pipe_sampler_view *view) +{ + if (!view) + return NULL; + + return to_tegra_sampler_view(view)->gpu; +} + +struct tegra_transfer { + struct pipe_transfer base; + struct pipe_transfer *gpu; + + unsigned int count; + void *map; +}; + +static INLINE struct tegra_transfer * +to_tegra_transfer(struct pipe_transfer *transfer) +{ + return (struct tegra_transfer *)transfer; +} + +#endif /* TEGRA_SCREEN_H */ diff --git a/src/gallium/drivers/tegra/tegra_resource.c b/src/gallium/drivers/tegra/tegra_resource.c new file mode 100644 index 000000000000..8c5b7d4e41fc --- /dev/null +++ b/src/gallium/drivers/tegra/tegra_resource.c @@ -0,0 +1,219 @@ +/* + * Copyright © 2014 NVIDIA Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <errno.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> + +#include <drm/tegra_drm.h> +#include <xf86drm.h> + +#include "pipe/p_state.h" +#include "util/u_debug.h" +#include "util/u_format.h" +#include "util/u_inlines.h" + +#include "state_tracker/drm_driver.h" + +#include "tegra/tegra_context.h" +#include "tegra/tegra_resource.h" +#include "tegra/tegra_screen.h" + +struct pipe_resource * +tegra_resource_create(struct pipe_screen *pscreen, + const struct pipe_resource *template) +{ + struct tegra_screen *screen = to_tegra_screen(pscreen); + struct tegra_resource *resource; + + resource = calloc(1, sizeof(*resource)); + if (!resource) + return NULL; + + /* import scanout buffers for display */ + if (template->bind & PIPE_BIND_SCANOUT) { + struct drm_tegra_gem_set_tiling args; + struct winsys_handle handle; + boolean status; + int fd, err; + + resource->gpu = screen->gpu->resource_create(screen->gpu, + template); + if (!resource->gpu) + goto free; + + memset(&handle, 0, sizeof(handle)); + handle.type = DRM_API_HANDLE_TYPE_FD; + + status = screen->gpu->resource_get_handle(screen->gpu, + resource->gpu, + &handle); + if (!status) + goto destroy; + + resource->stride = handle.stride; + fd = handle.handle; + + err = drmPrimeFDToHandle(screen->fd, fd, &resource->handle); + if (err < 0) { + fprintf(stderr, "drmPrimeFDToHandle() failed: %s\n", + strerror(errno)); + close(fd); + goto destroy; + } + + close(fd); + + memset(&args, 0, sizeof(args)); + args.handle = resource->handle; + args.mode = DRM_TEGRA_GEM_TILING_MODE_BLOCK; + args.value = 4; + + err = drmIoctl(screen->fd, DRM_IOCTL_TEGRA_GEM_SET_TILING, + &args); + if (err < 0) { + fprintf(stderr, "failed to set tiling parameters: %s\n", + strerror(errno)); + goto destroy; + } + } else { + resource->gpu = screen->gpu->resource_create(screen->gpu, + template); + if (!resource->gpu) + goto free; + } + + memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu)); + pipe_reference_init(&resource->base.reference, 1); + resource->base.screen = &screen->base; + + return &resource->base; + +destroy: + screen->gpu->resource_destroy(screen->gpu, resource->gpu); +free: + free(resource); + return NULL; +} + +struct pipe_resource * +tegra_resource_from_handle(struct pipe_screen *pscreen, + const struct pipe_resource *template, + struct winsys_handle *handle) +{ + struct tegra_screen *screen = to_tegra_screen(pscreen); + struct tegra_resource *resource; + + resource = calloc(1, sizeof(*resource)); + if (!resource) + return NULL; + + resource->gpu = screen->gpu->resource_from_handle(screen->gpu, + template, + handle); + if (!resource->gpu) { + free(resource); + return NULL; + } + + memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu)); + pipe_reference_init(&resource->base.reference, 1); + resource->base.screen = &screen->base; + + return &resource->base; +} + +boolean +tegra_resource_get_handle(struct pipe_screen *pscreen, + struct pipe_resource *presource, + struct winsys_handle *handle) +{ + struct tegra_resource *resource = to_tegra_resource(presource); + struct tegra_screen *screen = to_tegra_screen(pscreen); + boolean ret = TRUE; + + if (presource->bind & PIPE_BIND_SCANOUT) { + handle->handle = resource->handle; + handle->stride = resource->stride; + } else { + ret = screen->gpu->resource_get_handle(screen->gpu, + resource->gpu, + handle); + } + + return ret; +} + +void +tegra_resource_destroy(struct pipe_screen *pscreen, + struct pipe_resource *presource) +{ + struct tegra_resource *resource = to_tegra_resource(presource); + + pipe_resource_reference(&resource->gpu, NULL); + free(resource); +} + +struct pipe_surface * +tegra_create_surface(struct pipe_context *pcontext, + struct pipe_resource *presource, + const struct pipe_surface *template) +{ + struct tegra_resource *resource = to_tegra_resource(presource); + struct tegra_context *context = to_tegra_context(pcontext); + struct tegra_surface *surface; + + surface = calloc(1, sizeof(*surface)); + if (!surface) + return NULL; + + surface->gpu = context->gpu->create_surface(context->gpu, + resource->gpu, + template); + if (!surface->gpu) { + free(surface); + return NULL; + } + + memcpy(&surface->base, surface->gpu, sizeof(*surface->gpu)); + /* overwrite to prevent reference from being released */ + surface->base.texture = NULL; + + pipe_reference_init(&surface->base.reference, 1); + pipe_resource_reference(&surface->base.texture, presource); + surface->base.context = &context->base; + + return &surface->base; +} + +void +tegra_surface_destroy(struct pipe_context *pcontext, + struct pipe_surface *psurface) +{ + struct tegra_surface *surface = to_tegra_surface(psurface); + + pipe_resource_reference(&surface->base.texture, NULL); + pipe_surface_reference(&surface->gpu, NULL); + free(surface); +} diff --git a/src/gallium/drivers/tegra/tegra_resource.h b/src/gallium/drivers/tegra/tegra_resource.h new file mode 100644 index 000000000000..783fb37ec466 --- /dev/null +++ b/src/gallium/drivers/tegra/tegra_resource.h @@ -0,0 +1,98 @@ +/* + * Copyright © 2014 NVIDIA Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef TEGRA_RESOURCE_H +#define TEGRA_RESOURCE_H + +#include "pipe/p_state.h" + +struct winsys_handle; + +struct tegra_resource { + struct pipe_resource base; + struct pipe_resource *gpu; + + uint32_t stride; + uint32_t handle; + size_t size; +}; + +static INLINE struct tegra_resource * +to_tegra_resource(struct pipe_resource *resource) +{ + return (struct tegra_resource *)resource; +} + +static INLINE struct pipe_resource * +tegra_resource_unwrap(struct pipe_resource *resource) +{ + if (!resource) + return NULL; + + return to_tegra_resource(resource)->gpu; +} + +struct pipe_resource * +tegra_resource_create(struct pipe_screen *pscreen, + const struct pipe_resource *template); +struct pipe_resource * +tegra_resource_from_handle(struct pipe_screen *pscreen, + const struct pipe_resource *template, + struct winsys_handle *handle); +boolean +tegra_resource_get_handle(struct pipe_screen *pscreen, + struct pipe_resource *resource, + struct winsys_handle *handle); +void +tegra_resource_destroy(struct pipe_screen *pscreen, + struct pipe_resource *resource); + +struct tegra_surface { + struct pipe_surface base; + struct pipe_surface *gpu; +}; + +static INLINE struct tegra_surface * +to_tegra_surface(struct pipe_surface *surface) +{ + return (struct tegra_surface *)surface; +} + +static INLINE struct pipe_surface * +tegra_surface_unwrap(struct pipe_surface *surface) +{ + if (!surface) + return NULL; + + return to_tegra_surface(surface)->gpu; +} + +struct pipe_surface * +tegra_create_surface(struct pipe_context *pcontext, + struct pipe_resource *presource, + const struct pipe_surface *template); +void +tegra_surface_destroy(struct pipe_context *pcontext, + struct pipe_surface *psurface); + +#endif /* TEGRA_RESOURCE_H */ diff --git a/src/gallium/drivers/tegra/tegra_screen.c b/src/gallium/drivers/tegra/tegra_screen.c new file mode 100644 index 000000000000..aa7bf65cb7ec --- /dev/null +++ b/src/gallium/drivers/tegra/tegra_screen.c @@ -0,0 +1,311 @@ +/* + * Copyright © 2014 NVIDIA Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> + +#ifdef HAVE_LIBUDEV +#include <libudev.h> +#endif + +#include "util/u_debug.h" + +#include "tegra/tegra_context.h" +#include "tegra/tegra_resource.h" +#include "tegra/tegra_screen.h" + +/* TODO: obtain from include file */ +struct pipe_screen *nouveau_drm_screen_create(int fd); + +static const char * +tegra_get_name(struct pipe_screen *pscreen) +{ + return "tegra"; +} + +static const char * +tegra_get_vendor(struct pipe_screen *pscreen) +{ + return "tegra"; +} + +static void tegra_screen_destroy(struct pipe_screen *pscreen) +{ + struct tegra_screen *screen = to_tegra_screen(pscreen); + + screen->gpu->destroy(screen->gpu); + free(pscreen); +} + +static int +tegra_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) +{ + struct tegra_screen *screen = to_tegra_screen(pscreen); + + return screen->gpu->get_param(screen->gpu, param); +} + +static float +tegra_screen_get_paramf(struct pipe_screen *pscreen, enum pipe_capf param) +{ + struct tegra_screen *screen = to_tegra_screen(pscreen); + + return screen->gpu->get_paramf(screen->gpu, param); +} + +static int +tegra_screen_get_shader_param(struct pipe_screen *pscreen, + unsigned shader, + enum pipe_shader_cap param) +{ + struct tegra_screen *screen = to_tegra_screen(pscreen); + + return screen->gpu->get_shader_param(screen->gpu, shader, param); +} + +static boolean +tegra_screen_is_format_supported(struct pipe_screen *pscreen, + enum pipe_format format, + enum pipe_texture_target target, + unsigned sample_count, + unsigned usage) +{ + struct tegra_screen *screen = to_tegra_screen(pscreen); + + return screen->gpu->is_format_supported(screen->gpu, format, target, + sample_count, usage); +} + +static void +tegra_fence_reference(struct pipe_screen *pscreen, + struct pipe_fence_handle **ptr, + struct pipe_fence_handle *fence) +{ + struct tegra_screen *screen = to_tegra_screen(pscreen); + + screen->gpu->fence_reference(screen->gpu, ptr, fence); +} + +static boolean +tegra_fence_signalled(struct pipe_screen *pscreen, + struct pipe_fence_handle *fence) +{ + struct tegra_screen *screen = to_tegra_screen(pscreen); + + return screen->gpu->fence_signalled(screen->gpu, fence); +} + +static boolean +tegra_fence_finish(struct pipe_screen *pscreen, + struct pipe_fence_handle *fence, + uint64_t timeout) +{ + struct tegra_screen *screen = to_tegra_screen(pscreen); + + return screen->gpu->fence_finish(screen->gpu, fence, timeout); +} + +static struct udev_device *udev_device_new_from_fd(struct udev *udev, int fd) +{ + struct udev_device *device; + struct stat stat; + int err; + + err = fstat(fd, &stat); + if (err < 0) { + fprintf(stderr, "fstat() failed: %s\n", strerror(errno)); + return NULL; + } + + device = udev_device_new_from_devnum(udev, 'c', stat.st_rdev); + if (!device) { + fprintf(stderr, "udev_device_new_from_devnum() failed\n"); + return NULL; + } + + return device; +} + +static struct udev_device *udev_device_get_root(struct udev_device *device) +{ + struct udev_device *parent; + + while (true) { + parent = udev_device_get_parent(device); + if (!parent) + break; + + device = parent; + } + + return device; +} + +static bool udev_device_match(struct udev_device *x, struct udev_device *y) +{ + const char *p1 = udev_device_get_syspath(x); + const char *p2 = udev_device_get_syspath(y); + + return strcmp(p1, p2) == 0; +} + +static int tegra_open_render_node(int fd) +{ + struct udev_device *display, *parent, *root; + struct udev_list_entry *list, *entry; + struct udev_enumerate *enumerate; + struct udev *udev; + + udev = udev_new(); + if (!udev) + return -ENOMEM; + + display = udev_device_new_from_fd(udev, fd); + if (!display) { + udev_unref(udev); + return -ENODEV; + } + + parent = udev_device_get_parent(display); + if (!parent) { + udev_device_unref(display); + udev_unref(udev); + return -ENODEV; + } + + display = parent; + + root = udev_device_get_root(display); + if (!root) { + udev_device_unref(display); + udev_unref(udev); + return -ENODEV; + } + + enumerate = udev_enumerate_new(udev); + if (!enumerate) { + udev_device_unref(display); + udev_unref(udev); + return -ENOMEM; + } + + udev_enumerate_add_match_subsystem(enumerate, "drm"); + udev_enumerate_add_match_sysname(enumerate, "render*"); + udev_enumerate_scan_devices(enumerate); + + list = udev_enumerate_get_list_entry(enumerate); + + udev_list_entry_foreach(entry, list) { + const char *path = udev_list_entry_get_name(entry); + struct udev_device *device, *bus; + + device = udev_device_new_from_syspath(udev, path); + if (!device) + continue; + + path = udev_device_get_devnode(device); + + parent = udev_device_get_parent(device); + if (!parent) { + udev_device_unref(device); + continue; + } + + /* do not match if the render nodes shares the same parent */ + if (udev_device_match(parent, display)) { + udev_device_unref(parent); + udev_device_unref(device); + continue; + } + + bus = udev_device_get_root(device); + if (!bus) { + udev_device_unref(parent); + udev_device_unref(device); + continue; + } + + /* both devices need to be on the same bus, though */ + if (udev_device_match(bus, root)) { + fd = open(path, O_RDWR); + if (fd < 0) + fd = -errno; + + break; + } + } + + udev_enumerate_unref(enumerate); + udev_unref(udev); + + return open("/dev/dri/renderD128", O_RDWR); +} + +struct pipe_screen * +tegra_screen_create(int fd) +{ + struct tegra_screen *screen; + + screen = calloc(1, sizeof(*screen)); + if (!screen) + return NULL; + + screen->fd = fd; + + screen->gpu_fd = tegra_open_render_node(screen->fd); + if (screen->gpu_fd < 0) { + fprintf(stderr, "failed to open GPU device: %s\n", + strerror(errno)); + free(screen); + return NULL; + } + + screen->gpu = nouveau_drm_screen_create(screen->gpu_fd); + if (!screen->gpu) { + fprintf(stderr, "failed to create GPU screen\n"); + close(screen->gpu_fd); + free(screen); + return NULL; + } + + screen->base.get_name = tegra_get_name; + screen->base.get_vendor = tegra_get_vendor; + screen->base.destroy = tegra_screen_destroy; + screen->base.get_param = tegra_screen_get_param; + screen->base.get_paramf = tegra_screen_get_paramf; + screen->base.get_shader_param = tegra_screen_get_shader_param; + screen->base.context_create = tegra_context_create; + screen->base.is_format_supported = tegra_screen_is_format_supported; + + screen->base.resource_create = tegra_resource_create; + screen->base.resource_from_handle = tegra_resource_from_handle; + screen->base.resource_get_handle = tegra_resource_get_handle; + screen->base.resource_destroy = tegra_resource_destroy; + + screen->base.fence_reference = tegra_fence_reference; + screen->base.fence_signalled = tegra_fence_signalled; + screen->base.fence_finish = tegra_fence_finish; + + return &screen->base; +} diff --git a/src/gallium/drivers/tegra/tegra_screen.h b/src/gallium/drivers/tegra/tegra_screen.h new file mode 100644 index 000000000000..1fba510c241f --- /dev/null +++ b/src/gallium/drivers/tegra/tegra_screen.h @@ -0,0 +1,45 @@ +/* + * Copyright © 2014 NVIDIA Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef TEGRA_SCREEN_H +#define TEGRA_SCREEN_H + +#include "pipe/p_screen.h" + +struct tegra_screen { + struct pipe_screen base; + int fd; + + struct pipe_screen *gpu; + int gpu_fd; +}; + +static inline struct tegra_screen * +to_tegra_screen(struct pipe_screen *pscreen) +{ + return (struct tegra_screen *)pscreen; +} + +struct pipe_screen *tegra_screen_create(int fd); + +#endif /* TEGRA_SCREEN_H */ diff --git a/src/gallium/targets/dri/Makefile.am b/src/gallium/targets/dri/Makefile.am index 3c7140d75b5c..0406eaf66537 100644 --- a/src/gallium/targets/dri/Makefile.am +++ b/src/gallium/targets/dri/Makefile.am @@ -83,6 +83,8 @@ include $(top_srcdir)/src/gallium/drivers/svga/Automake.inc include $(top_srcdir)/src/gallium/drivers/freedreno/Automake.inc +include $(top_srcdir)/src/gallium/drivers/tegra/Automake.inc + include $(top_srcdir)/src/gallium/drivers/vc4/Automake.inc include $(top_srcdir)/src/gallium/drivers/softpipe/Automake.inc diff --git a/src/gallium/winsys/tegra/drm/Makefile.am b/src/gallium/winsys/tegra/drm/Makefile.am new file mode 100644 index 000000000000..8e3685ee20e8 --- /dev/null +++ b/src/gallium/winsys/tegra/drm/Makefile.am @@ -0,0 +1,11 @@ +include Makefile.sources +include $(top_srcdir)/src/gallium/Automake.inc + +AM_CFLAGS = \ + -I$(top_srcdir)/src/gallium/drivers \ + $(GALLIUM_WINSYS_CFLAGS) \ + $(FREEDRENO_CFLAGS) + +noinst_LTLIBRARIES = libtegradrm.la + +libtegradrm_la_SOURCES = $(C_SOURCES) diff --git a/src/gallium/winsys/tegra/drm/Makefile.sources b/src/gallium/winsys/tegra/drm/Makefile.sources new file mode 100644 index 000000000000..fe0d5c42e72d --- /dev/null +++ b/src/gallium/winsys/tegra/drm/Makefile.sources @@ -0,0 +1,2 @@ +C_SOURCES := \ + tegra_drm_winsys.c diff --git a/src/gallium/winsys/tegra/drm/tegra_drm_public.h b/src/gallium/winsys/tegra/drm/tegra_drm_public.h new file mode 100644 index 000000000000..45e3e006f9be --- /dev/null +++ b/src/gallium/winsys/tegra/drm/tegra_drm_public.h @@ -0,0 +1,31 @@ +/* + * Copyright © 2014 NVIDIA Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __TEGRA_DRM_PUBLIC_H__ +#define __TEGRA_DRM_PUBLIC_H__ + +struct pipe_screen; + +struct pipe_screen *tegra_drm_screen_create(int fd); + +#endif /* __TEGRA_DRM_PUBLIC_H__ */ diff --git a/src/gallium/winsys/tegra/drm/tegra_drm_winsys.c b/src/gallium/winsys/tegra/drm/tegra_drm_winsys.c new file mode 100644 index 000000000000..99b0e1649026 --- /dev/null +++ b/src/gallium/winsys/tegra/drm/tegra_drm_winsys.c @@ -0,0 +1,33 @@ +/* + * Copyright © 2014 NVIDIA Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "util/u_debug.h" + +#include "tegra/tegra_screen.h" + +struct pipe_screen *tegra_drm_screen_create(int fd); + +struct pipe_screen *tegra_drm_screen_create(int fd) +{ + return tegra_screen_create(fd); +} -- 2.1.3
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 driversI 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
On 11/28/2014 01:39 AM, Thierry Reding wrote:> Tegra K1 and later use a GPU that can be driven by the Nouveau driver. > But the GPU is a pure render node and has no display engine, hence the > scanout needs to happen on the Tegra display hardware. The GPU and the > display engine each have a separate DRM device node exposed by the > kernel. > > To make the setup appear as a single device, this driver instantiates > a Nouveau screen with each instance of a Tegra screen and forwards GPU > requests to the Nouveau screen. For purposes of scanout it will import > buffers created on the GPU into the display driver. Handles that > userspace requests are those of the display driver so that they can be > used to create framebuffers. > > This has been tested with some GBM test programs, as well as kmscube and > weston. All of those run without modifications, but I'm sure there is a > lot that can be improved.Tested with kmscube and Weston and I can confirm this works. However, EGL clients inside Weston have their window filled with garbage (they seem to run fine otherwise). Do you also experience this?
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 > > Signed-off-by: Thierry Reding <treding at nvidia.com>With the exception of resource creation, I don't see anything tegra-specific in here. Is there perhaps something that could be done to abstract that a little more, e.g. a wrapper driver, or... something? This is a situation that several mobile GPU's are in, AFAIK, and it may be nice to make it work for them as well. Also, can you explain why it's advantageous for the setup to appear as though it is a single device? i.e. what's wrong with just using nouveau as a render node or whatever? [The answer may be simple, but I'm very unfamiliar with a lot of that stuff, and perhaps others are in a similar predicament.]> diff --git a/src/gallium/winsys/tegra/drm/Makefile.am b/src/gallium/winsys/tegra/drm/Makefile.am > new file mode 100644 > index 000000000000..8e3685ee20e8 > --- /dev/null > +++ b/src/gallium/winsys/tegra/drm/Makefile.am > @@ -0,0 +1,11 @@ > +include Makefile.sources > +include $(top_srcdir)/src/gallium/Automake.inc > + > +AM_CFLAGS = \ > + -I$(top_srcdir)/src/gallium/drivers \ > + $(GALLIUM_WINSYS_CFLAGS) \ > + $(FREEDRENO_CFLAGS)oops?> + > +noinst_LTLIBRARIES = libtegradrm.la > + > +libtegradrm_la_SOURCES = $(C_SOURCES)
On Thu, Nov 27, 2014 at 11:51:08AM -0500, Rob Clark wrote:> On Thu, Nov 27, 2014 at 11:39 AM, Thierry Reding > <thierry.reding 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..?That's not how Mesa's loader works. Typically only a file descriptor is passed in and helpers determine a name for the driver to load, then the DRI code will load <name>_dri.so. I don't see how this could be made to work with a single Gallium driver. There's also the fact that these drivers need to become very HW-specific at some point, so sharing a single driver will likely just cause an explosion of conditionals to special-case for each and everyone of the drivers. Lastly, Tegra is also somewhat special in this regard because earlier generations did have a GPU that's controlled via the same DRM device as the display part. If ever a Mesa driver shows up for that older GPU we are going to have a conflict between the shim and the Tegra driver that isn't going to be easy to untangle. With a separate driver we can use SoC-specific knowledge to determine whether the driver is running on an old SoC generation or Tegra K1 and later. Thierry -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.freedesktop.org/archives/nouveau/attachments/20141128/0250a87a/attachment-0001.sig>
On Fri, Nov 28, 2014 at 02:14:24PM +0900, Alexandre Courbot wrote:> On 11/28/2014 01:39 AM, Thierry Reding wrote: > >Tegra K1 and later use a GPU that can be driven by the Nouveau driver. > >But the GPU is a pure render node and has no display engine, hence the > >scanout needs to happen on the Tegra display hardware. The GPU and the > >display engine each have a separate DRM device node exposed by the > >kernel. > > > >To make the setup appear as a single device, this driver instantiates > >a Nouveau screen with each instance of a Tegra screen and forwards GPU > >requests to the Nouveau screen. For purposes of scanout it will import > >buffers created on the GPU into the display driver. Handles that > >userspace requests are those of the display driver so that they can be > >used to create framebuffers. > > > >This has been tested with some GBM test programs, as well as kmscube and > >weston. All of those run without modifications, but I'm sure there is a > >lot that can be improved. > > Tested with kmscube and Weston and I can confirm this works. However, EGL > clients inside Weston have their window filled with garbage (they seem to > run fine otherwise). Do you also experience this?To be honest, that wasn't part of my set of test cases. I had assumed that since Weston could composite buffers into a final scan out buffer everything else would just work as well. Do you have any particular demos that aren't working? Thierry -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.freedesktop.org/archives/nouveau/attachments/20141128/d6c27400/attachment.sig>
On Fri, Nov 28, 2014 at 12:32:43AM -0500, Ilia Mirkin wrote:> On Thu, Nov 27, 2014 at 11:39 AM, Thierry Reding > <thierry.reding 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 > > > > Signed-off-by: Thierry Reding <treding at nvidia.com> > > With the exception of resource creation, I don't see anything > tegra-specific in here. Is there perhaps something that could be done > to abstract that a little more, e.g. a wrapper driver, or... > something? This is a situation that several mobile GPU's are in, > AFAIK, and it may be nice to make it work for them as well.I think it might be possible to factor out some things to reduce some amount of boilerplate, but I don't expect it to be very much. There is likely going to be hardware-specific details in each of these drivers that will be hard to abstract out. Given that this is the first driver of this sort I have no idea what other drivers will require, so it doesn't seem wise for me to make this any more generic. It's very likely to turn out completely wrong. Hence why I opted for just a straight implementation that would work on Tegra. That said, if it turns out that drivers for other SoCs need to duplicate a lot of the code in this driver I'm sure we can find ways to alleviate some of that. But like I already said in my reply to Rob, I don't think a common wrapper driver is going to cut it. Perhaps something like the u_transfer abstraction could work, but there is potential for that to turn into a midlayer of sorts and actually make things more difficult. The bottom-line is that the vast majority of the code is really just a skeleton driver, so it's not unlike any of the existing drivers. Requiring this particular driver to be common for all "mobile" SoCs is a little like saying that Radeon and Nouveau should share code because they both use PCI as the transport.> Also, can you explain why it's advantageous for the setup to appear as > though it is a single device? i.e. what's wrong with just using > nouveau as a render node or whatever? [The answer may be simple, but > I'm very unfamiliar with a lot of that stuff, and perhaps others are > in a similar predicament.]There are two reasons. For one, pretty much every software out there that runs on the "bare metal" (i.e. GBM) uses the same initialization sequence and it doesn't involve opening two DRM devices. So in order to support Tegra and other SoCs with a similar architecture, each of these applications would need to be patched. Now typically a lot of the applications would run under X or Wayland, so the number of applications that need patching is somewhat reduced. However, it would still mean that every Wayland compositor would need to be patched in order to support this, and each of them would use a mostly identical copy of that code. The second reason derives from the first. One of the issues I ran into when I prototyped the dual-fd code for kmscube was that the code to share these buffers between GPU and display is in fact highly hardware- specific. At least on Tegra it is, because we can take advantage of the tight coupling between GPU and display by directly scanning out block- linear buffers. For that to work we need to make assumptions and that just doesn't work generically. So we need to solve two problems: reduce code duplication and hide the hardware specific details. The natural solution for these two problems is to move the code into a library. But we already have that library: Mesa/GBM.> > diff --git a/src/gallium/winsys/tegra/drm/Makefile.am b/src/gallium/winsys/tegra/drm/Makefile.am > > new file mode 100644 > > index 000000000000..8e3685ee20e8 > > --- /dev/null > > +++ b/src/gallium/winsys/tegra/drm/Makefile.am > > @@ -0,0 +1,11 @@ > > +include Makefile.sources > > +include $(top_srcdir)/src/gallium/Automake.inc > > + > > +AM_CFLAGS = \ > > + -I$(top_srcdir)/src/gallium/drivers \ > > + $(GALLIUM_WINSYS_CFLAGS) \ > > + $(FREEDRENO_CFLAGS) > > oops?Yes, I wanted to make it obvious from where I copied. =) Good catch, thanks. Thierry -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 819 bytes Desc: not available URL: <http://lists.freedesktop.org/archives/nouveau/attachments/20141128/99aacfd3/attachment.sig>
Hi Thierry, Must admit that I really prefer this idea over modifying existing applications/users [1] because: - Most of these setups are tightly coupled (imx+vivante, tegra+nouveau) and pushing this down to the driver prevents duplication, and hardware specific details in the users. - Removes the need (at least temporary) to have an arbiter and policies about which devices can and how they should be coupled. Hope your trip through the build/target helpers did not leave you tearing your hairs out :) [1] xserver's libglx and everyone else whole deals with gbm or dri modules directly. On 27/11/14 16:39, Thierry Reding wrote:> Tegra K1 and later use a GPU that can be driven by the Nouveau driver. > But the GPU is a pure render node and has no display engine, hence the > scanout needs to happen on the Tegra display hardware. The GPU and the > display engine each have a separate DRM device node exposed by the > kernel. > > To make the setup appear as a single device, this driver instantiates > a Nouveau screen with each instance of a Tegra screen and forwards GPU > requests to the Nouveau screen. For purposes of scanout it will import > buffers created on the GPU into the display driver. Handles that > userspace requests are those of the display driver so that they can be > used to create framebuffers. > > This has been tested with some GBM test programs, as well as kmscube and > weston. All of those run without modifications, but I'm sure there is a > lot that can be improved. > > TODO: > - use Nouveau headers to get at the prototype for creating a screenI've addressed those inline for you :)> - implement enough support to seamlessly integrate with X > - refactor some of the code to be reusable by other driversI think this topic will be open for debate for a while. Especially since tegra is only one driver (for now) that uses this type on stacking/wrapping thus it's not so easy to predict if others won't need anything extra.> > Signed-off-by: Thierry Reding <treding at nvidia.com> > --- > configure.ac | 12 +- > src/gallium/Makefile.am | 5 + > .../auxiliary/target-helpers/inline_drm_helper.h | 30 + > src/gallium/drivers/tegra/Automake.inc | 11 + > src/gallium/drivers/tegra/Makefile.am | 17 + > src/gallium/drivers/tegra/Makefile.sources | 4 + > src/gallium/drivers/tegra/tegra_context.c | 699 +++++++++++++++++++++ > src/gallium/drivers/tegra/tegra_context.h | 80 +++ > src/gallium/drivers/tegra/tegra_resource.c | 219 +++++++ > src/gallium/drivers/tegra/tegra_resource.h | 98 +++ > src/gallium/drivers/tegra/tegra_screen.c | 311 +++++++++ > src/gallium/drivers/tegra/tegra_screen.h | 45 ++ > src/gallium/targets/dri/Makefile.am | 2 + > src/gallium/winsys/tegra/drm/Makefile.am | 11 + > src/gallium/winsys/tegra/drm/Makefile.sources | 2 + > src/gallium/winsys/tegra/drm/tegra_drm_public.h | 31 + > src/gallium/winsys/tegra/drm/tegra_drm_winsys.c | 33 + > 17 files changed, 1609 insertions(+), 1 deletion(-) > create mode 100644 src/gallium/drivers/tegra/Automake.inc > create mode 100644 src/gallium/drivers/tegra/Makefile.am > create mode 100644 src/gallium/drivers/tegra/Makefile.sources > create mode 100644 src/gallium/drivers/tegra/tegra_context.c > create mode 100644 src/gallium/drivers/tegra/tegra_context.h > create mode 100644 src/gallium/drivers/tegra/tegra_resource.c > create mode 100644 src/gallium/drivers/tegra/tegra_resource.h > create mode 100644 src/gallium/drivers/tegra/tegra_screen.c > create mode 100644 src/gallium/drivers/tegra/tegra_screen.h > create mode 100644 src/gallium/winsys/tegra/drm/Makefile.am > create mode 100644 src/gallium/winsys/tegra/drm/Makefile.sources > create mode 100644 src/gallium/winsys/tegra/drm/tegra_drm_public.h > create mode 100644 src/gallium/winsys/tegra/drm/tegra_drm_winsys.c > > diff --git a/configure.ac b/configure.ac > index 1d9d015481ec..ae50bec95339 100644 > --- a/configure.ac > +++ b/configure.ac[...]> @@ -1937,6 +1938,12 @@ if test -n "$with_gallium_drivers"; then > gallium_require_drm "freedreno" > gallium_require_drm_loader > ;; > + xtegra) > + HAVE_GALLIUM_TEGRA=yes > + PKG_CHECK_MODULES([TEGRA], [libdrm_tegra >= $LIBDRM_TEGRA_REQUIRED]) > + gallium_require_drm "tegra" > + gallium_require_drm_loader > + ;;You might want to have something like the following further down. Admittedly it's not perfect (it will create a nouveau_dri.so hardlink) but it'll avoid the manual case for nouveau dependencies. if test "x$HAVE_GALLIUM_NOUVEAU" != xyes -a test "x$HAVE_GALLIUM_TEGRA" = xyes; then AC_ERROR([Building with tegra requires that nouveau]) fi [...]> diff --git a/src/gallium/drivers/tegra/Makefile.am b/src/gallium/drivers/tegra/Makefile.am > new file mode 100644 > index 000000000000..eb03df9bb2ed > --- /dev/null > +++ b/src/gallium/drivers/tegra/Makefile.am > @@ -0,0 +1,17 @@ > +AUTOMAKE_OPTIONS = subdir-objects > +Don't think you need the AUTOMAKE_OPTIONS here.> +include Makefile.sources > +include $(top_srcdir)/src/gallium/Automake.inc > + > +AM_CFLAGS = \ > + $(GALLIUM_DRIVER_CFLAGS) \ > + $(LIBUDEV_CFLAGS) \ > + $(TEGRA_CFLAGS) > + > +noinst_LTLIBRARIES = libtegra.la > + > +libtegra_la_SOURCES = \ > + $(C_SOURCES) > + > +libtegra_la_LIBADD = \ > + $(LIBUDEV_LIBS)Here comes the big question: Can we do something to avoid the link against libudev ? If we _do_ need to go through libudev, can we please dlopen/dlsym it.> diff --git a/src/gallium/drivers/tegra/Makefile.sources b/src/gallium/drivers/tegra/Makefile.sources > new file mode 100644 > index 000000000000..978dd14667f5 > --- /dev/null > +++ b/src/gallium/drivers/tegra/Makefile.sources > @@ -0,0 +1,4 @@ > +C_SOURCES := \ > + tegra_context.c \ > + tegra_resource.c \ > + tegra_screen.cPlease add the headers to the above list. It will help automake pick them up in the distribution tarball. [...]> diff --git a/src/gallium/drivers/tegra/tegra_resource.c b/src/gallium/drivers/tegra/tegra_resource.c > new file mode 100644 > index 000000000000..8c5b7d4e41fc > --- /dev/null > +++ b/src/gallium/drivers/tegra/tegra_resource.c[...]> +#include <drm/tegra_drm.h>Please drop the "drm/" part.> diff --git a/src/gallium/drivers/tegra/tegra_screen.c b/src/gallium/drivers/tegra/tegra_screen.c > new file mode 100644 > index 000000000000..aa7bf65cb7ec > --- /dev/null > +++ b/src/gallium/drivers/tegra/tegra_screen.c[...]> +#ifdef HAVE_LIBUDEV > +#include <libudev.h> > +#endif > +You might as well drop the #ifdef here. Afaics you're using udev API explicitly below.> +#include "util/u_debug.h" > + > +#include "tegra/tegra_context.h" > +#include "tegra/tegra_resource.h" > +#include "tegra/tegra_screen.h" > + > +/* TODO: obtain from include file */ > +struct pipe_screen *nouveau_drm_screen_create(int fd); > +#include "nouveau/drm/nouveau_drm_public.h" ?> +static const char * > +tegra_get_name(struct pipe_screen *pscreen) > +{ > + return "tegra";For nouveau/radeons we add the chipset name so I guess doing similar thing here wouldn't be a bad idea. Additionally for combined/stacked drivers we might want to return both the base + gpu's get_name(). It will provide nice feedback about the actual rendering device + programs which use device name hacks will continue working :)> +} > + > +static const char * > +tegra_get_vendor(struct pipe_screen *pscreen) > +{ > + return "tegra";Provide both vendors similar to above ? "NVIDIA Corp + nouveau" :P [...]> +static int tegra_open_render_node(int fd) > +{[...]> + udev_list_entry_foreach(entry, list) { > + const char *path = udev_list_entry_get_name(entry); > + struct udev_device *device, *bus; > + > + device = udev_device_new_from_syspath(udev, path); > + if (!device) > + continue; > + > + path = udev_device_get_devnode(device); > + > + parent = udev_device_get_parent(device); > + if (!parent) { > + udev_device_unref(device); > + continue; > + } > + > + /* do not match if the render nodes shares the same parent */ > + if (udev_device_match(parent, display)) { > + udev_device_unref(parent); > + udev_device_unref(device); > + continue; > + } > + > + bus = udev_device_get_root(device); > + if (!bus) { > + udev_device_unref(parent); > + udev_device_unref(device); > + continue; > + } > + > + /* both devices need to be on the same bus, though */ > + if (udev_device_match(bus, root)) { > + fd = open(path, O_RDWR);open(path) only to ignore it and return open("renderD128") below ? Seems like something is missing here.> + if (fd < 0) > + fd = -errno; > + > + break; > + } > + } > + > + udev_enumerate_unref(enumerate); > + udev_unref(udev); > + > + return open("/dev/dri/renderD128", O_RDWR); > +} > +[...]> diff --git a/src/gallium/winsys/tegra/drm/Makefile.am b/src/gallium/winsys/tegra/drm/Makefile.am > new file mode 100644 > index 000000000000..8e3685ee20e8 > --- /dev/null > +++ b/src/gallium/winsys/tegra/drm/Makefile.am > @@ -0,0 +1,11 @@ > +include Makefile.sources > +include $(top_srcdir)/src/gallium/Automake.inc > + > +AM_CFLAGS = \ > + -I$(top_srcdir)/src/gallium/drivers \ > + $(GALLIUM_WINSYS_CFLAGS) \ > + $(FREEDRENO_CFLAGS) > +Do we even need FREEDRENO/TEGRA_CFLAGS here ?> +noinst_LTLIBRARIES = libtegradrm.la > + > +libtegradrm_la_SOURCES = $(C_SOURCES) > diff --git a/src/gallium/winsys/tegra/drm/Makefile.sources b/src/gallium/winsys/tegra/drm/Makefile.sources > new file mode 100644 > index 000000000000..fe0d5c42e72d > --- /dev/null > +++ b/src/gallium/winsys/tegra/drm/Makefile.sources > @@ -0,0 +1,2 @@ > +C_SOURCES := \ > + tegra_drm_winsys.cPlease add tegra_drm_public.h to the list. [...]> diff --git a/src/gallium/winsys/tegra/drm/tegra_drm_winsys.c b/src/gallium/winsys/tegra/drm/tegra_drm_winsys.c > new file mode 100644 > index 000000000000..99b0e1649026 > --- /dev/null > +++ b/src/gallium/winsys/tegra/drm/tegra_drm_winsys.c > @@ -0,0 +1,33 @@ > +/* > + * Copyright © 2014 NVIDIA Corporation > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the next > + * paragraph) shall be included in all copies or substantial portions of the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > + * IN THE SOFTWARE. > + */ > + > +#include "util/u_debug.h" > + > +#include "tegra/tegra_screen.h" > + > +struct pipe_screen *tegra_drm_screen_create(int fd); > +util/u_debug.h is not be needed so the following should suffice. #include "tegra_drm_public.h" #include "tegra/tegra_screen.h" Thanks Emil