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