41bf2052f94536617017b19d9a9bd640af48736c
[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 usage)
136 {
137 struct tegra_screen *screen = to_tegra_screen(pscreen);
138
139 return screen->gpu->is_format_supported(screen->gpu, format, target,
140 sample_count, usage);
141 }
142
143 static boolean
144 tegra_screen_is_video_format_supported(struct pipe_screen *pscreen,
145 enum pipe_format format,
146 enum pipe_video_profile profile,
147 enum pipe_video_entrypoint entrypoint)
148 {
149 struct tegra_screen *screen = to_tegra_screen(pscreen);
150
151 return screen->gpu->is_video_format_supported(screen->gpu, format, profile,
152 entrypoint);
153 }
154
155 static boolean
156 tegra_screen_can_create_resource(struct pipe_screen *pscreen,
157 const struct pipe_resource *template)
158 {
159 struct tegra_screen *screen = to_tegra_screen(pscreen);
160
161 return screen->gpu->can_create_resource(screen->gpu, template);
162 }
163
164 static int tegra_open_render_node(void)
165 {
166 drmDevicePtr *devices, device;
167 int err, render = -ENOENT, fd;
168 unsigned int num, i;
169
170 err = drmGetDevices2(0, NULL, 0);
171 if (err < 0)
172 return err;
173
174 num = err;
175
176 devices = calloc(num, sizeof(*devices));
177 if (!devices)
178 return -ENOMEM;
179
180 err = drmGetDevices2(0, devices, num);
181 if (err < 0) {
182 render = err;
183 goto free;
184 }
185
186 for (i = 0; i < num; i++) {
187 device = devices[i];
188
189 if ((device->available_nodes & (1 << DRM_NODE_RENDER)) &&
190 (device->bustype == DRM_BUS_PLATFORM)) {
191 drmVersionPtr version;
192
193 fd = open(device->nodes[DRM_NODE_RENDER], O_RDWR | O_CLOEXEC);
194 if (fd < 0)
195 continue;
196
197 version = drmGetVersion(fd);
198 if (!version) {
199 close(fd);
200 continue;
201 }
202
203 if (strcmp(version->name, "nouveau") != 0) {
204 close(fd);
205 continue;
206 }
207
208 drmFreeVersion(version);
209 render = fd;
210 break;
211 }
212 }
213
214 drmFreeDevices(devices, num);
215
216 free:
217 free(devices);
218 return render;
219 }
220
221 static int tegra_screen_import_resource(struct tegra_screen *screen,
222 struct tegra_resource *resource)
223 {
224 unsigned usage = PIPE_HANDLE_USAGE_READ;
225 struct winsys_handle handle;
226 boolean status;
227 int fd, err;
228
229 memset(&handle, 0, sizeof(handle));
230 handle.modifier = DRM_FORMAT_MOD_INVALID;
231 handle.type = DRM_API_HANDLE_TYPE_FD;
232
233 status = screen->gpu->resource_get_handle(screen->gpu, NULL, resource->gpu,
234 &handle, usage);
235 if (!status)
236 return -EINVAL;
237
238 assert(handle.modifier != DRM_FORMAT_MOD_INVALID);
239
240 if (handle.modifier == DRM_FORMAT_MOD_INVALID) {
241 close(handle.handle);
242 return -EINVAL;
243 }
244
245 resource->modifier = handle.modifier;
246 resource->stride = handle.stride;
247 fd = handle.handle;
248
249 err = drmPrimeFDToHandle(screen->fd, fd, &resource->handle);
250 if (err < 0)
251 err = -errno;
252
253 close(fd);
254
255 return err;
256 }
257
258 static struct pipe_resource *
259 tegra_screen_resource_create(struct pipe_screen *pscreen,
260 const struct pipe_resource *template)
261 {
262 struct tegra_screen *screen = to_tegra_screen(pscreen);
263 struct tegra_resource *resource;
264 int err;
265
266 resource = calloc(1, sizeof(*resource));
267 if (!resource)
268 return NULL;
269
270 resource->gpu = screen->gpu->resource_create(screen->gpu, template);
271 if (!resource->gpu)
272 goto free;
273
274 /* import scanout buffers for display */
275 if (template->bind & PIPE_BIND_SCANOUT) {
276 err = tegra_screen_import_resource(screen, resource);
277 if (err < 0)
278 goto destroy;
279 }
280
281 memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
282 pipe_reference_init(&resource->base.reference, 1);
283 resource->base.screen = &screen->base;
284
285 return &resource->base;
286
287 destroy:
288 screen->gpu->resource_destroy(screen->gpu, resource->gpu);
289 free:
290 free(resource);
291 return NULL;
292 }
293
294 /* XXX */
295 static struct pipe_resource *
296 tegra_screen_resource_create_front(struct pipe_screen *pscreen,
297 const struct pipe_resource *template,
298 const void *map_front_private)
299 {
300 struct tegra_screen *screen = to_tegra_screen(pscreen);
301 struct pipe_resource *resource;
302
303 resource = screen->gpu->resource_create_front(screen->gpu, template,
304 map_front_private);
305 if (resource)
306 resource->screen = pscreen;
307
308 return resource;
309 }
310
311 static struct pipe_resource *
312 tegra_screen_resource_from_handle(struct pipe_screen *pscreen,
313 const struct pipe_resource *template,
314 struct winsys_handle *handle,
315 unsigned usage)
316 {
317 struct tegra_screen *screen = to_tegra_screen(pscreen);
318 struct tegra_resource *resource;
319
320 resource = calloc(1, sizeof(*resource));
321 if (!resource)
322 return NULL;
323
324 resource->gpu = screen->gpu->resource_from_handle(screen->gpu, template,
325 handle, usage);
326 if (!resource->gpu) {
327 free(resource);
328 return NULL;
329 }
330
331 memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
332 pipe_reference_init(&resource->base.reference, 1);
333 resource->base.screen = &screen->base;
334
335 return &resource->base;
336 }
337
338 /* XXX */
339 static struct pipe_resource *
340 tegra_screen_resource_from_user_memory(struct pipe_screen *pscreen,
341 const struct pipe_resource *template,
342 void *buffer)
343 {
344 struct tegra_screen *screen = to_tegra_screen(pscreen);
345 struct pipe_resource *resource;
346
347 resource = screen->gpu->resource_from_user_memory(screen->gpu, template,
348 buffer);
349 if (resource)
350 resource->screen = pscreen;
351
352 return resource;
353 }
354
355 static boolean
356 tegra_screen_resource_get_handle(struct pipe_screen *pscreen,
357 struct pipe_context *pcontext,
358 struct pipe_resource *presource,
359 struct winsys_handle *handle,
360 unsigned usage)
361 {
362 struct tegra_resource *resource = to_tegra_resource(presource);
363 struct tegra_context *context = to_tegra_context(pcontext);
364 struct tegra_screen *screen = to_tegra_screen(pscreen);
365 boolean ret = TRUE;
366
367 /*
368 * Assume that KMS handles for scanout resources will only ever be used
369 * to pass buffers into Tegra DRM for display. In all other cases, return
370 * the Nouveau handle, assuming they will be used for sharing in DRI2/3.
371 */
372 if (handle->type == DRM_API_HANDLE_TYPE_KMS &&
373 presource->bind & PIPE_BIND_SCANOUT) {
374 handle->modifier = resource->modifier;
375 handle->handle = resource->handle;
376 handle->stride = resource->stride;
377 } else {
378 ret = screen->gpu->resource_get_handle(screen->gpu,
379 context ? context->gpu : NULL,
380 resource->gpu, handle, usage);
381 }
382
383 return ret;
384 }
385
386 static void
387 tegra_screen_resource_destroy(struct pipe_screen *pscreen,
388 struct pipe_resource *presource)
389 {
390 struct tegra_resource *resource = to_tegra_resource(presource);
391
392 pipe_resource_reference(&resource->gpu, NULL);
393 free(resource);
394 }
395
396 static void
397 tegra_screen_flush_frontbuffer(struct pipe_screen *pscreen,
398 struct pipe_resource *resource,
399 unsigned int level,
400 unsigned int layer,
401 void *winsys_drawable_handle,
402 struct pipe_box *box)
403 {
404 struct tegra_screen *screen = to_tegra_screen(pscreen);
405
406 screen->gpu->flush_frontbuffer(screen->gpu, resource, level, layer,
407 winsys_drawable_handle, box);
408 }
409
410 static void
411 tegra_screen_fence_reference(struct pipe_screen *pscreen,
412 struct pipe_fence_handle **ptr,
413 struct pipe_fence_handle *fence)
414 {
415 struct tegra_screen *screen = to_tegra_screen(pscreen);
416
417 screen->gpu->fence_reference(screen->gpu, ptr, fence);
418 }
419
420 static boolean
421 tegra_screen_fence_finish(struct pipe_screen *pscreen,
422 struct pipe_context *pcontext,
423 struct pipe_fence_handle *fence,
424 uint64_t timeout)
425 {
426 struct tegra_context *context = to_tegra_context(pcontext);
427 struct tegra_screen *screen = to_tegra_screen(pscreen);
428
429 return screen->gpu->fence_finish(screen->gpu,
430 context ? context->gpu : NULL,
431 fence, timeout);
432 }
433
434 static int
435 tegra_screen_fence_get_fd(struct pipe_screen *pscreen,
436 struct pipe_fence_handle *fence)
437 {
438 struct tegra_screen *screen = to_tegra_screen(pscreen);
439
440 return screen->gpu->fence_get_fd(screen->gpu, fence);
441 }
442
443 static int
444 tegra_screen_get_driver_query_info(struct pipe_screen *pscreen,
445 unsigned int index,
446 struct pipe_driver_query_info *info)
447 {
448 struct tegra_screen *screen = to_tegra_screen(pscreen);
449
450 return screen->gpu->get_driver_query_info(screen->gpu, index, info);
451 }
452
453 static int
454 tegra_screen_get_driver_query_group_info(struct pipe_screen *pscreen,
455 unsigned int index,
456 struct pipe_driver_query_group_info *info)
457 {
458 struct tegra_screen *screen = to_tegra_screen(pscreen);
459
460 return screen->gpu->get_driver_query_group_info(screen->gpu, index, info);
461 }
462
463 static void
464 tegra_screen_query_memory_info(struct pipe_screen *pscreen,
465 struct pipe_memory_info *info)
466 {
467 struct tegra_screen *screen = to_tegra_screen(pscreen);
468
469 screen->gpu->query_memory_info(screen->gpu, info);
470 }
471
472 static const void *
473 tegra_screen_get_compiler_options(struct pipe_screen *pscreen,
474 enum pipe_shader_ir ir,
475 unsigned int shader)
476 {
477 struct tegra_screen *screen = to_tegra_screen(pscreen);
478 const void *options = NULL;
479
480 if (screen->gpu->get_compiler_options)
481 options = screen->gpu->get_compiler_options(screen->gpu, ir, shader);
482
483 return options;
484 }
485
486 static struct disk_cache *
487 tegra_screen_get_disk_shader_cache(struct pipe_screen *pscreen)
488 {
489 struct tegra_screen *screen = to_tegra_screen(pscreen);
490
491 return screen->gpu->get_disk_shader_cache(screen->gpu);
492 }
493
494 static struct pipe_resource *
495 tegra_screen_resource_create_with_modifiers(struct pipe_screen *pscreen,
496 const struct pipe_resource *template,
497 const uint64_t *modifiers,
498 int count)
499 {
500 struct tegra_screen *screen = to_tegra_screen(pscreen);
501 struct tegra_resource *resource;
502 int err;
503
504 resource = calloc(1, sizeof(*resource));
505 if (!resource)
506 return NULL;
507
508 resource->gpu = screen->gpu->resource_create_with_modifiers(screen->gpu,
509 template,
510 modifiers,
511 count);
512 if (!resource->gpu)
513 goto free;
514
515 err = tegra_screen_import_resource(screen, resource);
516 if (err < 0)
517 goto destroy;
518
519 memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
520 pipe_reference_init(&resource->base.reference, 1);
521 resource->base.screen = &screen->base;
522
523 return &resource->base;
524
525 destroy:
526 screen->gpu->resource_destroy(screen->gpu, resource->gpu);
527 free:
528 free(resource);
529 return NULL;
530 }
531
532 static void tegra_screen_query_dmabuf_modifiers(struct pipe_screen *pscreen,
533 enum pipe_format format,
534 int max, uint64_t *modifiers,
535 unsigned int *external_only,
536 int *count)
537 {
538 struct tegra_screen *screen = to_tegra_screen(pscreen);
539
540 screen->gpu->query_dmabuf_modifiers(screen->gpu, format, max, modifiers,
541 external_only, count);
542 }
543
544 static struct pipe_memory_object *
545 tegra_screen_memobj_create_from_handle(struct pipe_screen *pscreen,
546 struct winsys_handle *handle,
547 bool dedicated)
548 {
549 struct tegra_screen *screen = to_tegra_screen(pscreen);
550
551 return screen->gpu->memobj_create_from_handle(screen->gpu, handle,
552 dedicated);
553 }
554
555 struct pipe_screen *
556 tegra_screen_create(int fd)
557 {
558 struct tegra_screen *screen;
559
560 screen = calloc(1, sizeof(*screen));
561 if (!screen)
562 return NULL;
563
564 screen->fd = fd;
565
566 screen->gpu_fd = tegra_open_render_node();
567 if (screen->gpu_fd < 0) {
568 if (errno != ENOENT)
569 fprintf(stderr, "failed to open GPU device: %s\n", strerror(errno));
570
571 free(screen);
572 return NULL;
573 }
574
575 screen->gpu = nouveau_drm_screen_create(screen->gpu_fd);
576 if (!screen->gpu) {
577 fprintf(stderr, "failed to create GPU screen\n");
578 close(screen->gpu_fd);
579 free(screen);
580 return NULL;
581 }
582
583 screen->base.destroy = tegra_screen_destroy;
584 screen->base.get_name = tegra_screen_get_name;
585 screen->base.get_vendor = tegra_screen_get_vendor;
586 screen->base.get_device_vendor = tegra_screen_get_device_vendor;
587 screen->base.get_param = tegra_screen_get_param;
588 screen->base.get_paramf = tegra_screen_get_paramf;
589 screen->base.get_shader_param = tegra_screen_get_shader_param;
590 screen->base.get_video_param = tegra_screen_get_video_param;
591 screen->base.get_compute_param = tegra_screen_get_compute_param;
592 screen->base.get_timestamp = tegra_screen_get_timestamp;
593 screen->base.context_create = tegra_screen_context_create;
594 screen->base.is_format_supported = tegra_screen_is_format_supported;
595 screen->base.is_video_format_supported = tegra_screen_is_video_format_supported;
596
597 /* allow fallback implementation if GPU driver doesn't implement it */
598 if (screen->gpu->can_create_resource)
599 screen->base.can_create_resource = tegra_screen_can_create_resource;
600
601 screen->base.resource_create = tegra_screen_resource_create;
602 screen->base.resource_create_front = tegra_screen_resource_create_front;
603 screen->base.resource_from_handle = tegra_screen_resource_from_handle;
604 screen->base.resource_from_user_memory = tegra_screen_resource_from_user_memory;
605 screen->base.resource_get_handle = tegra_screen_resource_get_handle;
606 screen->base.resource_destroy = tegra_screen_resource_destroy;
607
608 screen->base.flush_frontbuffer = tegra_screen_flush_frontbuffer;
609 screen->base.fence_reference = tegra_screen_fence_reference;
610 screen->base.fence_finish = tegra_screen_fence_finish;
611 screen->base.fence_get_fd = tegra_screen_fence_get_fd;
612
613 screen->base.get_driver_query_info = tegra_screen_get_driver_query_info;
614 screen->base.get_driver_query_group_info = tegra_screen_get_driver_query_group_info;
615 screen->base.query_memory_info = tegra_screen_query_memory_info;
616
617 screen->base.get_compiler_options = tegra_screen_get_compiler_options;
618 screen->base.get_disk_shader_cache = tegra_screen_get_disk_shader_cache;
619
620 screen->base.resource_create_with_modifiers = tegra_screen_resource_create_with_modifiers;
621 screen->base.query_dmabuf_modifiers = tegra_screen_query_dmabuf_modifiers;
622 screen->base.memobj_create_from_handle = tegra_screen_memobj_create_from_handle;
623
624 return &screen->base;
625 }