1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2014-2018 NVIDIA Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include <errno.h>
25bf215546Sopenharmony_ci#include <fcntl.h>
26bf215546Sopenharmony_ci#include <inttypes.h>
27bf215546Sopenharmony_ci#include <stdio.h>
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#include <sys/stat.h>
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ci#include "drm-uapi/drm_fourcc.h"
32bf215546Sopenharmony_ci#include "drm-uapi/tegra_drm.h"
33bf215546Sopenharmony_ci#include <xf86drm.h>
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci#include "loader/loader.h"
36bf215546Sopenharmony_ci#include "pipe/p_state.h"
37bf215546Sopenharmony_ci#include "util/u_debug.h"
38bf215546Sopenharmony_ci#include "util/format/u_format.h"
39bf215546Sopenharmony_ci#include "util/u_inlines.h"
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_ci#include "frontend/drm_driver.h"
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci#include "nouveau/drm/nouveau_drm_public.h"
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_ci#include "tegra_context.h"
46bf215546Sopenharmony_ci#include "tegra_resource.h"
47bf215546Sopenharmony_ci#include "tegra_screen.h"
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_cistatic void tegra_screen_destroy(struct pipe_screen *pscreen)
50bf215546Sopenharmony_ci{
51bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci   screen->gpu->destroy(screen->gpu);
54bf215546Sopenharmony_ci   free(pscreen);
55bf215546Sopenharmony_ci}
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_cistatic const char *
58bf215546Sopenharmony_citegra_screen_get_name(struct pipe_screen *pscreen)
59bf215546Sopenharmony_ci{
60bf215546Sopenharmony_ci   return "tegra";
61bf215546Sopenharmony_ci}
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_cistatic const char *
64bf215546Sopenharmony_citegra_screen_get_vendor(struct pipe_screen *pscreen)
65bf215546Sopenharmony_ci{
66bf215546Sopenharmony_ci   return "NVIDIA";
67bf215546Sopenharmony_ci}
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_cistatic const char *
70bf215546Sopenharmony_citegra_screen_get_device_vendor(struct pipe_screen *pscreen)
71bf215546Sopenharmony_ci{
72bf215546Sopenharmony_ci   return "NVIDIA";
73bf215546Sopenharmony_ci}
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_cistatic int
76bf215546Sopenharmony_citegra_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
77bf215546Sopenharmony_ci{
78bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci   return screen->gpu->get_param(screen->gpu, param);
81bf215546Sopenharmony_ci}
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_cistatic float
84bf215546Sopenharmony_citegra_screen_get_paramf(struct pipe_screen *pscreen, enum pipe_capf param)
85bf215546Sopenharmony_ci{
86bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_ci   return screen->gpu->get_paramf(screen->gpu, param);
89bf215546Sopenharmony_ci}
90bf215546Sopenharmony_ci
91bf215546Sopenharmony_cistatic int
92bf215546Sopenharmony_citegra_screen_get_shader_param(struct pipe_screen *pscreen, unsigned shader,
93bf215546Sopenharmony_ci                              enum pipe_shader_cap param)
94bf215546Sopenharmony_ci{
95bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci   return screen->gpu->get_shader_param(screen->gpu, shader, param);
98bf215546Sopenharmony_ci}
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_cistatic int
101bf215546Sopenharmony_citegra_screen_get_video_param(struct pipe_screen *pscreen,
102bf215546Sopenharmony_ci                             enum pipe_video_profile profile,
103bf215546Sopenharmony_ci                             enum pipe_video_entrypoint entrypoint,
104bf215546Sopenharmony_ci                             enum pipe_video_cap param)
105bf215546Sopenharmony_ci{
106bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_ci   return screen->gpu->get_video_param(screen->gpu, profile, entrypoint,
109bf215546Sopenharmony_ci                                       param);
110bf215546Sopenharmony_ci}
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_cistatic int
113bf215546Sopenharmony_citegra_screen_get_compute_param(struct pipe_screen *pscreen,
114bf215546Sopenharmony_ci                               enum pipe_shader_ir ir_type,
115bf215546Sopenharmony_ci                               enum pipe_compute_cap param,
116bf215546Sopenharmony_ci                               void *retp)
117bf215546Sopenharmony_ci{
118bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_ci   return screen->gpu->get_compute_param(screen->gpu, ir_type, param,
121bf215546Sopenharmony_ci                                         retp);
122bf215546Sopenharmony_ci}
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_cistatic uint64_t
125bf215546Sopenharmony_citegra_screen_get_timestamp(struct pipe_screen *pscreen)
126bf215546Sopenharmony_ci{
127bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_ci   return screen->gpu->get_timestamp(screen->gpu);
130bf215546Sopenharmony_ci}
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_cistatic bool
133bf215546Sopenharmony_citegra_screen_is_format_supported(struct pipe_screen *pscreen,
134bf215546Sopenharmony_ci                                 enum pipe_format format,
135bf215546Sopenharmony_ci                                 enum pipe_texture_target target,
136bf215546Sopenharmony_ci                                 unsigned sample_count,
137bf215546Sopenharmony_ci                                 unsigned storage_sample_count,
138bf215546Sopenharmony_ci                                 unsigned usage)
139bf215546Sopenharmony_ci{
140bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci   return screen->gpu->is_format_supported(screen->gpu, format, target,
143bf215546Sopenharmony_ci                                           sample_count, storage_sample_count,
144bf215546Sopenharmony_ci                                           usage);
145bf215546Sopenharmony_ci}
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_cistatic bool
148bf215546Sopenharmony_citegra_screen_is_video_format_supported(struct pipe_screen *pscreen,
149bf215546Sopenharmony_ci                                       enum pipe_format format,
150bf215546Sopenharmony_ci                                       enum pipe_video_profile profile,
151bf215546Sopenharmony_ci                                       enum pipe_video_entrypoint entrypoint)
152bf215546Sopenharmony_ci{
153bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci   return screen->gpu->is_video_format_supported(screen->gpu, format, profile,
156bf215546Sopenharmony_ci                                                 entrypoint);
157bf215546Sopenharmony_ci}
158bf215546Sopenharmony_ci
159bf215546Sopenharmony_cistatic bool
160bf215546Sopenharmony_citegra_screen_can_create_resource(struct pipe_screen *pscreen,
161bf215546Sopenharmony_ci                                 const struct pipe_resource *template)
162bf215546Sopenharmony_ci{
163bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci   return screen->gpu->can_create_resource(screen->gpu, template);
166bf215546Sopenharmony_ci}
167bf215546Sopenharmony_ci
168bf215546Sopenharmony_cistatic int tegra_screen_import_resource(struct tegra_screen *screen,
169bf215546Sopenharmony_ci                                        struct tegra_resource *resource)
170bf215546Sopenharmony_ci{
171bf215546Sopenharmony_ci   struct winsys_handle handle;
172bf215546Sopenharmony_ci   bool status;
173bf215546Sopenharmony_ci   int fd, err;
174bf215546Sopenharmony_ci
175bf215546Sopenharmony_ci   memset(&handle, 0, sizeof(handle));
176bf215546Sopenharmony_ci   handle.modifier = DRM_FORMAT_MOD_INVALID;
177bf215546Sopenharmony_ci   handle.type = WINSYS_HANDLE_TYPE_FD;
178bf215546Sopenharmony_ci
179bf215546Sopenharmony_ci   status = screen->gpu->resource_get_handle(screen->gpu, NULL, resource->gpu,
180bf215546Sopenharmony_ci                                             &handle, 0);
181bf215546Sopenharmony_ci   if (!status)
182bf215546Sopenharmony_ci      return -EINVAL;
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci   assert(handle.modifier != DRM_FORMAT_MOD_INVALID);
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci   if (handle.modifier == DRM_FORMAT_MOD_INVALID) {
187bf215546Sopenharmony_ci      close(handle.handle);
188bf215546Sopenharmony_ci      return -EINVAL;
189bf215546Sopenharmony_ci   }
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci   resource->modifier = handle.modifier;
192bf215546Sopenharmony_ci   resource->stride = handle.stride;
193bf215546Sopenharmony_ci   fd = handle.handle;
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ci   err = drmPrimeFDToHandle(screen->fd, fd, &resource->handle);
196bf215546Sopenharmony_ci   if (err < 0)
197bf215546Sopenharmony_ci      err = -errno;
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_ci   close(fd);
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci   return err;
202bf215546Sopenharmony_ci}
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_cistatic struct pipe_resource *
205bf215546Sopenharmony_citegra_screen_resource_create(struct pipe_screen *pscreen,
206bf215546Sopenharmony_ci                             const struct pipe_resource *template)
207bf215546Sopenharmony_ci{
208bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
209bf215546Sopenharmony_ci   uint64_t modifier = DRM_FORMAT_MOD_INVALID;
210bf215546Sopenharmony_ci   struct tegra_resource *resource;
211bf215546Sopenharmony_ci   int err;
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci   resource = calloc(1, sizeof(*resource));
214bf215546Sopenharmony_ci   if (!resource)
215bf215546Sopenharmony_ci      return NULL;
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_ci   /*
218bf215546Sopenharmony_ci    * Applications that create scanout resources without modifiers are very
219bf215546Sopenharmony_ci    * unlikely to support modifiers at all. In that case the resources need
220bf215546Sopenharmony_ci    * to be created with a pitch-linear layout so that they can be properly
221bf215546Sopenharmony_ci    * shared with scanout hardware.
222bf215546Sopenharmony_ci    *
223bf215546Sopenharmony_ci    * Technically it is possible for applications to create resources without
224bf215546Sopenharmony_ci    * specifying a modifier but still query the modifier associated with the
225bf215546Sopenharmony_ci    * resource (e.g. using gbm_bo_get_modifier()) before handing it to the
226bf215546Sopenharmony_ci    * framebuffer creation API (such as the DRM_IOCTL_MODE_ADDFB2 IOCTL).
227bf215546Sopenharmony_ci    */
228bf215546Sopenharmony_ci   if (template->bind & PIPE_BIND_SCANOUT)
229bf215546Sopenharmony_ci      modifier = DRM_FORMAT_MOD_LINEAR;
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci   resource->gpu = screen->gpu->resource_create_with_modifiers(screen->gpu,
232bf215546Sopenharmony_ci                                                               template,
233bf215546Sopenharmony_ci                                                               &modifier, 1);
234bf215546Sopenharmony_ci   if (!resource->gpu)
235bf215546Sopenharmony_ci      goto free;
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_ci   /* import scanout buffers for display */
238bf215546Sopenharmony_ci   if (template->bind & PIPE_BIND_SCANOUT) {
239bf215546Sopenharmony_ci      err = tegra_screen_import_resource(screen, resource);
240bf215546Sopenharmony_ci      if (err < 0)
241bf215546Sopenharmony_ci         goto destroy;
242bf215546Sopenharmony_ci   }
243bf215546Sopenharmony_ci
244bf215546Sopenharmony_ci   memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
245bf215546Sopenharmony_ci   pipe_reference_init(&resource->base.reference, 1);
246bf215546Sopenharmony_ci   resource->base.screen = &screen->base;
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci   /* use private reference count for wrapped resources */
249bf215546Sopenharmony_ci   resource->gpu->reference.count += 100000000;
250bf215546Sopenharmony_ci   resource->refcount = 100000000;
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci   return &resource->base;
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_cidestroy:
255bf215546Sopenharmony_ci   screen->gpu->resource_destroy(screen->gpu, resource->gpu);
256bf215546Sopenharmony_cifree:
257bf215546Sopenharmony_ci   free(resource);
258bf215546Sopenharmony_ci   return NULL;
259bf215546Sopenharmony_ci}
260bf215546Sopenharmony_ci
261bf215546Sopenharmony_ci/* XXX */
262bf215546Sopenharmony_cistatic struct pipe_resource *
263bf215546Sopenharmony_citegra_screen_resource_create_front(struct pipe_screen *pscreen,
264bf215546Sopenharmony_ci                                   const struct pipe_resource *template,
265bf215546Sopenharmony_ci                                   const void *map_front_private)
266bf215546Sopenharmony_ci{
267bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
268bf215546Sopenharmony_ci   struct pipe_resource *resource;
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci   resource = screen->gpu->resource_create_front(screen->gpu, template,
271bf215546Sopenharmony_ci                                                 map_front_private);
272bf215546Sopenharmony_ci   if (resource)
273bf215546Sopenharmony_ci      resource->screen = pscreen;
274bf215546Sopenharmony_ci
275bf215546Sopenharmony_ci   return resource;
276bf215546Sopenharmony_ci}
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_cistatic struct pipe_resource *
279bf215546Sopenharmony_citegra_screen_resource_from_handle(struct pipe_screen *pscreen,
280bf215546Sopenharmony_ci                                  const struct pipe_resource *template,
281bf215546Sopenharmony_ci                                  struct winsys_handle *handle,
282bf215546Sopenharmony_ci                                  unsigned usage)
283bf215546Sopenharmony_ci{
284bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
285bf215546Sopenharmony_ci   struct tegra_resource *resource;
286bf215546Sopenharmony_ci
287bf215546Sopenharmony_ci   resource = calloc(1, sizeof(*resource));
288bf215546Sopenharmony_ci   if (!resource)
289bf215546Sopenharmony_ci      return NULL;
290bf215546Sopenharmony_ci
291bf215546Sopenharmony_ci   resource->gpu = screen->gpu->resource_from_handle(screen->gpu, template,
292bf215546Sopenharmony_ci                                                     handle, usage);
293bf215546Sopenharmony_ci   if (!resource->gpu) {
294bf215546Sopenharmony_ci      free(resource);
295bf215546Sopenharmony_ci      return NULL;
296bf215546Sopenharmony_ci   }
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_ci   memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
299bf215546Sopenharmony_ci   pipe_reference_init(&resource->base.reference, 1);
300bf215546Sopenharmony_ci   resource->base.screen = &screen->base;
301bf215546Sopenharmony_ci
302bf215546Sopenharmony_ci   return &resource->base;
303bf215546Sopenharmony_ci}
304bf215546Sopenharmony_ci
305bf215546Sopenharmony_ci/* XXX */
306bf215546Sopenharmony_cistatic struct pipe_resource *
307bf215546Sopenharmony_citegra_screen_resource_from_user_memory(struct pipe_screen *pscreen,
308bf215546Sopenharmony_ci                                       const struct pipe_resource *template,
309bf215546Sopenharmony_ci                                       void *buffer)
310bf215546Sopenharmony_ci{
311bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
312bf215546Sopenharmony_ci   struct pipe_resource *resource;
313bf215546Sopenharmony_ci
314bf215546Sopenharmony_ci   resource = screen->gpu->resource_from_user_memory(screen->gpu, template,
315bf215546Sopenharmony_ci                                                     buffer);
316bf215546Sopenharmony_ci   if (resource)
317bf215546Sopenharmony_ci      resource->screen = pscreen;
318bf215546Sopenharmony_ci
319bf215546Sopenharmony_ci   return resource;
320bf215546Sopenharmony_ci}
321bf215546Sopenharmony_ci
322bf215546Sopenharmony_cistatic bool
323bf215546Sopenharmony_citegra_screen_resource_get_handle(struct pipe_screen *pscreen,
324bf215546Sopenharmony_ci                                 struct pipe_context *pcontext,
325bf215546Sopenharmony_ci                                 struct pipe_resource *presource,
326bf215546Sopenharmony_ci                                 struct winsys_handle *handle,
327bf215546Sopenharmony_ci                                 unsigned usage)
328bf215546Sopenharmony_ci{
329bf215546Sopenharmony_ci   struct tegra_resource *resource = to_tegra_resource(presource);
330bf215546Sopenharmony_ci   struct tegra_context *context = to_tegra_context(pcontext);
331bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
332bf215546Sopenharmony_ci   bool ret = true;
333bf215546Sopenharmony_ci
334bf215546Sopenharmony_ci   /*
335bf215546Sopenharmony_ci    * Assume that KMS handles for scanout resources will only ever be used
336bf215546Sopenharmony_ci    * to pass buffers into Tegra DRM for display. In all other cases, return
337bf215546Sopenharmony_ci    * the Nouveau handle, assuming they will be used for sharing in DRI2/3.
338bf215546Sopenharmony_ci    */
339bf215546Sopenharmony_ci   if (handle->type == WINSYS_HANDLE_TYPE_KMS &&
340bf215546Sopenharmony_ci       presource->bind & PIPE_BIND_SCANOUT) {
341bf215546Sopenharmony_ci      handle->modifier = resource->modifier;
342bf215546Sopenharmony_ci      handle->handle = resource->handle;
343bf215546Sopenharmony_ci      handle->stride = resource->stride;
344bf215546Sopenharmony_ci   } else {
345bf215546Sopenharmony_ci      ret = screen->gpu->resource_get_handle(screen->gpu,
346bf215546Sopenharmony_ci                                             context ? context->gpu : NULL,
347bf215546Sopenharmony_ci                                             resource->gpu, handle, usage);
348bf215546Sopenharmony_ci   }
349bf215546Sopenharmony_ci
350bf215546Sopenharmony_ci   return ret;
351bf215546Sopenharmony_ci}
352bf215546Sopenharmony_ci
353bf215546Sopenharmony_cistatic void
354bf215546Sopenharmony_citegra_screen_resource_destroy(struct pipe_screen *pscreen,
355bf215546Sopenharmony_ci                              struct pipe_resource *presource)
356bf215546Sopenharmony_ci{
357bf215546Sopenharmony_ci   struct tegra_resource *resource = to_tegra_resource(presource);
358bf215546Sopenharmony_ci
359bf215546Sopenharmony_ci   /* adjust private reference count */
360bf215546Sopenharmony_ci   p_atomic_add(&resource->gpu->reference.count, -resource->refcount);
361bf215546Sopenharmony_ci   pipe_resource_reference(&resource->gpu, NULL);
362bf215546Sopenharmony_ci   free(resource);
363bf215546Sopenharmony_ci}
364bf215546Sopenharmony_ci
365bf215546Sopenharmony_cistatic void
366bf215546Sopenharmony_citegra_screen_flush_frontbuffer(struct pipe_screen *pscreen,
367bf215546Sopenharmony_ci                               struct pipe_context *pcontext,
368bf215546Sopenharmony_ci                               struct pipe_resource *resource,
369bf215546Sopenharmony_ci                               unsigned int level,
370bf215546Sopenharmony_ci                               unsigned int layer,
371bf215546Sopenharmony_ci                               void *winsys_drawable_handle,
372bf215546Sopenharmony_ci                               struct pipe_box *box)
373bf215546Sopenharmony_ci{
374bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
375bf215546Sopenharmony_ci   struct tegra_context *context = to_tegra_context(pcontext);
376bf215546Sopenharmony_ci
377bf215546Sopenharmony_ci   screen->gpu->flush_frontbuffer(screen->gpu,
378bf215546Sopenharmony_ci                                  context ? context->gpu : NULL,
379bf215546Sopenharmony_ci                                  resource, level, layer,
380bf215546Sopenharmony_ci                                  winsys_drawable_handle, box);
381bf215546Sopenharmony_ci}
382bf215546Sopenharmony_ci
383bf215546Sopenharmony_cistatic void
384bf215546Sopenharmony_citegra_screen_fence_reference(struct pipe_screen *pscreen,
385bf215546Sopenharmony_ci                             struct pipe_fence_handle **ptr,
386bf215546Sopenharmony_ci                             struct pipe_fence_handle *fence)
387bf215546Sopenharmony_ci{
388bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
389bf215546Sopenharmony_ci
390bf215546Sopenharmony_ci   screen->gpu->fence_reference(screen->gpu, ptr, fence);
391bf215546Sopenharmony_ci}
392bf215546Sopenharmony_ci
393bf215546Sopenharmony_cistatic bool
394bf215546Sopenharmony_citegra_screen_fence_finish(struct pipe_screen *pscreen,
395bf215546Sopenharmony_ci                          struct pipe_context *pcontext,
396bf215546Sopenharmony_ci                          struct pipe_fence_handle *fence,
397bf215546Sopenharmony_ci                          uint64_t timeout)
398bf215546Sopenharmony_ci{
399bf215546Sopenharmony_ci   struct tegra_context *context = to_tegra_context(pcontext);
400bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
401bf215546Sopenharmony_ci
402bf215546Sopenharmony_ci   return screen->gpu->fence_finish(screen->gpu,
403bf215546Sopenharmony_ci                                    context ? context->gpu : NULL,
404bf215546Sopenharmony_ci                                    fence, timeout);
405bf215546Sopenharmony_ci}
406bf215546Sopenharmony_ci
407bf215546Sopenharmony_cistatic int
408bf215546Sopenharmony_citegra_screen_fence_get_fd(struct pipe_screen *pscreen,
409bf215546Sopenharmony_ci                          struct pipe_fence_handle *fence)
410bf215546Sopenharmony_ci{
411bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
412bf215546Sopenharmony_ci
413bf215546Sopenharmony_ci   return screen->gpu->fence_get_fd(screen->gpu, fence);
414bf215546Sopenharmony_ci}
415bf215546Sopenharmony_ci
416bf215546Sopenharmony_cistatic int
417bf215546Sopenharmony_citegra_screen_get_driver_query_info(struct pipe_screen *pscreen,
418bf215546Sopenharmony_ci                                   unsigned int index,
419bf215546Sopenharmony_ci                                   struct pipe_driver_query_info *info)
420bf215546Sopenharmony_ci{
421bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci   return screen->gpu->get_driver_query_info(screen->gpu, index, info);
424bf215546Sopenharmony_ci}
425bf215546Sopenharmony_ci
426bf215546Sopenharmony_cistatic int
427bf215546Sopenharmony_citegra_screen_get_driver_query_group_info(struct pipe_screen *pscreen,
428bf215546Sopenharmony_ci                                         unsigned int index,
429bf215546Sopenharmony_ci                                         struct pipe_driver_query_group_info *info)
430bf215546Sopenharmony_ci{
431bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_ci   return screen->gpu->get_driver_query_group_info(screen->gpu, index, info);
434bf215546Sopenharmony_ci}
435bf215546Sopenharmony_ci
436bf215546Sopenharmony_cistatic void
437bf215546Sopenharmony_citegra_screen_query_memory_info(struct pipe_screen *pscreen,
438bf215546Sopenharmony_ci                               struct pipe_memory_info *info)
439bf215546Sopenharmony_ci{
440bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
441bf215546Sopenharmony_ci
442bf215546Sopenharmony_ci   screen->gpu->query_memory_info(screen->gpu, info);
443bf215546Sopenharmony_ci}
444bf215546Sopenharmony_ci
445bf215546Sopenharmony_cistatic const void *
446bf215546Sopenharmony_citegra_screen_get_compiler_options(struct pipe_screen *pscreen,
447bf215546Sopenharmony_ci                                  enum pipe_shader_ir ir,
448bf215546Sopenharmony_ci                                  unsigned int shader)
449bf215546Sopenharmony_ci{
450bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
451bf215546Sopenharmony_ci   const void *options = NULL;
452bf215546Sopenharmony_ci
453bf215546Sopenharmony_ci   if (screen->gpu->get_compiler_options)
454bf215546Sopenharmony_ci      options = screen->gpu->get_compiler_options(screen->gpu, ir, shader);
455bf215546Sopenharmony_ci
456bf215546Sopenharmony_ci   return options;
457bf215546Sopenharmony_ci}
458bf215546Sopenharmony_ci
459bf215546Sopenharmony_cistatic struct disk_cache *
460bf215546Sopenharmony_citegra_screen_get_disk_shader_cache(struct pipe_screen *pscreen)
461bf215546Sopenharmony_ci{
462bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
463bf215546Sopenharmony_ci
464bf215546Sopenharmony_ci   return screen->gpu->get_disk_shader_cache(screen->gpu);
465bf215546Sopenharmony_ci}
466bf215546Sopenharmony_ci
467bf215546Sopenharmony_cistatic struct pipe_resource *
468bf215546Sopenharmony_citegra_screen_resource_create_with_modifiers(struct pipe_screen *pscreen,
469bf215546Sopenharmony_ci                                            const struct pipe_resource *template,
470bf215546Sopenharmony_ci                                            const uint64_t *modifiers,
471bf215546Sopenharmony_ci                                            int count)
472bf215546Sopenharmony_ci{
473bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
474bf215546Sopenharmony_ci   struct pipe_resource tmpl = *template;
475bf215546Sopenharmony_ci   struct tegra_resource *resource;
476bf215546Sopenharmony_ci   int err;
477bf215546Sopenharmony_ci
478bf215546Sopenharmony_ci   resource = calloc(1, sizeof(*resource));
479bf215546Sopenharmony_ci   if (!resource)
480bf215546Sopenharmony_ci      return NULL;
481bf215546Sopenharmony_ci
482bf215546Sopenharmony_ci   /*
483bf215546Sopenharmony_ci    * Assume that resources created with modifiers will always be used for
484bf215546Sopenharmony_ci    * scanout. This is necessary because some of the APIs that are used to
485bf215546Sopenharmony_ci    * create resources with modifiers (e.g. gbm_bo_create_with_modifiers())
486bf215546Sopenharmony_ci    * can't pass along usage information. Adding that capability might be
487bf215546Sopenharmony_ci    * worth adding to remove this ambiguity. Not all future use-cases that
488bf215546Sopenharmony_ci    * involve modifiers may always be targetting scanout hardware.
489bf215546Sopenharmony_ci    */
490bf215546Sopenharmony_ci   tmpl.bind |= PIPE_BIND_SCANOUT;
491bf215546Sopenharmony_ci
492bf215546Sopenharmony_ci   resource->gpu = screen->gpu->resource_create_with_modifiers(screen->gpu,
493bf215546Sopenharmony_ci                                                               &tmpl,
494bf215546Sopenharmony_ci                                                               modifiers,
495bf215546Sopenharmony_ci                                                               count);
496bf215546Sopenharmony_ci   if (!resource->gpu)
497bf215546Sopenharmony_ci      goto free;
498bf215546Sopenharmony_ci
499bf215546Sopenharmony_ci   err = tegra_screen_import_resource(screen, resource);
500bf215546Sopenharmony_ci   if (err < 0)
501bf215546Sopenharmony_ci      goto destroy;
502bf215546Sopenharmony_ci
503bf215546Sopenharmony_ci   memcpy(&resource->base, resource->gpu, sizeof(*resource->gpu));
504bf215546Sopenharmony_ci   pipe_reference_init(&resource->base.reference, 1);
505bf215546Sopenharmony_ci   resource->base.screen = &screen->base;
506bf215546Sopenharmony_ci
507bf215546Sopenharmony_ci   return &resource->base;
508bf215546Sopenharmony_ci
509bf215546Sopenharmony_cidestroy:
510bf215546Sopenharmony_ci   screen->gpu->resource_destroy(screen->gpu, resource->gpu);
511bf215546Sopenharmony_cifree:
512bf215546Sopenharmony_ci   free(resource);
513bf215546Sopenharmony_ci   return NULL;
514bf215546Sopenharmony_ci}
515bf215546Sopenharmony_ci
516bf215546Sopenharmony_cistatic void tegra_screen_query_dmabuf_modifiers(struct pipe_screen *pscreen,
517bf215546Sopenharmony_ci                                                enum pipe_format format,
518bf215546Sopenharmony_ci                                                int max, uint64_t *modifiers,
519bf215546Sopenharmony_ci                                                unsigned int *external_only,
520bf215546Sopenharmony_ci                                                int *count)
521bf215546Sopenharmony_ci{
522bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
523bf215546Sopenharmony_ci
524bf215546Sopenharmony_ci   screen->gpu->query_dmabuf_modifiers(screen->gpu, format, max, modifiers,
525bf215546Sopenharmony_ci                                       external_only, count);
526bf215546Sopenharmony_ci}
527bf215546Sopenharmony_ci
528bf215546Sopenharmony_cistatic bool
529bf215546Sopenharmony_citegra_screen_is_dmabuf_modifier_supported(struct pipe_screen *pscreen,
530bf215546Sopenharmony_ci                                          uint64_t modifier,
531bf215546Sopenharmony_ci                                          enum pipe_format format,
532bf215546Sopenharmony_ci                                          bool *external_only)
533bf215546Sopenharmony_ci{
534bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
535bf215546Sopenharmony_ci
536bf215546Sopenharmony_ci   return screen->gpu->is_dmabuf_modifier_supported(screen->gpu, modifier,
537bf215546Sopenharmony_ci                                                    format, external_only);
538bf215546Sopenharmony_ci}
539bf215546Sopenharmony_ci
540bf215546Sopenharmony_cistatic unsigned int
541bf215546Sopenharmony_citegra_screen_get_dmabuf_modifier_planes(struct pipe_screen *pscreen,
542bf215546Sopenharmony_ci                                        uint64_t modifier,
543bf215546Sopenharmony_ci                                        enum pipe_format format)
544bf215546Sopenharmony_ci{
545bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
546bf215546Sopenharmony_ci
547bf215546Sopenharmony_ci   return screen->gpu->get_dmabuf_modifier_planes ?
548bf215546Sopenharmony_ci      screen->gpu->get_dmabuf_modifier_planes(screen->gpu, modifier, format) :
549bf215546Sopenharmony_ci      util_format_get_num_planes(format);
550bf215546Sopenharmony_ci}
551bf215546Sopenharmony_ci
552bf215546Sopenharmony_cistatic struct pipe_memory_object *
553bf215546Sopenharmony_citegra_screen_memobj_create_from_handle(struct pipe_screen *pscreen,
554bf215546Sopenharmony_ci                                       struct winsys_handle *handle,
555bf215546Sopenharmony_ci                                       bool dedicated)
556bf215546Sopenharmony_ci{
557bf215546Sopenharmony_ci   struct tegra_screen *screen = to_tegra_screen(pscreen);
558bf215546Sopenharmony_ci
559bf215546Sopenharmony_ci   return screen->gpu->memobj_create_from_handle(screen->gpu, handle,
560bf215546Sopenharmony_ci                                                 dedicated);
561bf215546Sopenharmony_ci}
562bf215546Sopenharmony_ci
563bf215546Sopenharmony_cistruct pipe_screen *
564bf215546Sopenharmony_citegra_screen_create(int fd)
565bf215546Sopenharmony_ci{
566bf215546Sopenharmony_ci   struct tegra_screen *screen;
567bf215546Sopenharmony_ci
568bf215546Sopenharmony_ci   screen = calloc(1, sizeof(*screen));
569bf215546Sopenharmony_ci   if (!screen)
570bf215546Sopenharmony_ci      return NULL;
571bf215546Sopenharmony_ci
572bf215546Sopenharmony_ci   screen->fd = fd;
573bf215546Sopenharmony_ci
574bf215546Sopenharmony_ci   screen->gpu_fd = loader_open_render_node("nouveau");
575bf215546Sopenharmony_ci   if (screen->gpu_fd < 0) {
576bf215546Sopenharmony_ci      if (errno != ENOENT)
577bf215546Sopenharmony_ci         fprintf(stderr, "failed to open GPU device: %s\n", strerror(errno));
578bf215546Sopenharmony_ci
579bf215546Sopenharmony_ci      free(screen);
580bf215546Sopenharmony_ci      return NULL;
581bf215546Sopenharmony_ci   }
582bf215546Sopenharmony_ci
583bf215546Sopenharmony_ci   screen->gpu = nouveau_drm_screen_create(screen->gpu_fd);
584bf215546Sopenharmony_ci   if (!screen->gpu) {
585bf215546Sopenharmony_ci      fprintf(stderr, "failed to create GPU screen\n");
586bf215546Sopenharmony_ci      close(screen->gpu_fd);
587bf215546Sopenharmony_ci      free(screen);
588bf215546Sopenharmony_ci      return NULL;
589bf215546Sopenharmony_ci   }
590bf215546Sopenharmony_ci
591bf215546Sopenharmony_ci   screen->base.destroy = tegra_screen_destroy;
592bf215546Sopenharmony_ci   screen->base.get_name = tegra_screen_get_name;
593bf215546Sopenharmony_ci   screen->base.get_vendor = tegra_screen_get_vendor;
594bf215546Sopenharmony_ci   screen->base.get_device_vendor = tegra_screen_get_device_vendor;
595bf215546Sopenharmony_ci   screen->base.get_param = tegra_screen_get_param;
596bf215546Sopenharmony_ci   screen->base.get_paramf = tegra_screen_get_paramf;
597bf215546Sopenharmony_ci   screen->base.get_shader_param = tegra_screen_get_shader_param;
598bf215546Sopenharmony_ci   screen->base.get_video_param = tegra_screen_get_video_param;
599bf215546Sopenharmony_ci   screen->base.get_compute_param = tegra_screen_get_compute_param;
600bf215546Sopenharmony_ci   screen->base.get_timestamp = tegra_screen_get_timestamp;
601bf215546Sopenharmony_ci   screen->base.context_create = tegra_screen_context_create;
602bf215546Sopenharmony_ci   screen->base.is_format_supported = tegra_screen_is_format_supported;
603bf215546Sopenharmony_ci   screen->base.is_video_format_supported = tegra_screen_is_video_format_supported;
604bf215546Sopenharmony_ci
605bf215546Sopenharmony_ci   /* allow fallback implementation if GPU driver doesn't implement it */
606bf215546Sopenharmony_ci   if (screen->gpu->can_create_resource)
607bf215546Sopenharmony_ci      screen->base.can_create_resource = tegra_screen_can_create_resource;
608bf215546Sopenharmony_ci
609bf215546Sopenharmony_ci   screen->base.resource_create = tegra_screen_resource_create;
610bf215546Sopenharmony_ci   screen->base.resource_create_front = tegra_screen_resource_create_front;
611bf215546Sopenharmony_ci   screen->base.resource_from_handle = tegra_screen_resource_from_handle;
612bf215546Sopenharmony_ci   screen->base.resource_from_user_memory = tegra_screen_resource_from_user_memory;
613bf215546Sopenharmony_ci   screen->base.resource_get_handle = tegra_screen_resource_get_handle;
614bf215546Sopenharmony_ci   screen->base.resource_destroy = tegra_screen_resource_destroy;
615bf215546Sopenharmony_ci
616bf215546Sopenharmony_ci   screen->base.flush_frontbuffer = tegra_screen_flush_frontbuffer;
617bf215546Sopenharmony_ci   screen->base.fence_reference = tegra_screen_fence_reference;
618bf215546Sopenharmony_ci   screen->base.fence_finish = tegra_screen_fence_finish;
619bf215546Sopenharmony_ci   screen->base.fence_get_fd = tegra_screen_fence_get_fd;
620bf215546Sopenharmony_ci
621bf215546Sopenharmony_ci   screen->base.get_driver_query_info = tegra_screen_get_driver_query_info;
622bf215546Sopenharmony_ci   screen->base.get_driver_query_group_info = tegra_screen_get_driver_query_group_info;
623bf215546Sopenharmony_ci   screen->base.query_memory_info = tegra_screen_query_memory_info;
624bf215546Sopenharmony_ci
625bf215546Sopenharmony_ci   screen->base.get_compiler_options = tegra_screen_get_compiler_options;
626bf215546Sopenharmony_ci   screen->base.get_disk_shader_cache = tegra_screen_get_disk_shader_cache;
627bf215546Sopenharmony_ci
628bf215546Sopenharmony_ci   screen->base.resource_create_with_modifiers = tegra_screen_resource_create_with_modifiers;
629bf215546Sopenharmony_ci   screen->base.query_dmabuf_modifiers = tegra_screen_query_dmabuf_modifiers;
630bf215546Sopenharmony_ci   screen->base.is_dmabuf_modifier_supported = tegra_screen_is_dmabuf_modifier_supported;
631bf215546Sopenharmony_ci   screen->base.get_dmabuf_modifier_planes = tegra_screen_get_dmabuf_modifier_planes;
632bf215546Sopenharmony_ci   screen->base.memobj_create_from_handle = tegra_screen_memobj_create_from_handle;
633bf215546Sopenharmony_ci
634bf215546Sopenharmony_ci   return &screen->base;
635bf215546Sopenharmony_ci}
636