OSDN Git Service

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