Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/tegra/tegra_screen.c
4570 views
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
49
static 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
57
static const char *
58
tegra_screen_get_name(struct pipe_screen *pscreen)
59
{
60
return "tegra";
61
}
62
63
static const char *
64
tegra_screen_get_vendor(struct pipe_screen *pscreen)
65
{
66
return "NVIDIA";
67
}
68
69
static const char *
70
tegra_screen_get_device_vendor(struct pipe_screen *pscreen)
71
{
72
return "NVIDIA";
73
}
74
75
static int
76
tegra_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
83
static float
84
tegra_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
91
static int
92
tegra_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
100
static int
101
tegra_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
112
static int
113
tegra_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
124
static uint64_t
125
tegra_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
132
static bool
133
tegra_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
147
static bool
148
tegra_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
159
static bool
160
tegra_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
168
static 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
204
static struct pipe_resource *
205
tegra_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
return &resource->base;
249
250
destroy:
251
screen->gpu->resource_destroy(screen->gpu, resource->gpu);
252
free:
253
free(resource);
254
return NULL;
255
}
256
257
/* XXX */
258
static struct pipe_resource *
259
tegra_screen_resource_create_front(struct pipe_screen *pscreen,
260
const struct pipe_resource *template,
261
const void *map_front_private)
262
{
263
struct tegra_screen *screen = to_tegra_screen(pscreen);
264
struct pipe_resource *resource;
265
266
resource = screen->gpu->resource_create_front(screen->gpu, template,
267
map_front_private);
268
if (resource)
269
resource->screen = pscreen;
270
271
return resource;
272
}
273
274
static struct pipe_resource *
275
tegra_screen_resource_from_handle(struct pipe_screen *pscreen,
276
const struct pipe_resource *template,
277
struct winsys_handle *handle,
278
unsigned usage)
279
{
280
struct tegra_screen *screen = to_tegra_screen(pscreen);
281
struct tegra_resource *resource;
282
283
resource = calloc(1, sizeof(*resource));
284
if (!resource)
285
return NULL;
286
287
resource->gpu = screen->gpu->resource_from_handle(screen->gpu, template,
288
handle, usage);
289
if (!resource->gpu) {
290
free(resource);
291
return NULL;
292
}
293
294
memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
295
pipe_reference_init(&resource->base.reference, 1);
296
resource->base.screen = &screen->base;
297
298
return &resource->base;
299
}
300
301
/* XXX */
302
static struct pipe_resource *
303
tegra_screen_resource_from_user_memory(struct pipe_screen *pscreen,
304
const struct pipe_resource *template,
305
void *buffer)
306
{
307
struct tegra_screen *screen = to_tegra_screen(pscreen);
308
struct pipe_resource *resource;
309
310
resource = screen->gpu->resource_from_user_memory(screen->gpu, template,
311
buffer);
312
if (resource)
313
resource->screen = pscreen;
314
315
return resource;
316
}
317
318
static bool
319
tegra_screen_resource_get_handle(struct pipe_screen *pscreen,
320
struct pipe_context *pcontext,
321
struct pipe_resource *presource,
322
struct winsys_handle *handle,
323
unsigned usage)
324
{
325
struct tegra_resource *resource = to_tegra_resource(presource);
326
struct tegra_context *context = to_tegra_context(pcontext);
327
struct tegra_screen *screen = to_tegra_screen(pscreen);
328
bool ret = true;
329
330
/*
331
* Assume that KMS handles for scanout resources will only ever be used
332
* to pass buffers into Tegra DRM for display. In all other cases, return
333
* the Nouveau handle, assuming they will be used for sharing in DRI2/3.
334
*/
335
if (handle->type == WINSYS_HANDLE_TYPE_KMS &&
336
presource->bind & PIPE_BIND_SCANOUT) {
337
handle->modifier = resource->modifier;
338
handle->handle = resource->handle;
339
handle->stride = resource->stride;
340
} else {
341
ret = screen->gpu->resource_get_handle(screen->gpu,
342
context ? context->gpu : NULL,
343
resource->gpu, handle, usage);
344
}
345
346
return ret;
347
}
348
349
static void
350
tegra_screen_resource_destroy(struct pipe_screen *pscreen,
351
struct pipe_resource *presource)
352
{
353
struct tegra_resource *resource = to_tegra_resource(presource);
354
355
pipe_resource_reference(&resource->gpu, NULL);
356
free(resource);
357
}
358
359
static void
360
tegra_screen_flush_frontbuffer(struct pipe_screen *pscreen,
361
struct pipe_context *pcontext,
362
struct pipe_resource *resource,
363
unsigned int level,
364
unsigned int layer,
365
void *winsys_drawable_handle,
366
struct pipe_box *box)
367
{
368
struct tegra_screen *screen = to_tegra_screen(pscreen);
369
struct tegra_context *context = to_tegra_context(pcontext);
370
371
screen->gpu->flush_frontbuffer(screen->gpu,
372
context ? context->gpu : NULL,
373
resource, level, layer,
374
winsys_drawable_handle, box);
375
}
376
377
static void
378
tegra_screen_fence_reference(struct pipe_screen *pscreen,
379
struct pipe_fence_handle **ptr,
380
struct pipe_fence_handle *fence)
381
{
382
struct tegra_screen *screen = to_tegra_screen(pscreen);
383
384
screen->gpu->fence_reference(screen->gpu, ptr, fence);
385
}
386
387
static bool
388
tegra_screen_fence_finish(struct pipe_screen *pscreen,
389
struct pipe_context *pcontext,
390
struct pipe_fence_handle *fence,
391
uint64_t timeout)
392
{
393
struct tegra_context *context = to_tegra_context(pcontext);
394
struct tegra_screen *screen = to_tegra_screen(pscreen);
395
396
return screen->gpu->fence_finish(screen->gpu,
397
context ? context->gpu : NULL,
398
fence, timeout);
399
}
400
401
static int
402
tegra_screen_fence_get_fd(struct pipe_screen *pscreen,
403
struct pipe_fence_handle *fence)
404
{
405
struct tegra_screen *screen = to_tegra_screen(pscreen);
406
407
return screen->gpu->fence_get_fd(screen->gpu, fence);
408
}
409
410
static int
411
tegra_screen_get_driver_query_info(struct pipe_screen *pscreen,
412
unsigned int index,
413
struct pipe_driver_query_info *info)
414
{
415
struct tegra_screen *screen = to_tegra_screen(pscreen);
416
417
return screen->gpu->get_driver_query_info(screen->gpu, index, info);
418
}
419
420
static int
421
tegra_screen_get_driver_query_group_info(struct pipe_screen *pscreen,
422
unsigned int index,
423
struct pipe_driver_query_group_info *info)
424
{
425
struct tegra_screen *screen = to_tegra_screen(pscreen);
426
427
return screen->gpu->get_driver_query_group_info(screen->gpu, index, info);
428
}
429
430
static void
431
tegra_screen_query_memory_info(struct pipe_screen *pscreen,
432
struct pipe_memory_info *info)
433
{
434
struct tegra_screen *screen = to_tegra_screen(pscreen);
435
436
screen->gpu->query_memory_info(screen->gpu, info);
437
}
438
439
static const void *
440
tegra_screen_get_compiler_options(struct pipe_screen *pscreen,
441
enum pipe_shader_ir ir,
442
unsigned int shader)
443
{
444
struct tegra_screen *screen = to_tegra_screen(pscreen);
445
const void *options = NULL;
446
447
if (screen->gpu->get_compiler_options)
448
options = screen->gpu->get_compiler_options(screen->gpu, ir, shader);
449
450
return options;
451
}
452
453
static struct disk_cache *
454
tegra_screen_get_disk_shader_cache(struct pipe_screen *pscreen)
455
{
456
struct tegra_screen *screen = to_tegra_screen(pscreen);
457
458
return screen->gpu->get_disk_shader_cache(screen->gpu);
459
}
460
461
static struct pipe_resource *
462
tegra_screen_resource_create_with_modifiers(struct pipe_screen *pscreen,
463
const struct pipe_resource *template,
464
const uint64_t *modifiers,
465
int count)
466
{
467
struct tegra_screen *screen = to_tegra_screen(pscreen);
468
struct pipe_resource tmpl = *template;
469
struct tegra_resource *resource;
470
int err;
471
472
resource = calloc(1, sizeof(*resource));
473
if (!resource)
474
return NULL;
475
476
/*
477
* Assume that resources created with modifiers will always be used for
478
* scanout. This is necessary because some of the APIs that are used to
479
* create resources with modifiers (e.g. gbm_bo_create_with_modifiers())
480
* can't pass along usage information. Adding that capability might be
481
* worth adding to remove this ambiguity. Not all future use-cases that
482
* involve modifiers may always be targetting scanout hardware.
483
*/
484
tmpl.bind |= PIPE_BIND_SCANOUT;
485
486
resource->gpu = screen->gpu->resource_create_with_modifiers(screen->gpu,
487
&tmpl,
488
modifiers,
489
count);
490
if (!resource->gpu)
491
goto free;
492
493
err = tegra_screen_import_resource(screen, resource);
494
if (err < 0)
495
goto destroy;
496
497
memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
498
pipe_reference_init(&resource->base.reference, 1);
499
resource->base.screen = &screen->base;
500
501
return &resource->base;
502
503
destroy:
504
screen->gpu->resource_destroy(screen->gpu, resource->gpu);
505
free:
506
free(resource);
507
return NULL;
508
}
509
510
static void tegra_screen_query_dmabuf_modifiers(struct pipe_screen *pscreen,
511
enum pipe_format format,
512
int max, uint64_t *modifiers,
513
unsigned int *external_only,
514
int *count)
515
{
516
struct tegra_screen *screen = to_tegra_screen(pscreen);
517
518
screen->gpu->query_dmabuf_modifiers(screen->gpu, format, max, modifiers,
519
external_only, count);
520
}
521
522
static bool
523
tegra_screen_is_dmabuf_modifier_supported(struct pipe_screen *pscreen,
524
uint64_t modifier,
525
enum pipe_format format,
526
bool *external_only)
527
{
528
struct tegra_screen *screen = to_tegra_screen(pscreen);
529
530
return screen->gpu->is_dmabuf_modifier_supported(screen->gpu, modifier,
531
format, external_only);
532
}
533
534
static unsigned int
535
tegra_screen_get_dmabuf_modifier_planes(struct pipe_screen *pscreen,
536
uint64_t modifier,
537
enum pipe_format format)
538
{
539
struct tegra_screen *screen = to_tegra_screen(pscreen);
540
541
return screen->gpu->get_dmabuf_modifier_planes ?
542
screen->gpu->get_dmabuf_modifier_planes(screen->gpu, modifier, format) :
543
util_format_get_num_planes(format);
544
}
545
546
static struct pipe_memory_object *
547
tegra_screen_memobj_create_from_handle(struct pipe_screen *pscreen,
548
struct winsys_handle *handle,
549
bool dedicated)
550
{
551
struct tegra_screen *screen = to_tegra_screen(pscreen);
552
553
return screen->gpu->memobj_create_from_handle(screen->gpu, handle,
554
dedicated);
555
}
556
557
struct pipe_screen *
558
tegra_screen_create(int fd)
559
{
560
struct tegra_screen *screen;
561
562
screen = calloc(1, sizeof(*screen));
563
if (!screen)
564
return NULL;
565
566
screen->fd = fd;
567
568
screen->gpu_fd = loader_open_render_node("nouveau");
569
if (screen->gpu_fd < 0) {
570
if (errno != ENOENT)
571
fprintf(stderr, "failed to open GPU device: %s\n", strerror(errno));
572
573
free(screen);
574
return NULL;
575
}
576
577
screen->gpu = nouveau_drm_screen_create(screen->gpu_fd);
578
if (!screen->gpu) {
579
fprintf(stderr, "failed to create GPU screen\n");
580
close(screen->gpu_fd);
581
free(screen);
582
return NULL;
583
}
584
585
screen->base.destroy = tegra_screen_destroy;
586
screen->base.get_name = tegra_screen_get_name;
587
screen->base.get_vendor = tegra_screen_get_vendor;
588
screen->base.get_device_vendor = tegra_screen_get_device_vendor;
589
screen->base.get_param = tegra_screen_get_param;
590
screen->base.get_paramf = tegra_screen_get_paramf;
591
screen->base.get_shader_param = tegra_screen_get_shader_param;
592
screen->base.get_video_param = tegra_screen_get_video_param;
593
screen->base.get_compute_param = tegra_screen_get_compute_param;
594
screen->base.get_timestamp = tegra_screen_get_timestamp;
595
screen->base.context_create = tegra_screen_context_create;
596
screen->base.is_format_supported = tegra_screen_is_format_supported;
597
screen->base.is_video_format_supported = tegra_screen_is_video_format_supported;
598
599
/* allow fallback implementation if GPU driver doesn't implement it */
600
if (screen->gpu->can_create_resource)
601
screen->base.can_create_resource = tegra_screen_can_create_resource;
602
603
screen->base.resource_create = tegra_screen_resource_create;
604
screen->base.resource_create_front = tegra_screen_resource_create_front;
605
screen->base.resource_from_handle = tegra_screen_resource_from_handle;
606
screen->base.resource_from_user_memory = tegra_screen_resource_from_user_memory;
607
screen->base.resource_get_handle = tegra_screen_resource_get_handle;
608
screen->base.resource_destroy = tegra_screen_resource_destroy;
609
610
screen->base.flush_frontbuffer = tegra_screen_flush_frontbuffer;
611
screen->base.fence_reference = tegra_screen_fence_reference;
612
screen->base.fence_finish = tegra_screen_fence_finish;
613
screen->base.fence_get_fd = tegra_screen_fence_get_fd;
614
615
screen->base.get_driver_query_info = tegra_screen_get_driver_query_info;
616
screen->base.get_driver_query_group_info = tegra_screen_get_driver_query_group_info;
617
screen->base.query_memory_info = tegra_screen_query_memory_info;
618
619
screen->base.get_compiler_options = tegra_screen_get_compiler_options;
620
screen->base.get_disk_shader_cache = tegra_screen_get_disk_shader_cache;
621
622
screen->base.resource_create_with_modifiers = tegra_screen_resource_create_with_modifiers;
623
screen->base.query_dmabuf_modifiers = tegra_screen_query_dmabuf_modifiers;
624
screen->base.is_dmabuf_modifier_supported = tegra_screen_is_dmabuf_modifier_supported;
625
screen->base.get_dmabuf_modifier_planes = tegra_screen_get_dmabuf_modifier_planes;
626
screen->base.memobj_create_from_handle = tegra_screen_memobj_create_from_handle;
627
628
return &screen->base;
629
}
630
631