OSDN Git Service

minigbm: mediatek: add support HAL_PIXEL_FORMAT_YV12
[android-x86/external-minigbm.git] / drv.c
1 /*
2  * Copyright (c) 2016 The Chromium OS Authors. 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 #include <assert.h>
7 #include <fcntl.h>
8 #include <pthread.h>
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/mman.h>
14 #include <xf86drm.h>
15
16 #include "drv_priv.h"
17 #include "helpers.h"
18 #include "util.h"
19
20 #ifdef DRV_AMDGPU
21 extern struct backend backend_amdgpu;
22 #endif
23 extern struct backend backend_cirrus;
24 extern struct backend backend_evdi;
25 #ifdef DRV_EXYNOS
26 extern struct backend backend_exynos;
27 #endif
28 extern struct backend backend_gma500;
29 #ifdef DRV_I915
30 extern struct backend backend_i915;
31 #endif
32 #ifdef DRV_MARVELL
33 extern struct backend backend_marvell;
34 #endif
35 #ifdef DRV_MEDIATEK
36 extern struct backend backend_mediatek;
37 #endif
38 #ifdef DRV_ROCKCHIP
39 extern struct backend backend_rockchip;
40 #endif
41 #ifdef DRV_TEGRA
42 extern struct backend backend_tegra;
43 #endif
44 extern struct backend backend_udl;
45 extern struct backend backend_vgem;
46 extern struct backend backend_virtio_gpu;
47
48 static struct backend *drv_get_backend(int fd)
49 {
50         drmVersionPtr drm_version;
51         unsigned int i;
52
53         drm_version = drmGetVersion(fd);
54
55         if (!drm_version)
56                 return NULL;
57
58         struct backend *backend_list[] = {
59 #ifdef DRV_AMDGPU
60                 &backend_amdgpu,
61 #endif
62                 &backend_cirrus,
63                 &backend_evdi,
64 #ifdef DRV_EXYNOS
65                 &backend_exynos,
66 #endif
67                 &backend_gma500,
68 #ifdef DRV_I915
69                 &backend_i915,
70 #endif
71 #ifdef DRV_MARVELL
72                 &backend_marvell,
73 #endif
74 #ifdef DRV_MEDIATEK
75                 &backend_mediatek,
76 #endif
77 #ifdef DRV_ROCKCHIP
78                 &backend_rockchip,
79 #endif
80 #ifdef DRV_TEGRA
81                 &backend_tegra,
82 #endif
83                 &backend_udl,
84                 &backend_vgem,
85                 &backend_virtio_gpu,
86         };
87
88         for(i = 0; i < ARRAY_SIZE(backend_list); i++)
89                 if (!strcmp(drm_version->name, backend_list[i]->name)) {
90                         drmFreeVersion(drm_version);
91                         return backend_list[i];
92                 }
93
94         drmFreeVersion(drm_version);
95         return NULL;
96 }
97
98 struct driver *drv_create(int fd)
99 {
100         struct driver *drv;
101         int ret;
102
103         drv = (struct driver *) calloc(1, sizeof(*drv));
104
105         if (!drv)
106                 return NULL;
107
108         drv->fd = fd;
109         drv->backend = drv_get_backend(fd);
110
111         if (!drv->backend)
112                 goto free_driver;
113
114         if (pthread_mutex_init(&drv->driver_lock, NULL))
115                 goto free_driver;
116
117         drv->buffer_table = drmHashCreate();
118         if (!drv->buffer_table)
119                 goto free_lock;
120
121         drv->map_table = drmHashCreate();
122         if (!drv->map_table)
123                 goto free_buffer_table;
124
125         LIST_INITHEAD(&drv->backend->combinations);
126
127         if (drv->backend->init) {
128                 ret = drv->backend->init(drv);
129                 if (ret)
130                         goto free_map_table;
131         }
132
133         return drv;
134
135 free_map_table:
136         drmHashDestroy(drv->map_table);
137 free_buffer_table:
138         drmHashDestroy(drv->buffer_table);
139 free_lock:
140         pthread_mutex_destroy(&drv->driver_lock);
141 free_driver:
142         free(drv);
143         return NULL;
144 }
145
146 void drv_destroy(struct driver *drv)
147 {
148         pthread_mutex_lock(&drv->driver_lock);
149
150         if (drv->backend->close)
151                 drv->backend->close(drv);
152
153         drmHashDestroy(drv->buffer_table);
154         drmHashDestroy(drv->map_table);
155
156         list_for_each_entry_safe(struct combination_list_element, elem,
157                                  &drv->backend->combinations, link) {
158                 LIST_DEL(&elem->link);
159                 free(elem);
160         }
161
162         pthread_mutex_unlock(&drv->driver_lock);
163         pthread_mutex_destroy(&drv->driver_lock);
164
165         free(drv);
166 }
167
168 int drv_get_fd(struct driver *drv)
169 {
170         return drv->fd;
171 }
172
173 const char *
174 drv_get_name(struct driver *drv)
175 {
176         return drv->backend->name;
177 }
178
179 int drv_is_combination_supported(struct driver *drv, uint32_t format,
180                                  uint64_t usage, uint64_t modifier)
181 {
182
183         if (format == DRM_FORMAT_NONE || usage == BO_USE_NONE)
184                 return 0;
185
186         list_for_each_entry(struct combination_list_element, elem,
187                             &drv->backend->combinations, link) {
188                 if (format == elem->combination.format &&
189                     usage == (elem->combination.usage & usage) &&
190                     modifier == elem->combination.modifier)
191                         return 1;
192         }
193
194         return 0;
195 }
196
197 struct bo *drv_bo_new(struct driver *drv, uint32_t width, uint32_t height,
198                       uint32_t format)
199 {
200
201         struct bo *bo;
202         bo = (struct bo *) calloc(1, sizeof(*bo));
203
204         if (!bo)
205                 return NULL;
206
207         bo->drv = drv;
208         bo->width = width;
209         bo->height = height;
210         bo->format = format;
211         bo->num_planes = drv_num_planes_from_format(format);
212
213         if (!bo->num_planes) {
214                 free(bo);
215                 return NULL;
216         }
217
218         return bo;
219 }
220
221 struct bo *drv_bo_create(struct driver *drv, uint32_t width, uint32_t height,
222                          uint32_t format, uint64_t flags)
223 {
224         int ret;
225         size_t plane;
226         struct bo *bo;
227
228         bo = drv_bo_new(drv, width, height, format);
229
230         if (!bo)
231                 return NULL;
232
233         ret = drv->backend->bo_create(bo, width, height, format, flags);
234
235         if (ret) {
236                 free(bo);
237                 return NULL;
238         }
239
240         pthread_mutex_lock(&drv->driver_lock);
241
242         for (plane = 0; plane < bo->num_planes; plane++)
243                 drv_increment_reference_count(drv, bo, plane);
244
245         pthread_mutex_unlock(&drv->driver_lock);
246
247         return bo;
248 }
249
250 void drv_bo_destroy(struct bo *bo)
251 {
252         size_t plane;
253         uintptr_t total = 0;
254         struct driver *drv = bo->drv;
255
256         pthread_mutex_lock(&drv->driver_lock);
257
258         for (plane = 0; plane < bo->num_planes; plane++)
259                 drv_decrement_reference_count(drv, bo, plane);
260
261         for (plane = 0; plane < bo->num_planes; plane++)
262                 total += drv_get_reference_count(drv, bo, plane);
263
264         pthread_mutex_unlock(&drv->driver_lock);
265
266         if (total == 0)
267                 bo->drv->backend->bo_destroy(bo);
268
269         free(bo);
270 }
271
272 struct bo *drv_bo_import(struct driver *drv, struct drv_import_fd_data *data)
273 {
274         int ret;
275         size_t plane;
276         struct bo *bo;
277         struct drm_prime_handle prime_handle;
278
279         bo = drv_bo_new(drv, data->width, data->height, data->format);
280
281         if (!bo)
282                 return NULL;
283
284         for (plane = 0; plane < bo->num_planes; plane++) {
285
286                 memset(&prime_handle, 0, sizeof(prime_handle));
287                 prime_handle.fd = data->fds[plane];
288
289                 ret = drmIoctl(drv->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE,
290                                &prime_handle);
291
292                 if (ret) {
293                         fprintf(stderr, "drv: DRM_IOCTL_PRIME_FD_TO_HANDLE failed "
294                                 "(fd=%u)\n", prime_handle.fd);
295
296                         if (plane > 0) {
297                                 bo->num_planes = plane;
298                                 drv_bo_destroy(bo);
299                         } else {
300                                 free(bo);
301                         }
302
303                         return NULL;
304                 }
305
306                 bo->handles[plane].u32 = prime_handle.handle;
307                 bo->strides[plane] = data->strides[plane];
308                 bo->offsets[plane] = data->offsets[plane];
309                 bo->sizes[plane] = data->sizes[plane];
310                 bo->format_modifiers[plane] = data->format_modifiers[plane];
311                 bo->total_size += data->sizes[plane];
312
313                 pthread_mutex_lock(&drv->driver_lock);
314                 drv_increment_reference_count(drv, bo, plane);
315                 pthread_mutex_unlock(&drv->driver_lock);
316         }
317
318         return bo;
319 }
320
321 void *drv_bo_map(struct bo *bo, uint32_t x, uint32_t y, uint32_t width,
322                  uint32_t height, uint32_t flags, void **map_data, size_t plane)
323 {
324         void *ptr;
325         uint8_t *addr;
326         size_t offset;
327         struct map_info *data;
328
329         assert(width > 0);
330         assert(height > 0);
331         assert(x + width <= drv_bo_get_width(bo));
332         assert(y + height <= drv_bo_get_height(bo));
333
334         pthread_mutex_lock(&bo->drv->driver_lock);
335
336         if (!drmHashLookup(bo->drv->map_table, bo->handles[plane].u32, &ptr)) {
337                 data = (struct map_info *) ptr;
338                 data->refcount++;
339                 goto success;
340         }
341
342         data = calloc(1, sizeof(*data));
343         addr = bo->drv->backend->bo_map(bo, data, plane);
344         if (addr == MAP_FAILED) {
345                 *map_data = NULL;
346                 free(data);
347                 pthread_mutex_unlock(&bo->drv->driver_lock);
348                 return MAP_FAILED;
349         }
350
351         data->refcount = 1;
352         data->addr = addr;
353         data->handle = bo->handles[plane].u32;
354         drmHashInsert(bo->drv->buffer_table, bo->handles[plane].u32,
355                       (void *) data);
356
357 success:
358         *map_data = (void *) data;
359         offset = drv_bo_get_plane_stride(bo, plane) * y;
360         offset += drv_stride_from_format(bo->format, x, plane);
361         addr = (uint8_t *) data->addr;
362         addr += drv_bo_get_plane_offset(bo, plane) + offset;
363         pthread_mutex_unlock(&bo->drv->driver_lock);
364
365         return (void *) addr;
366 }
367
368 int drv_bo_unmap(struct bo *bo, void *map_data)
369 {
370         struct map_info *data = map_data;
371         int ret = 0;
372
373         assert(data);
374         assert(data->refcount >= 0);
375
376         pthread_mutex_lock(&bo->drv->driver_lock);
377
378         if (!--data->refcount) {
379                 ret = munmap(data->addr, data->length);
380                 drmHashDelete(bo->drv->map_table, data->handle);
381                 free(data);
382         }
383
384         pthread_mutex_unlock(&bo->drv->driver_lock);
385
386         return ret;
387 }
388
389 uint32_t drv_bo_get_width(struct bo *bo)
390 {
391         return bo->width;
392 }
393
394 uint32_t drv_bo_get_height(struct bo *bo)
395 {
396         return bo->height;
397 }
398
399 uint32_t drv_bo_get_stride_or_tiling(struct bo *bo)
400 {
401         return bo->tiling ? bo->tiling : drv_bo_get_plane_stride(bo, 0);
402 }
403
404 size_t drv_bo_get_num_planes(struct bo *bo)
405 {
406         return bo->num_planes;
407 }
408
409 union bo_handle drv_bo_get_plane_handle(struct bo *bo, size_t plane)
410 {
411         return bo->handles[plane];
412 }
413
414 #ifndef DRM_RDWR
415 #define DRM_RDWR O_RDWR
416 #endif
417
418 int drv_bo_get_plane_fd(struct bo *bo, size_t plane)
419 {
420
421         int ret, fd;
422         assert(plane < bo->num_planes);
423
424         ret = drmPrimeHandleToFD(bo->drv->fd, bo->handles[plane].u32,
425                                  DRM_CLOEXEC | DRM_RDWR, &fd);
426
427         return (ret) ? ret : fd;
428
429 }
430
431 uint32_t drv_bo_get_plane_offset(struct bo *bo, size_t plane)
432 {
433         assert(plane < bo->num_planes);
434         return bo->offsets[plane];
435 }
436
437 uint32_t drv_bo_get_plane_size(struct bo *bo, size_t plane)
438 {
439         assert(plane < bo->num_planes);
440         return bo->sizes[plane];
441 }
442
443 uint32_t drv_bo_get_plane_stride(struct bo *bo, size_t plane)
444 {
445         assert(plane < bo->num_planes);
446         return bo->strides[plane];
447 }
448
449 uint64_t drv_bo_get_plane_format_modifier(struct bo *bo, size_t plane)
450 {
451         assert(plane < bo->num_planes);
452         return bo->format_modifiers[plane];
453 }
454
455 uint32_t drv_bo_get_format(struct bo *bo)
456 {
457         return bo->format;
458 }
459
460 uint32_t drv_resolve_format(struct driver *drv, uint32_t format)
461 {
462         if (drv->backend->resolve_format)
463                 return drv->backend->resolve_format(format);
464
465         return format;
466 }
467
468 /*
469  * This function returns the stride for a given format, width and plane.
470  */
471 int drv_stride_from_format(uint32_t format, uint32_t width, size_t plane)
472 {
473         int stride = width * DIV_ROUND_UP(drv_bpp_from_format(format, plane),
474                                           8);
475
476         /*
477          * Only downsample for certain multiplanar formats which have horizontal
478          * subsampling for chroma planes.  Only formats supported by our drivers
479          * are listed here -- add more as needed.
480          */
481         if (plane != 0) {
482                 switch (format) {
483                 case DRM_FORMAT_NV12:
484                 case DRM_FORMAT_YVU420:
485                         stride = stride / 2;
486                         break;
487                 }
488         }
489
490         return stride;
491 }
492
493 size_t drv_num_planes_from_format(uint32_t format)
494 {
495         switch (format) {
496         case DRM_FORMAT_ABGR1555:
497         case DRM_FORMAT_ABGR2101010:
498         case DRM_FORMAT_ABGR4444:
499         case DRM_FORMAT_ABGR8888:
500         case DRM_FORMAT_ARGB1555:
501         case DRM_FORMAT_ARGB2101010:
502         case DRM_FORMAT_ARGB4444:
503         case DRM_FORMAT_ARGB8888:
504         case DRM_FORMAT_AYUV:
505         case DRM_FORMAT_BGR233:
506         case DRM_FORMAT_BGR565:
507         case DRM_FORMAT_BGR888:
508         case DRM_FORMAT_BGRA1010102:
509         case DRM_FORMAT_BGRA4444:
510         case DRM_FORMAT_BGRA5551:
511         case DRM_FORMAT_BGRA8888:
512         case DRM_FORMAT_BGRX1010102:
513         case DRM_FORMAT_BGRX4444:
514         case DRM_FORMAT_BGRX5551:
515         case DRM_FORMAT_BGRX8888:
516         case DRM_FORMAT_C8:
517         case DRM_FORMAT_GR88:
518         case DRM_FORMAT_R8:
519         case DRM_FORMAT_RG88:
520         case DRM_FORMAT_RGB332:
521         case DRM_FORMAT_RGB565:
522         case DRM_FORMAT_RGB888:
523         case DRM_FORMAT_RGBA1010102:
524         case DRM_FORMAT_RGBA4444:
525         case DRM_FORMAT_RGBA5551:
526         case DRM_FORMAT_RGBA8888:
527         case DRM_FORMAT_RGBX1010102:
528         case DRM_FORMAT_RGBX4444:
529         case DRM_FORMAT_RGBX5551:
530         case DRM_FORMAT_RGBX8888:
531         case DRM_FORMAT_UYVY:
532         case DRM_FORMAT_VYUY:
533         case DRM_FORMAT_XBGR1555:
534         case DRM_FORMAT_XBGR2101010:
535         case DRM_FORMAT_XBGR4444:
536         case DRM_FORMAT_XBGR8888:
537         case DRM_FORMAT_XRGB1555:
538         case DRM_FORMAT_XRGB2101010:
539         case DRM_FORMAT_XRGB4444:
540         case DRM_FORMAT_XRGB8888:
541         case DRM_FORMAT_YUYV:
542         case DRM_FORMAT_YVYU:
543                 return 1;
544         case DRM_FORMAT_NV12:
545                 return 2;
546         case DRM_FORMAT_YVU420:
547                 return 3;
548         }
549
550         fprintf(stderr, "drv: UNKNOWN FORMAT %d\n", format);
551         return 0;
552 }
553
554 uint32_t drv_size_from_format(uint32_t format, uint32_t stride,
555                               uint32_t height, size_t plane)
556 {
557         assert(plane < drv_num_planes_from_format(format));
558         uint32_t vertical_subsampling;
559
560         switch (format) {
561         case DRM_FORMAT_NV12:
562         case DRM_FORMAT_YVU420:
563                 vertical_subsampling = (plane == 0) ? 1 : 2;
564                 break;
565         default:
566                 vertical_subsampling = 1;
567         }
568
569         return stride * DIV_ROUND_UP(height, vertical_subsampling);
570 }
571
572 uint32_t drv_num_buffers_per_bo(struct bo *bo)
573 {
574         uint32_t count = 0;
575         size_t plane, p;
576
577         for (plane = 0; plane < bo->num_planes; plane++) {
578                 for (p = 0; p < plane; p++)
579                         if (bo->handles[p].u32 == bo->handles[plane].u32)
580                                 break;
581                 if (p == plane)
582                         count++;
583         }
584
585         return count;
586 }