101e04c3fSmrg/*
201e04c3fSmrg * Copyright © 2014-2018 NVIDIA Corporation
301e04c3fSmrg *
401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
501e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
601e04c3fSmrg * to deal in the Software without restriction, including without limitation
701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
901e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1001e04c3fSmrg *
1101e04c3fSmrg * The above copyright notice and this permission notice (including the next
1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1301e04c3fSmrg * Software.
1401e04c3fSmrg *
1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2101e04c3fSmrg * IN THE SOFTWARE.
2201e04c3fSmrg */
2301e04c3fSmrg
2401e04c3fSmrg#include <errno.h>
2501e04c3fSmrg#include <fcntl.h>
2601e04c3fSmrg#include <inttypes.h>
2701e04c3fSmrg#include <stdio.h>
2801e04c3fSmrg
2901e04c3fSmrg#include <sys/stat.h>
3001e04c3fSmrg
319f464c52Smaya#include "drm-uapi/drm_fourcc.h"
329f464c52Smaya#include "drm-uapi/tegra_drm.h"
3301e04c3fSmrg#include <xf86drm.h>
3401e04c3fSmrg
3501e04c3fSmrg#include "loader/loader.h"
3601e04c3fSmrg#include "pipe/p_state.h"
3701e04c3fSmrg#include "util/u_debug.h"
387ec681f3Smrg#include "util/format/u_format.h"
3901e04c3fSmrg#include "util/u_inlines.h"
4001e04c3fSmrg
417ec681f3Smrg#include "frontend/drm_driver.h"
4201e04c3fSmrg
4301e04c3fSmrg#include "nouveau/drm/nouveau_drm_public.h"
4401e04c3fSmrg
4501e04c3fSmrg#include "tegra_context.h"
4601e04c3fSmrg#include "tegra_resource.h"
4701e04c3fSmrg#include "tegra_screen.h"
4801e04c3fSmrg
4901e04c3fSmrgstatic void tegra_screen_destroy(struct pipe_screen *pscreen)
5001e04c3fSmrg{
5101e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
5201e04c3fSmrg
5301e04c3fSmrg   screen->gpu->destroy(screen->gpu);
5401e04c3fSmrg   free(pscreen);
5501e04c3fSmrg}
5601e04c3fSmrg
5701e04c3fSmrgstatic const char *
5801e04c3fSmrgtegra_screen_get_name(struct pipe_screen *pscreen)
5901e04c3fSmrg{
6001e04c3fSmrg   return "tegra";
6101e04c3fSmrg}
6201e04c3fSmrg
6301e04c3fSmrgstatic const char *
6401e04c3fSmrgtegra_screen_get_vendor(struct pipe_screen *pscreen)
6501e04c3fSmrg{
6601e04c3fSmrg   return "NVIDIA";
6701e04c3fSmrg}
6801e04c3fSmrg
6901e04c3fSmrgstatic const char *
7001e04c3fSmrgtegra_screen_get_device_vendor(struct pipe_screen *pscreen)
7101e04c3fSmrg{
7201e04c3fSmrg   return "NVIDIA";
7301e04c3fSmrg}
7401e04c3fSmrg
7501e04c3fSmrgstatic int
7601e04c3fSmrgtegra_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
7701e04c3fSmrg{
7801e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
7901e04c3fSmrg
8001e04c3fSmrg   return screen->gpu->get_param(screen->gpu, param);
8101e04c3fSmrg}
8201e04c3fSmrg
8301e04c3fSmrgstatic float
8401e04c3fSmrgtegra_screen_get_paramf(struct pipe_screen *pscreen, enum pipe_capf param)
8501e04c3fSmrg{
8601e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
8701e04c3fSmrg
8801e04c3fSmrg   return screen->gpu->get_paramf(screen->gpu, param);
8901e04c3fSmrg}
9001e04c3fSmrg
9101e04c3fSmrgstatic int
9201e04c3fSmrgtegra_screen_get_shader_param(struct pipe_screen *pscreen, unsigned shader,
9301e04c3fSmrg                              enum pipe_shader_cap param)
9401e04c3fSmrg{
9501e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
9601e04c3fSmrg
9701e04c3fSmrg   return screen->gpu->get_shader_param(screen->gpu, shader, param);
9801e04c3fSmrg}
9901e04c3fSmrg
10001e04c3fSmrgstatic int
10101e04c3fSmrgtegra_screen_get_video_param(struct pipe_screen *pscreen,
10201e04c3fSmrg                             enum pipe_video_profile profile,
10301e04c3fSmrg                             enum pipe_video_entrypoint entrypoint,
10401e04c3fSmrg                             enum pipe_video_cap param)
10501e04c3fSmrg{
10601e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
10701e04c3fSmrg
10801e04c3fSmrg   return screen->gpu->get_video_param(screen->gpu, profile, entrypoint,
10901e04c3fSmrg                                       param);
11001e04c3fSmrg}
11101e04c3fSmrg
11201e04c3fSmrgstatic int
11301e04c3fSmrgtegra_screen_get_compute_param(struct pipe_screen *pscreen,
11401e04c3fSmrg                               enum pipe_shader_ir ir_type,
11501e04c3fSmrg                               enum pipe_compute_cap param,
11601e04c3fSmrg                               void *retp)
11701e04c3fSmrg{
11801e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
11901e04c3fSmrg
12001e04c3fSmrg   return screen->gpu->get_compute_param(screen->gpu, ir_type, param,
12101e04c3fSmrg                                         retp);
12201e04c3fSmrg}
12301e04c3fSmrg
12401e04c3fSmrgstatic uint64_t
12501e04c3fSmrgtegra_screen_get_timestamp(struct pipe_screen *pscreen)
12601e04c3fSmrg{
12701e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
12801e04c3fSmrg
12901e04c3fSmrg   return screen->gpu->get_timestamp(screen->gpu);
13001e04c3fSmrg}
13101e04c3fSmrg
1327ec681f3Smrgstatic bool
13301e04c3fSmrgtegra_screen_is_format_supported(struct pipe_screen *pscreen,
13401e04c3fSmrg                                 enum pipe_format format,
13501e04c3fSmrg                                 enum pipe_texture_target target,
13601e04c3fSmrg                                 unsigned sample_count,
13701e04c3fSmrg                                 unsigned storage_sample_count,
13801e04c3fSmrg                                 unsigned usage)
13901e04c3fSmrg{
14001e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
14101e04c3fSmrg
14201e04c3fSmrg   return screen->gpu->is_format_supported(screen->gpu, format, target,
14301e04c3fSmrg                                           sample_count, storage_sample_count,
14401e04c3fSmrg                                           usage);
14501e04c3fSmrg}
14601e04c3fSmrg
1477ec681f3Smrgstatic bool
14801e04c3fSmrgtegra_screen_is_video_format_supported(struct pipe_screen *pscreen,
14901e04c3fSmrg                                       enum pipe_format format,
15001e04c3fSmrg                                       enum pipe_video_profile profile,
15101e04c3fSmrg                                       enum pipe_video_entrypoint entrypoint)
15201e04c3fSmrg{
15301e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
15401e04c3fSmrg
15501e04c3fSmrg   return screen->gpu->is_video_format_supported(screen->gpu, format, profile,
15601e04c3fSmrg                                                 entrypoint);
15701e04c3fSmrg}
15801e04c3fSmrg
1597ec681f3Smrgstatic bool
16001e04c3fSmrgtegra_screen_can_create_resource(struct pipe_screen *pscreen,
16101e04c3fSmrg                                 const struct pipe_resource *template)
16201e04c3fSmrg{
16301e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
16401e04c3fSmrg
16501e04c3fSmrg   return screen->gpu->can_create_resource(screen->gpu, template);
16601e04c3fSmrg}
16701e04c3fSmrg
16801e04c3fSmrgstatic int tegra_screen_import_resource(struct tegra_screen *screen,
16901e04c3fSmrg                                        struct tegra_resource *resource)
17001e04c3fSmrg{
17101e04c3fSmrg   struct winsys_handle handle;
1727ec681f3Smrg   bool status;
17301e04c3fSmrg   int fd, err;
17401e04c3fSmrg
17501e04c3fSmrg   memset(&handle, 0, sizeof(handle));
17601e04c3fSmrg   handle.modifier = DRM_FORMAT_MOD_INVALID;
17701e04c3fSmrg   handle.type = WINSYS_HANDLE_TYPE_FD;
17801e04c3fSmrg
17901e04c3fSmrg   status = screen->gpu->resource_get_handle(screen->gpu, NULL, resource->gpu,
18001e04c3fSmrg                                             &handle, 0);
18101e04c3fSmrg   if (!status)
18201e04c3fSmrg      return -EINVAL;
18301e04c3fSmrg
18401e04c3fSmrg   assert(handle.modifier != DRM_FORMAT_MOD_INVALID);
18501e04c3fSmrg
18601e04c3fSmrg   if (handle.modifier == DRM_FORMAT_MOD_INVALID) {
18701e04c3fSmrg      close(handle.handle);
18801e04c3fSmrg      return -EINVAL;
18901e04c3fSmrg   }
19001e04c3fSmrg
19101e04c3fSmrg   resource->modifier = handle.modifier;
19201e04c3fSmrg   resource->stride = handle.stride;
19301e04c3fSmrg   fd = handle.handle;
19401e04c3fSmrg
19501e04c3fSmrg   err = drmPrimeFDToHandle(screen->fd, fd, &resource->handle);
19601e04c3fSmrg   if (err < 0)
19701e04c3fSmrg      err = -errno;
19801e04c3fSmrg
19901e04c3fSmrg   close(fd);
20001e04c3fSmrg
20101e04c3fSmrg   return err;
20201e04c3fSmrg}
20301e04c3fSmrg
20401e04c3fSmrgstatic struct pipe_resource *
20501e04c3fSmrgtegra_screen_resource_create(struct pipe_screen *pscreen,
20601e04c3fSmrg                             const struct pipe_resource *template)
20701e04c3fSmrg{
20801e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
20901e04c3fSmrg   uint64_t modifier = DRM_FORMAT_MOD_INVALID;
21001e04c3fSmrg   struct tegra_resource *resource;
21101e04c3fSmrg   int err;
21201e04c3fSmrg
21301e04c3fSmrg   resource = calloc(1, sizeof(*resource));
21401e04c3fSmrg   if (!resource)
21501e04c3fSmrg      return NULL;
21601e04c3fSmrg
21701e04c3fSmrg   /*
21801e04c3fSmrg    * Applications that create scanout resources without modifiers are very
21901e04c3fSmrg    * unlikely to support modifiers at all. In that case the resources need
22001e04c3fSmrg    * to be created with a pitch-linear layout so that they can be properly
22101e04c3fSmrg    * shared with scanout hardware.
22201e04c3fSmrg    *
22301e04c3fSmrg    * Technically it is possible for applications to create resources without
22401e04c3fSmrg    * specifying a modifier but still query the modifier associated with the
22501e04c3fSmrg    * resource (e.g. using gbm_bo_get_modifier()) before handing it to the
22601e04c3fSmrg    * framebuffer creation API (such as the DRM_IOCTL_MODE_ADDFB2 IOCTL).
22701e04c3fSmrg    */
22801e04c3fSmrg   if (template->bind & PIPE_BIND_SCANOUT)
22901e04c3fSmrg      modifier = DRM_FORMAT_MOD_LINEAR;
23001e04c3fSmrg
23101e04c3fSmrg   resource->gpu = screen->gpu->resource_create_with_modifiers(screen->gpu,
23201e04c3fSmrg                                                               template,
23301e04c3fSmrg                                                               &modifier, 1);
23401e04c3fSmrg   if (!resource->gpu)
23501e04c3fSmrg      goto free;
23601e04c3fSmrg
23701e04c3fSmrg   /* import scanout buffers for display */
23801e04c3fSmrg   if (template->bind & PIPE_BIND_SCANOUT) {
23901e04c3fSmrg      err = tegra_screen_import_resource(screen, resource);
24001e04c3fSmrg      if (err < 0)
24101e04c3fSmrg         goto destroy;
24201e04c3fSmrg   }
24301e04c3fSmrg
24401e04c3fSmrg   memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
24501e04c3fSmrg   pipe_reference_init(&resource->base.reference, 1);
24601e04c3fSmrg   resource->base.screen = &screen->base;
24701e04c3fSmrg
2487ec681f3Smrg   /* use private reference count for wrapped resources */
2497ec681f3Smrg   resource->gpu->reference.count += 100000000;
2507ec681f3Smrg   resource->refcount = 100000000;
2517ec681f3Smrg
25201e04c3fSmrg   return &resource->base;
25301e04c3fSmrg
25401e04c3fSmrgdestroy:
25501e04c3fSmrg   screen->gpu->resource_destroy(screen->gpu, resource->gpu);
25601e04c3fSmrgfree:
25701e04c3fSmrg   free(resource);
25801e04c3fSmrg   return NULL;
25901e04c3fSmrg}
26001e04c3fSmrg
26101e04c3fSmrg/* XXX */
26201e04c3fSmrgstatic struct pipe_resource *
26301e04c3fSmrgtegra_screen_resource_create_front(struct pipe_screen *pscreen,
26401e04c3fSmrg                                   const struct pipe_resource *template,
26501e04c3fSmrg                                   const void *map_front_private)
26601e04c3fSmrg{
26701e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
26801e04c3fSmrg   struct pipe_resource *resource;
26901e04c3fSmrg
27001e04c3fSmrg   resource = screen->gpu->resource_create_front(screen->gpu, template,
27101e04c3fSmrg                                                 map_front_private);
27201e04c3fSmrg   if (resource)
27301e04c3fSmrg      resource->screen = pscreen;
27401e04c3fSmrg
27501e04c3fSmrg   return resource;
27601e04c3fSmrg}
27701e04c3fSmrg
27801e04c3fSmrgstatic struct pipe_resource *
27901e04c3fSmrgtegra_screen_resource_from_handle(struct pipe_screen *pscreen,
28001e04c3fSmrg                                  const struct pipe_resource *template,
28101e04c3fSmrg                                  struct winsys_handle *handle,
28201e04c3fSmrg                                  unsigned usage)
28301e04c3fSmrg{
28401e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
28501e04c3fSmrg   struct tegra_resource *resource;
28601e04c3fSmrg
28701e04c3fSmrg   resource = calloc(1, sizeof(*resource));
28801e04c3fSmrg   if (!resource)
28901e04c3fSmrg      return NULL;
29001e04c3fSmrg
29101e04c3fSmrg   resource->gpu = screen->gpu->resource_from_handle(screen->gpu, template,
29201e04c3fSmrg                                                     handle, usage);
29301e04c3fSmrg   if (!resource->gpu) {
29401e04c3fSmrg      free(resource);
29501e04c3fSmrg      return NULL;
29601e04c3fSmrg   }
29701e04c3fSmrg
29801e04c3fSmrg   memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
29901e04c3fSmrg   pipe_reference_init(&resource->base.reference, 1);
30001e04c3fSmrg   resource->base.screen = &screen->base;
30101e04c3fSmrg
30201e04c3fSmrg   return &resource->base;
30301e04c3fSmrg}
30401e04c3fSmrg
30501e04c3fSmrg/* XXX */
30601e04c3fSmrgstatic struct pipe_resource *
30701e04c3fSmrgtegra_screen_resource_from_user_memory(struct pipe_screen *pscreen,
30801e04c3fSmrg                                       const struct pipe_resource *template,
30901e04c3fSmrg                                       void *buffer)
31001e04c3fSmrg{
31101e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
31201e04c3fSmrg   struct pipe_resource *resource;
31301e04c3fSmrg
31401e04c3fSmrg   resource = screen->gpu->resource_from_user_memory(screen->gpu, template,
31501e04c3fSmrg                                                     buffer);
31601e04c3fSmrg   if (resource)
31701e04c3fSmrg      resource->screen = pscreen;
31801e04c3fSmrg
31901e04c3fSmrg   return resource;
32001e04c3fSmrg}
32101e04c3fSmrg
3227ec681f3Smrgstatic bool
32301e04c3fSmrgtegra_screen_resource_get_handle(struct pipe_screen *pscreen,
32401e04c3fSmrg                                 struct pipe_context *pcontext,
32501e04c3fSmrg                                 struct pipe_resource *presource,
32601e04c3fSmrg                                 struct winsys_handle *handle,
32701e04c3fSmrg                                 unsigned usage)
32801e04c3fSmrg{
32901e04c3fSmrg   struct tegra_resource *resource = to_tegra_resource(presource);
33001e04c3fSmrg   struct tegra_context *context = to_tegra_context(pcontext);
33101e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
3327ec681f3Smrg   bool ret = true;
33301e04c3fSmrg
33401e04c3fSmrg   /*
33501e04c3fSmrg    * Assume that KMS handles for scanout resources will only ever be used
33601e04c3fSmrg    * to pass buffers into Tegra DRM for display. In all other cases, return
33701e04c3fSmrg    * the Nouveau handle, assuming they will be used for sharing in DRI2/3.
33801e04c3fSmrg    */
33901e04c3fSmrg   if (handle->type == WINSYS_HANDLE_TYPE_KMS &&
34001e04c3fSmrg       presource->bind & PIPE_BIND_SCANOUT) {
34101e04c3fSmrg      handle->modifier = resource->modifier;
34201e04c3fSmrg      handle->handle = resource->handle;
34301e04c3fSmrg      handle->stride = resource->stride;
34401e04c3fSmrg   } else {
34501e04c3fSmrg      ret = screen->gpu->resource_get_handle(screen->gpu,
34601e04c3fSmrg                                             context ? context->gpu : NULL,
34701e04c3fSmrg                                             resource->gpu, handle, usage);
34801e04c3fSmrg   }
34901e04c3fSmrg
35001e04c3fSmrg   return ret;
35101e04c3fSmrg}
35201e04c3fSmrg
35301e04c3fSmrgstatic void
35401e04c3fSmrgtegra_screen_resource_destroy(struct pipe_screen *pscreen,
35501e04c3fSmrg                              struct pipe_resource *presource)
35601e04c3fSmrg{
35701e04c3fSmrg   struct tegra_resource *resource = to_tegra_resource(presource);
35801e04c3fSmrg
3597ec681f3Smrg   /* adjust private reference count */
3607ec681f3Smrg   p_atomic_add(&resource->gpu->reference.count, -resource->refcount);
36101e04c3fSmrg   pipe_resource_reference(&resource->gpu, NULL);
36201e04c3fSmrg   free(resource);
36301e04c3fSmrg}
36401e04c3fSmrg
36501e04c3fSmrgstatic void
36601e04c3fSmrgtegra_screen_flush_frontbuffer(struct pipe_screen *pscreen,
3677ec681f3Smrg                               struct pipe_context *pcontext,
36801e04c3fSmrg                               struct pipe_resource *resource,
36901e04c3fSmrg                               unsigned int level,
37001e04c3fSmrg                               unsigned int layer,
37101e04c3fSmrg                               void *winsys_drawable_handle,
37201e04c3fSmrg                               struct pipe_box *box)
37301e04c3fSmrg{
37401e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
3757ec681f3Smrg   struct tegra_context *context = to_tegra_context(pcontext);
37601e04c3fSmrg
3777ec681f3Smrg   screen->gpu->flush_frontbuffer(screen->gpu,
3787ec681f3Smrg                                  context ? context->gpu : NULL,
3797ec681f3Smrg                                  resource, level, layer,
38001e04c3fSmrg                                  winsys_drawable_handle, box);
38101e04c3fSmrg}
38201e04c3fSmrg
38301e04c3fSmrgstatic void
38401e04c3fSmrgtegra_screen_fence_reference(struct pipe_screen *pscreen,
38501e04c3fSmrg                             struct pipe_fence_handle **ptr,
38601e04c3fSmrg                             struct pipe_fence_handle *fence)
38701e04c3fSmrg{
38801e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
38901e04c3fSmrg
39001e04c3fSmrg   screen->gpu->fence_reference(screen->gpu, ptr, fence);
39101e04c3fSmrg}
39201e04c3fSmrg
3937ec681f3Smrgstatic bool
39401e04c3fSmrgtegra_screen_fence_finish(struct pipe_screen *pscreen,
39501e04c3fSmrg                          struct pipe_context *pcontext,
39601e04c3fSmrg                          struct pipe_fence_handle *fence,
39701e04c3fSmrg                          uint64_t timeout)
39801e04c3fSmrg{
39901e04c3fSmrg   struct tegra_context *context = to_tegra_context(pcontext);
40001e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
40101e04c3fSmrg
40201e04c3fSmrg   return screen->gpu->fence_finish(screen->gpu,
40301e04c3fSmrg                                    context ? context->gpu : NULL,
40401e04c3fSmrg                                    fence, timeout);
40501e04c3fSmrg}
40601e04c3fSmrg
40701e04c3fSmrgstatic int
40801e04c3fSmrgtegra_screen_fence_get_fd(struct pipe_screen *pscreen,
40901e04c3fSmrg                          struct pipe_fence_handle *fence)
41001e04c3fSmrg{
41101e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
41201e04c3fSmrg
41301e04c3fSmrg   return screen->gpu->fence_get_fd(screen->gpu, fence);
41401e04c3fSmrg}
41501e04c3fSmrg
41601e04c3fSmrgstatic int
41701e04c3fSmrgtegra_screen_get_driver_query_info(struct pipe_screen *pscreen,
41801e04c3fSmrg                                   unsigned int index,
41901e04c3fSmrg                                   struct pipe_driver_query_info *info)
42001e04c3fSmrg{
42101e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
42201e04c3fSmrg
42301e04c3fSmrg   return screen->gpu->get_driver_query_info(screen->gpu, index, info);
42401e04c3fSmrg}
42501e04c3fSmrg
42601e04c3fSmrgstatic int
42701e04c3fSmrgtegra_screen_get_driver_query_group_info(struct pipe_screen *pscreen,
42801e04c3fSmrg                                         unsigned int index,
42901e04c3fSmrg                                         struct pipe_driver_query_group_info *info)
43001e04c3fSmrg{
43101e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
43201e04c3fSmrg
43301e04c3fSmrg   return screen->gpu->get_driver_query_group_info(screen->gpu, index, info);
43401e04c3fSmrg}
43501e04c3fSmrg
43601e04c3fSmrgstatic void
43701e04c3fSmrgtegra_screen_query_memory_info(struct pipe_screen *pscreen,
43801e04c3fSmrg                               struct pipe_memory_info *info)
43901e04c3fSmrg{
44001e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
44101e04c3fSmrg
44201e04c3fSmrg   screen->gpu->query_memory_info(screen->gpu, info);
44301e04c3fSmrg}
44401e04c3fSmrg
44501e04c3fSmrgstatic const void *
44601e04c3fSmrgtegra_screen_get_compiler_options(struct pipe_screen *pscreen,
44701e04c3fSmrg                                  enum pipe_shader_ir ir,
44801e04c3fSmrg                                  unsigned int shader)
44901e04c3fSmrg{
45001e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
45101e04c3fSmrg   const void *options = NULL;
45201e04c3fSmrg
45301e04c3fSmrg   if (screen->gpu->get_compiler_options)
45401e04c3fSmrg      options = screen->gpu->get_compiler_options(screen->gpu, ir, shader);
45501e04c3fSmrg
45601e04c3fSmrg   return options;
45701e04c3fSmrg}
45801e04c3fSmrg
45901e04c3fSmrgstatic struct disk_cache *
46001e04c3fSmrgtegra_screen_get_disk_shader_cache(struct pipe_screen *pscreen)
46101e04c3fSmrg{
46201e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
46301e04c3fSmrg
46401e04c3fSmrg   return screen->gpu->get_disk_shader_cache(screen->gpu);
46501e04c3fSmrg}
46601e04c3fSmrg
46701e04c3fSmrgstatic struct pipe_resource *
46801e04c3fSmrgtegra_screen_resource_create_with_modifiers(struct pipe_screen *pscreen,
46901e04c3fSmrg                                            const struct pipe_resource *template,
47001e04c3fSmrg                                            const uint64_t *modifiers,
47101e04c3fSmrg                                            int count)
47201e04c3fSmrg{
47301e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
47401e04c3fSmrg   struct pipe_resource tmpl = *template;
47501e04c3fSmrg   struct tegra_resource *resource;
47601e04c3fSmrg   int err;
47701e04c3fSmrg
47801e04c3fSmrg   resource = calloc(1, sizeof(*resource));
47901e04c3fSmrg   if (!resource)
48001e04c3fSmrg      return NULL;
48101e04c3fSmrg
48201e04c3fSmrg   /*
48301e04c3fSmrg    * Assume that resources created with modifiers will always be used for
48401e04c3fSmrg    * scanout. This is necessary because some of the APIs that are used to
48501e04c3fSmrg    * create resources with modifiers (e.g. gbm_bo_create_with_modifiers())
48601e04c3fSmrg    * can't pass along usage information. Adding that capability might be
48701e04c3fSmrg    * worth adding to remove this ambiguity. Not all future use-cases that
48801e04c3fSmrg    * involve modifiers may always be targetting scanout hardware.
48901e04c3fSmrg    */
49001e04c3fSmrg   tmpl.bind |= PIPE_BIND_SCANOUT;
49101e04c3fSmrg
49201e04c3fSmrg   resource->gpu = screen->gpu->resource_create_with_modifiers(screen->gpu,
49301e04c3fSmrg                                                               &tmpl,
49401e04c3fSmrg                                                               modifiers,
49501e04c3fSmrg                                                               count);
49601e04c3fSmrg   if (!resource->gpu)
49701e04c3fSmrg      goto free;
49801e04c3fSmrg
49901e04c3fSmrg   err = tegra_screen_import_resource(screen, resource);
50001e04c3fSmrg   if (err < 0)
50101e04c3fSmrg      goto destroy;
50201e04c3fSmrg
50301e04c3fSmrg   memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
50401e04c3fSmrg   pipe_reference_init(&resource->base.reference, 1);
50501e04c3fSmrg   resource->base.screen = &screen->base;
50601e04c3fSmrg
50701e04c3fSmrg   return &resource->base;
50801e04c3fSmrg
50901e04c3fSmrgdestroy:
51001e04c3fSmrg   screen->gpu->resource_destroy(screen->gpu, resource->gpu);
51101e04c3fSmrgfree:
51201e04c3fSmrg   free(resource);
51301e04c3fSmrg   return NULL;
51401e04c3fSmrg}
51501e04c3fSmrg
51601e04c3fSmrgstatic void tegra_screen_query_dmabuf_modifiers(struct pipe_screen *pscreen,
51701e04c3fSmrg                                                enum pipe_format format,
51801e04c3fSmrg                                                int max, uint64_t *modifiers,
51901e04c3fSmrg                                                unsigned int *external_only,
52001e04c3fSmrg                                                int *count)
52101e04c3fSmrg{
52201e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
52301e04c3fSmrg
52401e04c3fSmrg   screen->gpu->query_dmabuf_modifiers(screen->gpu, format, max, modifiers,
52501e04c3fSmrg                                       external_only, count);
52601e04c3fSmrg}
52701e04c3fSmrg
5287ec681f3Smrgstatic bool
5297ec681f3Smrgtegra_screen_is_dmabuf_modifier_supported(struct pipe_screen *pscreen,
5307ec681f3Smrg                                          uint64_t modifier,
5317ec681f3Smrg                                          enum pipe_format format,
5327ec681f3Smrg                                          bool *external_only)
5337ec681f3Smrg{
5347ec681f3Smrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
5357ec681f3Smrg
5367ec681f3Smrg   return screen->gpu->is_dmabuf_modifier_supported(screen->gpu, modifier,
5377ec681f3Smrg                                                    format, external_only);
5387ec681f3Smrg}
5397ec681f3Smrg
5407ec681f3Smrgstatic unsigned int
5417ec681f3Smrgtegra_screen_get_dmabuf_modifier_planes(struct pipe_screen *pscreen,
5427ec681f3Smrg                                        uint64_t modifier,
5437ec681f3Smrg                                        enum pipe_format format)
5447ec681f3Smrg{
5457ec681f3Smrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
5467ec681f3Smrg
5477ec681f3Smrg   return screen->gpu->get_dmabuf_modifier_planes ?
5487ec681f3Smrg      screen->gpu->get_dmabuf_modifier_planes(screen->gpu, modifier, format) :
5497ec681f3Smrg      util_format_get_num_planes(format);
5507ec681f3Smrg}
5517ec681f3Smrg
55201e04c3fSmrgstatic struct pipe_memory_object *
55301e04c3fSmrgtegra_screen_memobj_create_from_handle(struct pipe_screen *pscreen,
55401e04c3fSmrg                                       struct winsys_handle *handle,
55501e04c3fSmrg                                       bool dedicated)
55601e04c3fSmrg{
55701e04c3fSmrg   struct tegra_screen *screen = to_tegra_screen(pscreen);
55801e04c3fSmrg
55901e04c3fSmrg   return screen->gpu->memobj_create_from_handle(screen->gpu, handle,
56001e04c3fSmrg                                                 dedicated);
56101e04c3fSmrg}
56201e04c3fSmrg
56301e04c3fSmrgstruct pipe_screen *
56401e04c3fSmrgtegra_screen_create(int fd)
56501e04c3fSmrg{
56601e04c3fSmrg   struct tegra_screen *screen;
56701e04c3fSmrg
56801e04c3fSmrg   screen = calloc(1, sizeof(*screen));
56901e04c3fSmrg   if (!screen)
57001e04c3fSmrg      return NULL;
57101e04c3fSmrg
57201e04c3fSmrg   screen->fd = fd;
57301e04c3fSmrg
57401e04c3fSmrg   screen->gpu_fd = loader_open_render_node("nouveau");
57501e04c3fSmrg   if (screen->gpu_fd < 0) {
57601e04c3fSmrg      if (errno != ENOENT)
57701e04c3fSmrg         fprintf(stderr, "failed to open GPU device: %s\n", strerror(errno));
57801e04c3fSmrg
57901e04c3fSmrg      free(screen);
58001e04c3fSmrg      return NULL;
58101e04c3fSmrg   }
58201e04c3fSmrg
58301e04c3fSmrg   screen->gpu = nouveau_drm_screen_create(screen->gpu_fd);
58401e04c3fSmrg   if (!screen->gpu) {
58501e04c3fSmrg      fprintf(stderr, "failed to create GPU screen\n");
58601e04c3fSmrg      close(screen->gpu_fd);
58701e04c3fSmrg      free(screen);
58801e04c3fSmrg      return NULL;
58901e04c3fSmrg   }
59001e04c3fSmrg
59101e04c3fSmrg   screen->base.destroy = tegra_screen_destroy;
59201e04c3fSmrg   screen->base.get_name = tegra_screen_get_name;
59301e04c3fSmrg   screen->base.get_vendor = tegra_screen_get_vendor;
59401e04c3fSmrg   screen->base.get_device_vendor = tegra_screen_get_device_vendor;
59501e04c3fSmrg   screen->base.get_param = tegra_screen_get_param;
59601e04c3fSmrg   screen->base.get_paramf = tegra_screen_get_paramf;
59701e04c3fSmrg   screen->base.get_shader_param = tegra_screen_get_shader_param;
59801e04c3fSmrg   screen->base.get_video_param = tegra_screen_get_video_param;
59901e04c3fSmrg   screen->base.get_compute_param = tegra_screen_get_compute_param;
60001e04c3fSmrg   screen->base.get_timestamp = tegra_screen_get_timestamp;
60101e04c3fSmrg   screen->base.context_create = tegra_screen_context_create;
60201e04c3fSmrg   screen->base.is_format_supported = tegra_screen_is_format_supported;
60301e04c3fSmrg   screen->base.is_video_format_supported = tegra_screen_is_video_format_supported;
60401e04c3fSmrg
60501e04c3fSmrg   /* allow fallback implementation if GPU driver doesn't implement it */
60601e04c3fSmrg   if (screen->gpu->can_create_resource)
60701e04c3fSmrg      screen->base.can_create_resource = tegra_screen_can_create_resource;
60801e04c3fSmrg
60901e04c3fSmrg   screen->base.resource_create = tegra_screen_resource_create;
61001e04c3fSmrg   screen->base.resource_create_front = tegra_screen_resource_create_front;
61101e04c3fSmrg   screen->base.resource_from_handle = tegra_screen_resource_from_handle;
61201e04c3fSmrg   screen->base.resource_from_user_memory = tegra_screen_resource_from_user_memory;
61301e04c3fSmrg   screen->base.resource_get_handle = tegra_screen_resource_get_handle;
61401e04c3fSmrg   screen->base.resource_destroy = tegra_screen_resource_destroy;
61501e04c3fSmrg
61601e04c3fSmrg   screen->base.flush_frontbuffer = tegra_screen_flush_frontbuffer;
61701e04c3fSmrg   screen->base.fence_reference = tegra_screen_fence_reference;
61801e04c3fSmrg   screen->base.fence_finish = tegra_screen_fence_finish;
61901e04c3fSmrg   screen->base.fence_get_fd = tegra_screen_fence_get_fd;
62001e04c3fSmrg
62101e04c3fSmrg   screen->base.get_driver_query_info = tegra_screen_get_driver_query_info;
62201e04c3fSmrg   screen->base.get_driver_query_group_info = tegra_screen_get_driver_query_group_info;
62301e04c3fSmrg   screen->base.query_memory_info = tegra_screen_query_memory_info;
62401e04c3fSmrg
62501e04c3fSmrg   screen->base.get_compiler_options = tegra_screen_get_compiler_options;
62601e04c3fSmrg   screen->base.get_disk_shader_cache = tegra_screen_get_disk_shader_cache;
62701e04c3fSmrg
62801e04c3fSmrg   screen->base.resource_create_with_modifiers = tegra_screen_resource_create_with_modifiers;
62901e04c3fSmrg   screen->base.query_dmabuf_modifiers = tegra_screen_query_dmabuf_modifiers;
6307ec681f3Smrg   screen->base.is_dmabuf_modifier_supported = tegra_screen_is_dmabuf_modifier_supported;
6317ec681f3Smrg   screen->base.get_dmabuf_modifier_planes = tegra_screen_get_dmabuf_modifier_planes;
63201e04c3fSmrg   screen->base.memobj_create_from_handle = tegra_screen_memobj_create_from_handle;
63301e04c3fSmrg
63401e04c3fSmrg   return &screen->base;
63501e04c3fSmrg}
636