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