OSDN Git Service

minigbm: add new GBM_BO_IMPORT_FD_PLANAR
[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->table_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         if (drv->backend->init) {
126                 ret = drv->backend->init(drv);
127                 if (ret)
128                         goto free_map_table;
129         }
130
131         return drv;
132
133 free_map_table:
134         drmHashDestroy(drv->map_table);
135 free_buffer_table:
136         drmHashDestroy(drv->buffer_table);
137 free_lock:
138         pthread_mutex_destroy(&drv->table_lock);
139 free_driver:
140         free(drv);
141         return NULL;
142 }
143
144 void drv_destroy(struct driver *drv)
145 {
146         if (drv->backend->close)
147                 drv->backend->close(drv);
148
149         pthread_mutex_destroy(&drv->table_lock);
150         drmHashDestroy(drv->buffer_table);
151         drmHashDestroy(drv->map_table);
152
153         free(drv);
154 }
155
156 int drv_get_fd(struct driver *drv)
157 {
158         return drv->fd;
159 }
160
161 const char *
162 drv_get_name(struct driver *drv)
163 {
164         return drv->backend->name;
165 }
166
167 int drv_is_format_supported(struct driver *drv, drv_format_t format,
168                             uint64_t usage)
169 {
170         unsigned int i;
171
172         if (format == DRV_FORMAT_NONE || usage == DRV_BO_USE_NONE)
173                 return 0;
174
175         for (i = 0 ; i < ARRAY_SIZE(drv->backend->format_list); i++)
176         {
177                 if (!drv->backend->format_list[i].format)
178                         break;
179
180                 if (drv->backend->format_list[i].format == format &&
181                       (drv->backend->format_list[i].usage & usage) == usage)
182                         return 1;
183         }
184
185         return 0;
186 }
187
188 struct bo *drv_bo_new(struct driver *drv, uint32_t width, uint32_t height,
189                       drv_format_t format)
190 {
191
192         struct bo *bo;
193         bo = (struct bo *) calloc(1, sizeof(*bo));
194
195         if (!bo)
196                 return NULL;
197
198         bo->drv = drv;
199         bo->width = width;
200         bo->height = height;
201         bo->format = format;
202         bo->num_planes = drv_num_planes_from_format(format);
203
204         if (!bo->num_planes) {
205                 free(bo);
206                 return NULL;
207         }
208
209         return bo;
210 }
211
212 struct bo *drv_bo_create(struct driver *drv, uint32_t width, uint32_t height,
213                          drv_format_t format, uint64_t flags)
214 {
215         int ret;
216         size_t plane;
217         struct bo *bo;
218
219         bo = drv_bo_new(drv, width, height, format);
220
221         if (!bo)
222                 return NULL;
223
224         ret = drv->backend->bo_create(bo, width, height, format, flags);
225
226         if (ret) {
227                 free(bo);
228                 return NULL;
229         }
230
231         pthread_mutex_lock(&drv->table_lock);
232
233         for (plane = 0; plane < bo->num_planes; plane++)
234                 drv_increment_reference_count(drv, bo, plane);
235
236         pthread_mutex_unlock(&drv->table_lock);
237
238         return bo;
239 }
240
241 void drv_bo_destroy(struct bo *bo)
242 {
243         size_t plane;
244         uintptr_t total = 0;
245         struct driver *drv = bo->drv;
246
247         pthread_mutex_lock(&drv->table_lock);
248
249         for (plane = 0; plane < bo->num_planes; plane++)
250                 drv_decrement_reference_count(drv, bo, plane);
251
252         for (plane = 0; plane < bo->num_planes; plane++)
253                 total += drv_get_reference_count(drv, bo, plane);
254
255         pthread_mutex_unlock(&drv->table_lock);
256
257         if (total == 0)
258                 bo->drv->backend->bo_destroy(bo);
259
260         free(bo);
261 }
262
263 struct bo *drv_bo_import(struct driver *drv, struct drv_import_fd_data *data)
264 {
265         int ret;
266         size_t plane;
267         struct bo *bo;
268         struct drm_prime_handle prime_handle;
269
270         bo = drv_bo_new(drv, data->width, data->height, data->format);
271
272         if (!bo)
273                 return NULL;
274
275         for (plane = 0; plane < bo->num_planes; plane++) {
276
277                 memset(&prime_handle, 0, sizeof(prime_handle));
278                 prime_handle.fd = data->fds[plane];
279
280                 ret = drmIoctl(drv->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE,
281                                &prime_handle);
282
283                 if (ret) {
284                         fprintf(stderr, "drv: DRM_IOCTL_PRIME_FD_TO_HANDLE failed "
285                                 "(fd=%u)\n", prime_handle.fd);
286
287                         if (plane > 0) {
288                                 bo->num_planes = plane;
289                                 drv_bo_destroy(bo);
290                         } else {
291                                 free(bo);
292                         }
293
294                         return NULL;
295                 }
296
297                 bo->handles[plane].u32 = prime_handle.handle;
298                 bo->strides[plane] = data->strides[plane];
299                 bo->offsets[plane] = data->offsets[plane];
300                 bo->sizes[plane] = data->sizes[plane];
301                 bo->format_modifiers[plane] = data->format_modifiers[plane];
302                 bo->total_size += data->sizes[plane];
303
304                 pthread_mutex_lock(&drv->table_lock);
305                 drv_increment_reference_count(drv, bo, plane);
306                 pthread_mutex_unlock(&drv->table_lock);
307         }
308
309         return bo;
310 }
311
312 void *drv_bo_map(struct bo *bo, uint32_t x, uint32_t y, uint32_t width,
313                  uint32_t height, uint32_t flags, void **map_data, size_t plane)
314 {
315         void *ptr;
316         uint8_t *addr;
317         size_t offset;
318         struct map_info *data;
319
320         assert(width > 0);
321         assert(height > 0);
322         assert(x + width <= drv_bo_get_width(bo));
323         assert(y + height <= drv_bo_get_height(bo));
324
325         pthread_mutex_lock(&bo->drv->table_lock);
326
327         if (!drmHashLookup(bo->drv->map_table, bo->handles[plane].u32, &ptr)) {
328                 data = (struct map_info *) ptr;
329                 data->refcount++;
330                 goto success;
331         }
332
333         data = calloc(1, sizeof(*data));
334         addr = bo->drv->backend->bo_map(bo, data, plane);
335         if (addr == MAP_FAILED) {
336                 *map_data = NULL;
337                 free(data);
338                 pthread_mutex_unlock(&bo->drv->table_lock);
339                 return MAP_FAILED;
340         }
341
342         data->refcount = 1;
343         data->addr = addr;
344         data->handle = bo->handles[plane].u32;
345         drmHashInsert(bo->drv->buffer_table, bo->handles[plane].u32,
346                       (void *) data);
347
348 success:
349         *map_data = (void *) data;
350         offset = drv_bo_get_plane_stride(bo, plane) * y;
351         offset += drv_stride_from_format(bo->format, x, plane);
352         addr = (uint8_t *) data->addr;
353         addr += drv_bo_get_plane_offset(bo, plane) + offset;
354         pthread_mutex_unlock(&bo->drv->table_lock);
355
356         return (void *) addr;
357 }
358
359 int drv_bo_unmap(struct bo *bo, void *map_data)
360 {
361         struct map_info *data = map_data;
362         int ret = 0;
363
364         assert(data);
365         assert(data->refcount >= 0);
366
367         pthread_mutex_lock(&bo->drv->table_lock);
368
369         if (!--data->refcount) {
370                 ret = munmap(data->addr, data->length);
371                 drmHashDelete(bo->drv->map_table, data->handle);
372                 free(data);
373         }
374
375         pthread_mutex_unlock(&bo->drv->table_lock);
376
377         return ret;
378 }
379
380 uint32_t drv_bo_get_width(struct bo *bo)
381 {
382         return bo->width;
383 }
384
385 uint32_t drv_bo_get_height(struct bo *bo)
386 {
387         return bo->height;
388 }
389
390 uint32_t drv_bo_get_stride_or_tiling(struct bo *bo)
391 {
392         return bo->tiling ? bo->tiling : drv_bo_get_plane_stride(bo, 0);
393 }
394
395 size_t drv_bo_get_num_planes(struct bo *bo)
396 {
397         return bo->num_planes;
398 }
399
400 union bo_handle drv_bo_get_plane_handle(struct bo *bo, size_t plane)
401 {
402         return bo->handles[plane];
403 }
404
405 #ifndef DRM_RDWR
406 #define DRM_RDWR O_RDWR
407 #endif
408
409 int drv_bo_get_plane_fd(struct bo *bo, size_t plane)
410 {
411
412         int ret, fd;
413         assert(plane < bo->num_planes);
414
415         ret = drmPrimeHandleToFD(bo->drv->fd, bo->handles[plane].u32,
416                                  DRM_CLOEXEC | DRM_RDWR, &fd);
417
418         return (ret) ? ret : fd;
419
420 }
421
422 uint32_t drv_bo_get_plane_offset(struct bo *bo, size_t plane)
423 {
424         assert(plane < bo->num_planes);
425         return bo->offsets[plane];
426 }
427
428 uint32_t drv_bo_get_plane_size(struct bo *bo, size_t plane)
429 {
430         assert(plane < bo->num_planes);
431         return bo->sizes[plane];
432 }
433
434 uint32_t drv_bo_get_plane_stride(struct bo *bo, size_t plane)
435 {
436         assert(plane < bo->num_planes);
437         return bo->strides[plane];
438 }
439
440 uint64_t drv_bo_get_plane_format_modifier(struct bo *bo, size_t plane)
441 {
442         assert(plane < bo->num_planes);
443         return bo->format_modifiers[plane];
444 }
445
446 drv_format_t drv_bo_get_format(struct bo *bo)
447 {
448         return bo->format;
449 }
450
451 drv_format_t drv_resolve_format(struct driver *drv, drv_format_t format)
452 {
453         if (drv->backend->resolve_format)
454                 return drv->backend->resolve_format(format);
455
456         return format;
457 }
458
459 /*
460  * This function returns the stride for a given format, width and plane.
461  */
462 int drv_stride_from_format(uint32_t format, uint32_t width, size_t plane)
463 {
464         /* Get stride of the first plane */
465         int stride = width * DIV_ROUND_UP(drv_bpp_from_format(format, 0), 8);
466
467         /*
468          * Only downsample for certain multiplanar formats which are not
469          * interleaved and have horizontal subsampling.  Only formats supported
470          * by our drivers are listed here -- add more as needed.
471          */
472         if (plane != 0) {
473                 switch (format) {
474                 case DRV_FORMAT_YVU420:
475                         stride = stride / 2;
476                         break;
477                 }
478         }
479
480         return stride;
481 }
482
483 uint32_t drv_num_buffers_per_bo(struct bo *bo)
484 {
485         uint32_t count = 0;
486         size_t plane, p;
487
488         for (plane = 0; plane < bo->num_planes; plane++) {
489                 for (p = 0; p < plane; p++)
490                         if (bo->handles[p].u32 == bo->handles[plane].u32)
491                                 break;
492                 if (p == plane)
493                         count++;
494         }
495
496         return count;
497 }