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