gallium: rename 'state tracker' to 'frontend'
[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-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 "frontend/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
48 static 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
56 static const char *
57 tegra_screen_get_name(struct pipe_screen *pscreen)
58 {
59 return "tegra";
60 }
61
62 static const char *
63 tegra_screen_get_vendor(struct pipe_screen *pscreen)
64 {
65 return "NVIDIA";
66 }
67
68 static const char *
69 tegra_screen_get_device_vendor(struct pipe_screen *pscreen)
70 {
71 return "NVIDIA";
72 }
73
74 static int
75 tegra_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
82 static float
83 tegra_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
90 static int
91 tegra_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
99 static int
100 tegra_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
111 static int
112 tegra_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
123 static uint64_t
124 tegra_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
131 static bool
132 tegra_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
146 static bool
147 tegra_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
158 static bool
159 tegra_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
167 static int tegra_screen_import_resource(struct tegra_screen *screen,
168 struct tegra_resource *resource)
169 {
170 struct winsys_handle handle;
171 bool 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
203 static struct pipe_resource *
204 tegra_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
249 destroy:
250 screen->gpu->resource_destroy(screen->gpu, resource->gpu);
251 free:
252 free(resource);
253 return NULL;
254 }
255
256 /* XXX */
257 static struct pipe_resource *
258 tegra_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
273 static struct pipe_resource *
274 tegra_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 */
301 static struct pipe_resource *
302 tegra_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
317 static bool
318 tegra_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 bool 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
348 static void
349 tegra_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
358 static void
359 tegra_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
372 static void
373 tegra_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
382 static bool
383 tegra_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
396 static int
397 tegra_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
405 static int
406 tegra_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
415 static int
416 tegra_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
425 static void
426 tegra_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
434 static const void *
435 tegra_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
448 static struct disk_cache *
449 tegra_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
456 static struct pipe_resource *
457 tegra_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
498 destroy:
499 screen->gpu->resource_destroy(screen->gpu, resource->gpu);
500 free:
501 free(resource);
502 return NULL;
503 }
504
505 static 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
517 static struct pipe_memory_object *
518 tegra_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
528 struct pipe_screen *
529 tegra_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 }