1/*
2 * Copyright © 2014-2018 NVIDIA Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24#include <errno.h>
25#include <fcntl.h>
26#include <inttypes.h>
27#include <stdio.h>
28
29#include <sys/stat.h>
30
31#include "drm-uapi/drm_fourcc.h"
32#include "drm-uapi/tegra_drm.h"
33#include <xf86drm.h>
34
35#include "loader/loader.h"
36#include "pipe/p_state.h"
37#include "util/u_debug.h"
38#include "util/format/u_format.h"
39#include "util/u_inlines.h"
40
41#include "frontend/drm_driver.h"
42
43#include "nouveau/drm/nouveau_drm_public.h"
44
45#include "tegra_context.h"
46#include "tegra_resource.h"
47#include "tegra_screen.h"
48
49static void tegra_screen_destroy(struct pipe_screen *pscreen)
50{
51   struct tegra_screen *screen = to_tegra_screen(pscreen);
52
53   screen->gpu->destroy(screen->gpu);
54   free(pscreen);
55}
56
57static const char *
58tegra_screen_get_name(struct pipe_screen *pscreen)
59{
60   return "tegra";
61}
62
63static const char *
64tegra_screen_get_vendor(struct pipe_screen *pscreen)
65{
66   return "NVIDIA";
67}
68
69static const char *
70tegra_screen_get_device_vendor(struct pipe_screen *pscreen)
71{
72   return "NVIDIA";
73}
74
75static int
76tegra_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
77{
78   struct tegra_screen *screen = to_tegra_screen(pscreen);
79
80   return screen->gpu->get_param(screen->gpu, param);
81}
82
83static float
84tegra_screen_get_paramf(struct pipe_screen *pscreen, enum pipe_capf param)
85{
86   struct tegra_screen *screen = to_tegra_screen(pscreen);
87
88   return screen->gpu->get_paramf(screen->gpu, param);
89}
90
91static int
92tegra_screen_get_shader_param(struct pipe_screen *pscreen, unsigned shader,
93                              enum pipe_shader_cap param)
94{
95   struct tegra_screen *screen = to_tegra_screen(pscreen);
96
97   return screen->gpu->get_shader_param(screen->gpu, shader, param);
98}
99
100static int
101tegra_screen_get_video_param(struct pipe_screen *pscreen,
102                             enum pipe_video_profile profile,
103                             enum pipe_video_entrypoint entrypoint,
104                             enum pipe_video_cap param)
105{
106   struct tegra_screen *screen = to_tegra_screen(pscreen);
107
108   return screen->gpu->get_video_param(screen->gpu, profile, entrypoint,
109                                       param);
110}
111
112static int
113tegra_screen_get_compute_param(struct pipe_screen *pscreen,
114                               enum pipe_shader_ir ir_type,
115                               enum pipe_compute_cap param,
116                               void *retp)
117{
118   struct tegra_screen *screen = to_tegra_screen(pscreen);
119
120   return screen->gpu->get_compute_param(screen->gpu, ir_type, param,
121                                         retp);
122}
123
124static uint64_t
125tegra_screen_get_timestamp(struct pipe_screen *pscreen)
126{
127   struct tegra_screen *screen = to_tegra_screen(pscreen);
128
129   return screen->gpu->get_timestamp(screen->gpu);
130}
131
132static bool
133tegra_screen_is_format_supported(struct pipe_screen *pscreen,
134                                 enum pipe_format format,
135                                 enum pipe_texture_target target,
136                                 unsigned sample_count,
137                                 unsigned storage_sample_count,
138                                 unsigned usage)
139{
140   struct tegra_screen *screen = to_tegra_screen(pscreen);
141
142   return screen->gpu->is_format_supported(screen->gpu, format, target,
143                                           sample_count, storage_sample_count,
144                                           usage);
145}
146
147static bool
148tegra_screen_is_video_format_supported(struct pipe_screen *pscreen,
149                                       enum pipe_format format,
150                                       enum pipe_video_profile profile,
151                                       enum pipe_video_entrypoint entrypoint)
152{
153   struct tegra_screen *screen = to_tegra_screen(pscreen);
154
155   return screen->gpu->is_video_format_supported(screen->gpu, format, profile,
156                                                 entrypoint);
157}
158
159static bool
160tegra_screen_can_create_resource(struct pipe_screen *pscreen,
161                                 const struct pipe_resource *template)
162{
163   struct tegra_screen *screen = to_tegra_screen(pscreen);
164
165   return screen->gpu->can_create_resource(screen->gpu, template);
166}
167
168static int tegra_screen_import_resource(struct tegra_screen *screen,
169                                        struct tegra_resource *resource)
170{
171   struct winsys_handle handle;
172   bool status;
173   int fd, err;
174
175   memset(&handle, 0, sizeof(handle));
176   handle.modifier = DRM_FORMAT_MOD_INVALID;
177   handle.type = WINSYS_HANDLE_TYPE_FD;
178
179   status = screen->gpu->resource_get_handle(screen->gpu, NULL, resource->gpu,
180                                             &handle, 0);
181   if (!status)
182      return -EINVAL;
183
184   assert(handle.modifier != DRM_FORMAT_MOD_INVALID);
185
186   if (handle.modifier == DRM_FORMAT_MOD_INVALID) {
187      close(handle.handle);
188      return -EINVAL;
189   }
190
191   resource->modifier = handle.modifier;
192   resource->stride = handle.stride;
193   fd = handle.handle;
194
195   err = drmPrimeFDToHandle(screen->fd, fd, &resource->handle);
196   if (err < 0)
197      err = -errno;
198
199   close(fd);
200
201   return err;
202}
203
204static struct pipe_resource *
205tegra_screen_resource_create(struct pipe_screen *pscreen,
206                             const struct pipe_resource *template)
207{
208   struct tegra_screen *screen = to_tegra_screen(pscreen);
209   uint64_t modifier = DRM_FORMAT_MOD_INVALID;
210   struct tegra_resource *resource;
211   int err;
212
213   resource = calloc(1, sizeof(*resource));
214   if (!resource)
215      return NULL;
216
217   /*
218    * Applications that create scanout resources without modifiers are very
219    * unlikely to support modifiers at all. In that case the resources need
220    * to be created with a pitch-linear layout so that they can be properly
221    * shared with scanout hardware.
222    *
223    * Technically it is possible for applications to create resources without
224    * specifying a modifier but still query the modifier associated with the
225    * resource (e.g. using gbm_bo_get_modifier()) before handing it to the
226    * framebuffer creation API (such as the DRM_IOCTL_MODE_ADDFB2 IOCTL).
227    */
228   if (template->bind & PIPE_BIND_SCANOUT)
229      modifier = DRM_FORMAT_MOD_LINEAR;
230
231   resource->gpu = screen->gpu->resource_create_with_modifiers(screen->gpu,
232                                                               template,
233                                                               &modifier, 1);
234   if (!resource->gpu)
235      goto free;
236
237   /* import scanout buffers for display */
238   if (template->bind & PIPE_BIND_SCANOUT) {
239      err = tegra_screen_import_resource(screen, resource);
240      if (err < 0)
241         goto destroy;
242   }
243
244   memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
245   pipe_reference_init(&resource->base.reference, 1);
246   resource->base.screen = &screen->base;
247
248   /* use private reference count for wrapped resources */
249   resource->gpu->reference.count += 100000000;
250   resource->refcount = 100000000;
251
252   return &resource->base;
253
254destroy:
255   screen->gpu->resource_destroy(screen->gpu, resource->gpu);
256free:
257   free(resource);
258   return NULL;
259}
260
261/* XXX */
262static struct pipe_resource *
263tegra_screen_resource_create_front(struct pipe_screen *pscreen,
264                                   const struct pipe_resource *template,
265                                   const void *map_front_private)
266{
267   struct tegra_screen *screen = to_tegra_screen(pscreen);
268   struct pipe_resource *resource;
269
270   resource = screen->gpu->resource_create_front(screen->gpu, template,
271                                                 map_front_private);
272   if (resource)
273      resource->screen = pscreen;
274
275   return resource;
276}
277
278static struct pipe_resource *
279tegra_screen_resource_from_handle(struct pipe_screen *pscreen,
280                                  const struct pipe_resource *template,
281                                  struct winsys_handle *handle,
282                                  unsigned usage)
283{
284   struct tegra_screen *screen = to_tegra_screen(pscreen);
285   struct tegra_resource *resource;
286
287   resource = calloc(1, sizeof(*resource));
288   if (!resource)
289      return NULL;
290
291   resource->gpu = screen->gpu->resource_from_handle(screen->gpu, template,
292                                                     handle, usage);
293   if (!resource->gpu) {
294      free(resource);
295      return NULL;
296   }
297
298   memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
299   pipe_reference_init(&resource->base.reference, 1);
300   resource->base.screen = &screen->base;
301
302   return &resource->base;
303}
304
305/* XXX */
306static struct pipe_resource *
307tegra_screen_resource_from_user_memory(struct pipe_screen *pscreen,
308                                       const struct pipe_resource *template,
309                                       void *buffer)
310{
311   struct tegra_screen *screen = to_tegra_screen(pscreen);
312   struct pipe_resource *resource;
313
314   resource = screen->gpu->resource_from_user_memory(screen->gpu, template,
315                                                     buffer);
316   if (resource)
317      resource->screen = pscreen;
318
319   return resource;
320}
321
322static bool
323tegra_screen_resource_get_handle(struct pipe_screen *pscreen,
324                                 struct pipe_context *pcontext,
325                                 struct pipe_resource *presource,
326                                 struct winsys_handle *handle,
327                                 unsigned usage)
328{
329   struct tegra_resource *resource = to_tegra_resource(presource);
330   struct tegra_context *context = to_tegra_context(pcontext);
331   struct tegra_screen *screen = to_tegra_screen(pscreen);
332   bool ret = true;
333
334   /*
335    * Assume that KMS handles for scanout resources will only ever be used
336    * to pass buffers into Tegra DRM for display. In all other cases, return
337    * the Nouveau handle, assuming they will be used for sharing in DRI2/3.
338    */
339   if (handle->type == WINSYS_HANDLE_TYPE_KMS &&
340       presource->bind & PIPE_BIND_SCANOUT) {
341      handle->modifier = resource->modifier;
342      handle->handle = resource->handle;
343      handle->stride = resource->stride;
344   } else {
345      ret = screen->gpu->resource_get_handle(screen->gpu,
346                                             context ? context->gpu : NULL,
347                                             resource->gpu, handle, usage);
348   }
349
350   return ret;
351}
352
353static void
354tegra_screen_resource_destroy(struct pipe_screen *pscreen,
355                              struct pipe_resource *presource)
356{
357   struct tegra_resource *resource = to_tegra_resource(presource);
358
359   /* adjust private reference count */
360   p_atomic_add(&resource->gpu->reference.count, -resource->refcount);
361   pipe_resource_reference(&resource->gpu, NULL);
362   free(resource);
363}
364
365static void
366tegra_screen_flush_frontbuffer(struct pipe_screen *pscreen,
367                               struct pipe_context *pcontext,
368                               struct pipe_resource *resource,
369                               unsigned int level,
370                               unsigned int layer,
371                               void *winsys_drawable_handle,
372                               struct pipe_box *box)
373{
374   struct tegra_screen *screen = to_tegra_screen(pscreen);
375   struct tegra_context *context = to_tegra_context(pcontext);
376
377   screen->gpu->flush_frontbuffer(screen->gpu,
378                                  context ? context->gpu : NULL,
379                                  resource, level, layer,
380                                  winsys_drawable_handle, box);
381}
382
383static void
384tegra_screen_fence_reference(struct pipe_screen *pscreen,
385                             struct pipe_fence_handle **ptr,
386                             struct pipe_fence_handle *fence)
387{
388   struct tegra_screen *screen = to_tegra_screen(pscreen);
389
390   screen->gpu->fence_reference(screen->gpu, ptr, fence);
391}
392
393static bool
394tegra_screen_fence_finish(struct pipe_screen *pscreen,
395                          struct pipe_context *pcontext,
396                          struct pipe_fence_handle *fence,
397                          uint64_t timeout)
398{
399   struct tegra_context *context = to_tegra_context(pcontext);
400   struct tegra_screen *screen = to_tegra_screen(pscreen);
401
402   return screen->gpu->fence_finish(screen->gpu,
403                                    context ? context->gpu : NULL,
404                                    fence, timeout);
405}
406
407static int
408tegra_screen_fence_get_fd(struct pipe_screen *pscreen,
409                          struct pipe_fence_handle *fence)
410{
411   struct tegra_screen *screen = to_tegra_screen(pscreen);
412
413   return screen->gpu->fence_get_fd(screen->gpu, fence);
414}
415
416static int
417tegra_screen_get_driver_query_info(struct pipe_screen *pscreen,
418                                   unsigned int index,
419                                   struct pipe_driver_query_info *info)
420{
421   struct tegra_screen *screen = to_tegra_screen(pscreen);
422
423   return screen->gpu->get_driver_query_info(screen->gpu, index, info);
424}
425
426static int
427tegra_screen_get_driver_query_group_info(struct pipe_screen *pscreen,
428                                         unsigned int index,
429                                         struct pipe_driver_query_group_info *info)
430{
431   struct tegra_screen *screen = to_tegra_screen(pscreen);
432
433   return screen->gpu->get_driver_query_group_info(screen->gpu, index, info);
434}
435
436static void
437tegra_screen_query_memory_info(struct pipe_screen *pscreen,
438                               struct pipe_memory_info *info)
439{
440   struct tegra_screen *screen = to_tegra_screen(pscreen);
441
442   screen->gpu->query_memory_info(screen->gpu, info);
443}
444
445static const void *
446tegra_screen_get_compiler_options(struct pipe_screen *pscreen,
447                                  enum pipe_shader_ir ir,
448                                  unsigned int shader)
449{
450   struct tegra_screen *screen = to_tegra_screen(pscreen);
451   const void *options = NULL;
452
453   if (screen->gpu->get_compiler_options)
454      options = screen->gpu->get_compiler_options(screen->gpu, ir, shader);
455
456   return options;
457}
458
459static struct disk_cache *
460tegra_screen_get_disk_shader_cache(struct pipe_screen *pscreen)
461{
462   struct tegra_screen *screen = to_tegra_screen(pscreen);
463
464   return screen->gpu->get_disk_shader_cache(screen->gpu);
465}
466
467static struct pipe_resource *
468tegra_screen_resource_create_with_modifiers(struct pipe_screen *pscreen,
469                                            const struct pipe_resource *template,
470                                            const uint64_t *modifiers,
471                                            int count)
472{
473   struct tegra_screen *screen = to_tegra_screen(pscreen);
474   struct pipe_resource tmpl = *template;
475   struct tegra_resource *resource;
476   int err;
477
478   resource = calloc(1, sizeof(*resource));
479   if (!resource)
480      return NULL;
481
482   /*
483    * Assume that resources created with modifiers will always be used for
484    * scanout. This is necessary because some of the APIs that are used to
485    * create resources with modifiers (e.g. gbm_bo_create_with_modifiers())
486    * can't pass along usage information. Adding that capability might be
487    * worth adding to remove this ambiguity. Not all future use-cases that
488    * involve modifiers may always be targetting scanout hardware.
489    */
490   tmpl.bind |= PIPE_BIND_SCANOUT;
491
492   resource->gpu = screen->gpu->resource_create_with_modifiers(screen->gpu,
493                                                               &tmpl,
494                                                               modifiers,
495                                                               count);
496   if (!resource->gpu)
497      goto free;
498
499   err = tegra_screen_import_resource(screen, resource);
500   if (err < 0)
501      goto destroy;
502
503   memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
504   pipe_reference_init(&resource->base.reference, 1);
505   resource->base.screen = &screen->base;
506
507   return &resource->base;
508
509destroy:
510   screen->gpu->resource_destroy(screen->gpu, resource->gpu);
511free:
512   free(resource);
513   return NULL;
514}
515
516static void tegra_screen_query_dmabuf_modifiers(struct pipe_screen *pscreen,
517                                                enum pipe_format format,
518                                                int max, uint64_t *modifiers,
519                                                unsigned int *external_only,
520                                                int *count)
521{
522   struct tegra_screen *screen = to_tegra_screen(pscreen);
523
524   screen->gpu->query_dmabuf_modifiers(screen->gpu, format, max, modifiers,
525                                       external_only, count);
526}
527
528static bool
529tegra_screen_is_dmabuf_modifier_supported(struct pipe_screen *pscreen,
530                                          uint64_t modifier,
531                                          enum pipe_format format,
532                                          bool *external_only)
533{
534   struct tegra_screen *screen = to_tegra_screen(pscreen);
535
536   return screen->gpu->is_dmabuf_modifier_supported(screen->gpu, modifier,
537                                                    format, external_only);
538}
539
540static unsigned int
541tegra_screen_get_dmabuf_modifier_planes(struct pipe_screen *pscreen,
542                                        uint64_t modifier,
543                                        enum pipe_format format)
544{
545   struct tegra_screen *screen = to_tegra_screen(pscreen);
546
547   return screen->gpu->get_dmabuf_modifier_planes ?
548      screen->gpu->get_dmabuf_modifier_planes(screen->gpu, modifier, format) :
549      util_format_get_num_planes(format);
550}
551
552static struct pipe_memory_object *
553tegra_screen_memobj_create_from_handle(struct pipe_screen *pscreen,
554                                       struct winsys_handle *handle,
555                                       bool dedicated)
556{
557   struct tegra_screen *screen = to_tegra_screen(pscreen);
558
559   return screen->gpu->memobj_create_from_handle(screen->gpu, handle,
560                                                 dedicated);
561}
562
563struct pipe_screen *
564tegra_screen_create(int fd)
565{
566   struct tegra_screen *screen;
567
568   screen = calloc(1, sizeof(*screen));
569   if (!screen)
570      return NULL;
571
572   screen->fd = fd;
573
574   screen->gpu_fd = loader_open_render_node("nouveau");
575   if (screen->gpu_fd < 0) {
576      if (errno != ENOENT)
577         fprintf(stderr, "failed to open GPU device: %s\n", strerror(errno));
578
579      free(screen);
580      return NULL;
581   }
582
583   screen->gpu = nouveau_drm_screen_create(screen->gpu_fd);
584   if (!screen->gpu) {
585      fprintf(stderr, "failed to create GPU screen\n");
586      close(screen->gpu_fd);
587      free(screen);
588      return NULL;
589   }
590
591   screen->base.destroy = tegra_screen_destroy;
592   screen->base.get_name = tegra_screen_get_name;
593   screen->base.get_vendor = tegra_screen_get_vendor;
594   screen->base.get_device_vendor = tegra_screen_get_device_vendor;
595   screen->base.get_param = tegra_screen_get_param;
596   screen->base.get_paramf = tegra_screen_get_paramf;
597   screen->base.get_shader_param = tegra_screen_get_shader_param;
598   screen->base.get_video_param = tegra_screen_get_video_param;
599   screen->base.get_compute_param = tegra_screen_get_compute_param;
600   screen->base.get_timestamp = tegra_screen_get_timestamp;
601   screen->base.context_create = tegra_screen_context_create;
602   screen->base.is_format_supported = tegra_screen_is_format_supported;
603   screen->base.is_video_format_supported = tegra_screen_is_video_format_supported;
604
605   /* allow fallback implementation if GPU driver doesn't implement it */
606   if (screen->gpu->can_create_resource)
607      screen->base.can_create_resource = tegra_screen_can_create_resource;
608
609   screen->base.resource_create = tegra_screen_resource_create;
610   screen->base.resource_create_front = tegra_screen_resource_create_front;
611   screen->base.resource_from_handle = tegra_screen_resource_from_handle;
612   screen->base.resource_from_user_memory = tegra_screen_resource_from_user_memory;
613   screen->base.resource_get_handle = tegra_screen_resource_get_handle;
614   screen->base.resource_destroy = tegra_screen_resource_destroy;
615
616   screen->base.flush_frontbuffer = tegra_screen_flush_frontbuffer;
617   screen->base.fence_reference = tegra_screen_fence_reference;
618   screen->base.fence_finish = tegra_screen_fence_finish;
619   screen->base.fence_get_fd = tegra_screen_fence_get_fd;
620
621   screen->base.get_driver_query_info = tegra_screen_get_driver_query_info;
622   screen->base.get_driver_query_group_info = tegra_screen_get_driver_query_group_info;
623   screen->base.query_memory_info = tegra_screen_query_memory_info;
624
625   screen->base.get_compiler_options = tegra_screen_get_compiler_options;
626   screen->base.get_disk_shader_cache = tegra_screen_get_disk_shader_cache;
627
628   screen->base.resource_create_with_modifiers = tegra_screen_resource_create_with_modifiers;
629   screen->base.query_dmabuf_modifiers = tegra_screen_query_dmabuf_modifiers;
630   screen->base.is_dmabuf_modifier_supported = tegra_screen_is_dmabuf_modifier_supported;
631   screen->base.get_dmabuf_modifier_planes = tegra_screen_get_dmabuf_modifier_planes;
632   screen->base.memobj_create_from_handle = tegra_screen_memobj_create_from_handle;
633
634   return &screen->base;
635}
636