OSDN Git Service

Add DRI-based generic backend
[android-x86/external-minigbm.git] / dri.c
1 /*
2  * Copyright 2017 Advanced Micro Devices. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6
7 #if defined(DRI_GENERIC_DRV) || defined(DRV_AMDGPU)
8
9 #include <assert.h>
10 #include <dlfcn.h>
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <stdbool.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <sys/mman.h>
17 #include <unistd.h>
18 #include <xf86drm.h>
19
20 #include "dri.h"
21 #include "drv_priv.h"
22 #include "helpers.h"
23 #include "util.h"
24
25 #ifdef DRI_GENERIC_DRV
26 #include <loader.h>
27 #endif
28
29 static const struct {
30         uint32_t drm_format;
31         int dri_image_format;
32 } drm_to_dri_image_formats[] = {
33         { DRM_FORMAT_R8, __DRI_IMAGE_FORMAT_R8 },
34         { DRM_FORMAT_GR88, __DRI_IMAGE_FORMAT_GR88 },
35         { DRM_FORMAT_RGB565, __DRI_IMAGE_FORMAT_RGB565 },
36         { DRM_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_XRGB8888 },
37         { DRM_FORMAT_ARGB8888, __DRI_IMAGE_FORMAT_ARGB8888 },
38         { DRM_FORMAT_XBGR8888, __DRI_IMAGE_FORMAT_XBGR8888 },
39         { DRM_FORMAT_ABGR8888, __DRI_IMAGE_FORMAT_ABGR8888 },
40         { DRM_FORMAT_XRGB2101010, __DRI_IMAGE_FORMAT_XRGB2101010 },
41         { DRM_FORMAT_XBGR2101010, __DRI_IMAGE_FORMAT_XBGR2101010 },
42         { DRM_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ARGB2101010 },
43         { DRM_FORMAT_ABGR2101010, __DRI_IMAGE_FORMAT_ABGR2101010 },
44 };
45
46 static int drm_format_to_dri_format(uint32_t drm_format)
47 {
48         uint32_t i;
49         for (i = 0; i < ARRAY_SIZE(drm_to_dri_image_formats); i++) {
50                 if (drm_to_dri_image_formats[i].drm_format == drm_format)
51                         return drm_to_dri_image_formats[i].dri_image_format;
52         }
53
54         return 0;
55 }
56
57 static bool lookup_extension(const __DRIextension *const *extensions, const char *name,
58                              int min_version, const __DRIextension **dst)
59 {
60         while (*extensions) {
61                 if ((*extensions)->name && !strcmp((*extensions)->name, name) &&
62                     (*extensions)->version >= min_version) {
63                         *dst = *extensions;
64                         return true;
65                 }
66
67                 extensions++;
68         }
69
70         return false;
71 }
72
73 int dri_bo_get_plane_fd(struct bo *bo, size_t plane)
74 {
75         struct dri_driver *dri = bo->drv->priv;
76         __DRIimage *plane_image = NULL;
77         int fd = -1;
78
79         plane_image = dri->image_extension->fromPlanar(bo->priv, plane, NULL);
80         __DRIimage *image = plane_image ? plane_image : bo->priv;
81
82         dri->image_extension->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
83
84         if (plane_image)
85                 dri->image_extension->destroyImage(plane_image);
86
87         return fd;
88 }
89 /*
90  * The DRI GEM namespace may be different from the minigbm's driver GEM namespace. We have
91  * to import into minigbm.
92  */
93 static int import_into_minigbm(struct dri_driver *dri, struct bo *bo)
94 {
95         int ret, modifier_upper, modifier_lower, num_planes, i, j;
96         off_t dmabuf_sizes[DRV_MAX_PLANES];
97         __DRIimage *plane_image = NULL;
98
99         if (dri->image_extension->queryImage(bo->priv, __DRI_IMAGE_ATTRIB_MODIFIER_UPPER,
100                                              &modifier_upper) &&
101             dri->image_extension->queryImage(bo->priv, __DRI_IMAGE_ATTRIB_MODIFIER_LOWER,
102                                              &modifier_lower)) {
103                 bo->meta.format_modifiers[0] =
104                     ((uint64_t)modifier_upper << 32) | (uint32_t)modifier_lower;
105         } else {
106                 bo->meta.format_modifiers[0] = DRM_FORMAT_MOD_INVALID;
107         }
108
109         if (!dri->image_extension->queryImage(bo->priv, __DRI_IMAGE_ATTRIB_NUM_PLANES,
110                                               &num_planes)) {
111                 return -errno;
112         }
113
114         for (i = 0; i < num_planes; ++i) {
115                 int prime_fd, stride, offset;
116                 plane_image = dri->image_extension->fromPlanar(bo->priv, i, NULL);
117                 __DRIimage *image = plane_image ? plane_image : bo->priv;
118
119                 if (i)
120                         bo->meta.format_modifiers[i] = bo->meta.format_modifiers[0];
121
122                 if (!dri->image_extension->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride) ||
123                     !dri->image_extension->queryImage(image, __DRI_IMAGE_ATTRIB_OFFSET, &offset)) {
124                         ret = -errno;
125                         goto cleanup;
126                 }
127
128                 if (!dri->image_extension->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &prime_fd)) {
129                         ret = -errno;
130                         goto cleanup;
131                 }
132
133                 dmabuf_sizes[i] = lseek(prime_fd, 0, SEEK_END);
134                 if (dmabuf_sizes[i] == (off_t)-1) {
135                         ret = -errno;
136                         close(prime_fd);
137                         goto cleanup;
138                 }
139
140                 lseek(prime_fd, 0, SEEK_SET);
141
142                 close(prime_fd);
143
144                 if (!dri->image_extension->queryImage(image, __DRI_IMAGE_ATTRIB_HANDLE,
145                                                       &bo->handles[i].s32)) {
146                         drv_log("queryImage() failed with %s\n", strerror(errno));
147                         ret = -errno;
148                         goto cleanup;
149                 }
150
151                 bo->meta.strides[i] = stride;
152                 bo->meta.offsets[i] = offset;
153
154                 if (plane_image)
155                         dri->image_extension->destroyImage(plane_image);
156         }
157
158         for (i = 0; i < num_planes; ++i) {
159                 off_t next_plane = dmabuf_sizes[i];
160                 for (j = 0; j < num_planes; ++j) {
161                         if (bo->meta.offsets[j] < next_plane &&
162                             bo->meta.offsets[j] > bo->meta.offsets[i] &&
163                             bo->handles[j].u32 == bo->handles[i].u32)
164                                 next_plane = bo->meta.offsets[j];
165                 }
166
167                 bo->meta.sizes[i] = next_plane - bo->meta.offsets[i];
168
169                 /* This is kind of misleading if different planes use
170                    different dmabufs. */
171                 bo->meta.total_size += bo->meta.sizes[i];
172         }
173
174         return 0;
175
176 cleanup:
177         if (plane_image)
178                 dri->image_extension->destroyImage(plane_image);
179         while (--i >= 0) {
180                 for (j = 0; j <= i; ++j)
181                         if (bo->handles[j].u32 == bo->handles[i].u32)
182                                 break;
183
184                 /* Multiple equivalent handles) */
185                 if (i == j)
186                         break;
187         }
188         return ret;
189 }
190
191 /*
192  * The caller is responsible for setting drv->priv to a structure that derives from dri_driver.
193  */
194 int dri_init(struct driver *drv, const char *dri_so_path, const char *driver_suffix)
195 {
196         char fname[128];
197         const __DRIextension **(*get_extensions)();
198         const __DRIextension *loader_extensions[] = { NULL };
199
200         struct dri_driver *dri = drv->priv;
201
202         dri->fd = open(drmGetDeviceNameFromFd(drv_get_fd(drv)), O_RDWR);
203         if (dri->fd < 0)
204                 return -ENODEV;
205
206         dri->driver_handle = dlopen(dri_so_path, RTLD_NOW | RTLD_GLOBAL);
207         if (!dri->driver_handle)
208                 goto close_dri_fd;
209
210         snprintf(fname, sizeof(fname), __DRI_DRIVER_GET_EXTENSIONS "_%s", driver_suffix);
211         get_extensions = dlsym(dri->driver_handle, fname);
212         if (!get_extensions)
213                 goto free_handle;
214
215         dri->extensions = get_extensions();
216         if (!dri->extensions)
217                 goto free_handle;
218
219         if (!lookup_extension(dri->extensions, __DRI_CORE, 2,
220                               (const __DRIextension **)&dri->core_extension))
221                 goto free_handle;
222
223         /* Version 4 for createNewScreen2 */
224         if (!lookup_extension(dri->extensions, __DRI_DRI2, 4,
225                               (const __DRIextension **)&dri->dri2_extension))
226                 goto free_handle;
227
228         dri->device = dri->dri2_extension->createNewScreen2(0, dri->fd, loader_extensions,
229                                                             dri->extensions, &dri->configs, NULL);
230         if (!dri->device)
231                 goto free_handle;
232
233         dri->context =
234             dri->dri2_extension->createNewContext(dri->device, *dri->configs, NULL, NULL);
235
236         if (!dri->context)
237                 goto free_screen;
238
239         if (!lookup_extension(dri->core_extension->getExtensions(dri->device), __DRI_IMAGE, 12,
240                               (const __DRIextension **)&dri->image_extension))
241                 goto free_context;
242
243         if (!lookup_extension(dri->core_extension->getExtensions(dri->device), __DRI2_FLUSH, 4,
244                               (const __DRIextension **)&dri->flush_extension))
245                 goto free_context;
246
247         return 0;
248
249 free_context:
250         dri->core_extension->destroyContext(dri->context);
251 free_screen:
252         dri->core_extension->destroyScreen(dri->device);
253 free_handle:
254         dlclose(dri->driver_handle);
255         dri->driver_handle = NULL;
256 close_dri_fd:
257         close(dri->fd);
258         return -ENODEV;
259 }
260 /*
261  * The caller is responsible for setting drv->priv to a structure that derives from dri_driver.
262  */
263 int dri_init2(struct driver *drv)
264 {
265 #ifdef DRI_GENERIC_DRV
266         char dri_pathname[64];
267         char drv_suffix[32];
268
269         char *drv_name = loader_get_driver_for_fd(drv->fd);
270
271         sprintf(dri_pathname, STRINGIZE(DRI_DRIVER_DIR) "/%s_dri.so", drv_name);
272
273         strcpy(drv_suffix, drv_name);
274         free(drv_name);
275
276         /* replace all '-' chars with '_' in drv_suffix to use in dlsym() */
277         char *current_pos = strchr(drv_suffix, '-');
278         while (current_pos) {
279                 *current_pos = '_';
280                 current_pos = strchr(current_pos, '-');
281         }
282
283         if (dri_init(drv, dri_pathname, drv_suffix)) {
284                 drv_log("dri_init failed for (%s) , (%s)", dri_pathname, drv_suffix);
285                 return -ENODEV;
286         }
287
288         return 0;
289 #else
290         return -ENOTSUPP;
291 #endif
292 }
293
294 /*
295  * The caller is responsible for freeing drv->priv.
296  */
297 void dri_close(struct driver *drv)
298 {
299         struct dri_driver *dri = drv->priv;
300
301         dri->core_extension->destroyContext(dri->context);
302         dri->core_extension->destroyScreen(dri->device);
303         dlclose(dri->driver_handle);
304         dri->driver_handle = NULL;
305         close(dri->fd);
306 }
307
308 int dri_bo_create_common(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
309                          uint64_t use_flags, const uint64_t *modifiers, uint32_t modifier_count)
310 {
311         uint32_t width_ = width;
312         uint32_t height_ = height;
313         unsigned int dri_use;
314         int ret, dri_format;
315         int dri_format_unavailable = false;
316         struct dri_driver *dri = bo->drv->priv;
317
318         dri_format = drm_format_to_dri_format(format);
319         /* Video buffers can't be allocated using DRI */
320         if (!dri_format)
321                 dri_format_unavailable = true;
322
323         /* Gallium drivers require shared to get the handle and stride. */
324         dri_use = __DRI_IMAGE_USE_SHARE;
325         if (use_flags & BO_USE_SCANOUT)
326                 dri_use |= __DRI_IMAGE_USE_SCANOUT;
327         if (use_flags & BO_USE_CURSOR)
328                 dri_use |= __DRI_IMAGE_USE_CURSOR;
329         if (use_flags & (BO_USE_LINEAR | BO_USE_SW_MASK))
330                 dri_use |= __DRI_IMAGE_USE_LINEAR;
331
332         if (dri_format_unavailable) {
333                 int stride = drv_stride_from_format(format, width, 0);
334                 drv_bo_from_format(bo, stride, height, format);
335                 dri_format = __DRI_IMAGE_FORMAT_R8;
336                 dri_use |= __DRI_IMAGE_USE_LINEAR;
337                 width_ = stride /  drv_bytes_per_pixel_from_format(format, 0);
338                 height_ = DIV_ROUND_UP(bo->meta.total_size, width_);
339         }
340
341         if (modifier_count == 0) {
342                 bo->priv = dri->image_extension->createImage(dri->device, width_, height_,
343                                                              dri_format, dri_use, NULL);
344         } else {
345                 if (!dri->image_extension->createImageWithModifiers) {
346                         return -ENOENT;
347                 }
348                 bo->priv = dri->image_extension->createImageWithModifiers(
349                     dri->device, width, height, dri_format, modifiers, modifier_count, NULL);
350         }
351
352         if (!bo->priv) {
353                 ret = -errno;
354                 return ret;
355         }
356
357         if (dri_format_unavailable) {
358                 __DRIimage *plane_image = dri->image_extension->fromPlanar(bo->priv, 0, NULL);
359                 __DRIimage *image = plane_image ? plane_image : bo->priv;
360
361                 if (!dri->image_extension->queryImage(image, __DRI_IMAGE_ATTRIB_HANDLE,
362                                                       &bo->handles[0].s32)) {
363                         drv_log("queryImage() failed with error %s\n", strerror(errno));
364                         ret = -errno;
365                         goto free_image;
366                 }
367
368                 if (!dri->image_extension->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE,
369                                                       (int32_t *)&bo->meta.strides[0])) {
370                         drv_log("queryImage() failed with error %s\n", strerror(errno));
371                         ret = -errno;
372                         goto free_image;
373                 }
374
375                 drv_bo_from_format(bo, bo->meta.strides[0], height, format);
376
377                 if (plane_image)
378                         dri->image_extension->destroyImage(plane_image);
379
380                 for (size_t plane = 1; plane < bo->meta.num_planes; plane++)
381                         bo->handles[plane].u32 = bo->handles[0].u32;
382         } else {
383                 ret = import_into_minigbm(dri, bo);
384                 if (ret)
385                         goto free_image;
386         }
387
388         return 0;
389
390 free_image:
391         dri->image_extension->destroyImage(bo->priv);
392         return ret;
393 }
394
395 int dri_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
396                   uint64_t use_flags)
397 {
398         return dri_bo_create_common(bo, width, height, format, use_flags, NULL, 0);
399 }
400
401 int dri_bo_create_with_modifiers(struct bo *bo, uint32_t width, uint32_t height, uint32_t format,
402                                  const uint64_t *modifiers, uint32_t modifier_count)
403 {
404         return dri_bo_create_common(bo, width, height, format, 0, modifiers, modifier_count);
405 }
406
407 int dri_bo_import(struct bo *bo, struct drv_import_fd_data *data)
408 {
409         int ret;
410         struct dri_driver *dri = bo->drv->priv;
411
412         if (data->format_modifiers[0] != DRM_FORMAT_MOD_INVALID) {
413                 unsigned error;
414
415                 if (!dri->image_extension->createImageFromDmaBufs2)
416                         return -ENOSYS;
417
418                 // clang-format off
419                 bo->priv = dri->image_extension->createImageFromDmaBufs2(dri->device, data->width, data->height,
420                                                                          drv_get_standard_fourcc(data->format),
421                                                                          data->format_modifiers[0],
422                                                                          data->fds,
423                                                                          bo->meta.num_planes,
424                                                                          (int *)data->strides,
425                                                                          (int *)data->offsets,
426                                                                          __DRI_YUV_COLOR_SPACE_UNDEFINED,
427                                                                          __DRI_YUV_RANGE_UNDEFINED,
428                                                                          __DRI_YUV_CHROMA_SITING_UNDEFINED,
429                                                                          __DRI_YUV_CHROMA_SITING_UNDEFINED,
430                                                                          &error, NULL);
431                 // clang-format on
432
433                 /* Could translate the DRI error, but the Mesa GBM also returns ENOSYS. */
434                 if (!bo->priv)
435                         return -ENOSYS;
436         } else {
437                 // clang-format off
438                 bo->priv = dri->image_extension->createImageFromFds(dri->device, data->width, data->height,
439                                                                     drv_get_standard_fourcc(data->format), data->fds,
440                                                                     bo->meta.num_planes,
441                                                                     (int *)data->strides,
442                                                                     (int *)data->offsets, NULL);
443                 // clang-format on
444                 if (!bo->priv)
445                         return -errno;
446         }
447
448         ret = import_into_minigbm(dri, bo);
449         if (ret) {
450                 dri->image_extension->destroyImage(bo->priv);
451                 return ret;
452         }
453
454         return 0;
455 }
456
457 int dri_bo_destroy(struct bo *bo)
458 {
459         struct dri_driver *dri = bo->drv->priv;
460
461         assert(bo->priv);
462         dri->image_extension->destroyImage(bo->priv);
463         bo->priv = NULL;
464         return 0;
465 }
466
467 /*
468  * Map an image plane.
469  *
470  * This relies on the underlying driver to do a decompressing and/or de-tiling
471  * blit if necessary,
472  *
473  * This function itself is not thread-safe; we rely on the fact that the caller
474  * locks a per-driver mutex.
475  */
476 void *dri_bo_map(struct bo *bo, struct vma *vma, size_t plane, uint32_t map_flags)
477 {
478         struct dri_driver *dri = bo->drv->priv;
479
480         /* GBM flags and DRI flags are the same. */
481         vma->addr = dri->image_extension->mapImage(dri->context, bo->priv, 0, 0, bo->meta.width,
482                                                    bo->meta.height, map_flags,
483                                                    (int *)&vma->map_strides[plane], &vma->priv);
484         if (!vma->addr)
485                 return MAP_FAILED;
486
487         return vma->addr;
488 }
489
490 int dri_bo_unmap(struct bo *bo, struct vma *vma)
491 {
492         struct dri_driver *dri = bo->drv->priv;
493
494         assert(vma->priv);
495         dri->image_extension->unmapImage(dri->context, bo->priv, vma->priv);
496
497         /*
498          * From gbm_dri.c in Mesa:
499          *
500          * "Not all DRI drivers use direct maps. They may queue up DMA operations
501          *  on the mapping context. Since there is no explicit gbm flush mechanism,
502          *  we need to flush here."
503          */
504
505         dri->flush_extension->flush_with_flags(dri->context, NULL, __DRI2_FLUSH_CONTEXT, 0);
506         return 0;
507 }
508
509 size_t dri_num_planes_from_modifier(struct driver *drv, uint32_t format, uint64_t modifier)
510 {
511         struct dri_driver *dri = drv->priv;
512         if (!dri->image_extension->queryDmaBufFormatModifierAttribs) {
513                 /* We do not do any modifier checks here. The create will fail
514                  * later if the modifier is not supported. */
515                 return drv_num_planes_from_format(format);
516         }
517
518         uint64_t planes;
519         GLboolean ret = dri->image_extension->queryDmaBufFormatModifierAttribs(
520             dri->device, format, modifier, __DRI_IMAGE_ATTRIB_NUM_PLANES, &planes);
521         if (!ret)
522                 return 0;
523
524         return planes;
525 }
526
527 #endif