blob: f652bba45717b8729ec85f2dd5cd06058b697379 [file] [log] [blame]
Gurchetan Singh46faf6b2016-08-05 14:40:07 -07001/*
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>
Gurchetan Singh1647fbe2016-08-03 17:14:55 -07008#include <pthread.h>
Gurchetan Singh46faf6b2016-08-05 14:40:07 -07009#include <stdint.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
Gurchetan Singhef920532016-08-12 16:38:25 -070013#include <sys/mman.h>
Gurchetan Singh46faf6b2016-08-05 14:40:07 -070014#include <xf86drm.h>
15
16#include "drv_priv.h"
17#include "helpers.h"
18#include "util.h"
19
Akshu Agrawal0337d9b2016-07-28 15:35:45 +053020#ifdef DRV_AMDGPU
21extern struct backend backend_amdgpu;
22#endif
Gurchetan Singh46faf6b2016-08-05 14:40:07 -070023extern struct backend backend_cirrus;
24extern struct backend backend_evdi;
25#ifdef DRV_EXYNOS
26extern struct backend backend_exynos;
27#endif
28extern struct backend backend_gma500;
29#ifdef DRV_I915
30extern struct backend backend_i915;
31#endif
32#ifdef DRV_MARVELL
33extern struct backend backend_marvell;
34#endif
35#ifdef DRV_MEDIATEK
36extern struct backend backend_mediatek;
37#endif
38#ifdef DRV_ROCKCHIP
39extern struct backend backend_rockchip;
40#endif
41#ifdef DRV_TEGRA
42extern struct backend backend_tegra;
43#endif
44extern struct backend backend_udl;
Gurchetan Singh5521bde2016-09-30 14:53:32 -070045extern struct backend backend_vgem;
Gurchetan Singh46faf6b2016-08-05 14:40:07 -070046extern struct backend backend_virtio_gpu;
47
48static 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[] = {
Akshu Agrawal0337d9b2016-07-28 15:35:45 +053059#ifdef DRV_AMDGPU
60 &backend_amdgpu,
61#endif
Gurchetan Singh46faf6b2016-08-05 14:40:07 -070062 &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,
Gurchetan Singh5521bde2016-09-30 14:53:32 -070084 &backend_vgem,
Gurchetan Singh46faf6b2016-08-05 14:40:07 -070085 &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
98struct 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
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700111 if (!drv->backend)
112 goto free_driver;
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700113
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700114 if (pthread_mutex_init(&drv->table_lock, NULL))
115 goto free_driver;
Gurchetan Singh1647fbe2016-08-03 17:14:55 -0700116
117 drv->buffer_table = drmHashCreate();
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700118 if (!drv->buffer_table)
119 goto free_lock;
120
121 drv->map_table = drmHashCreate();
122 if (!drv->map_table)
123 goto free_buffer_table;
Gurchetan Singh1647fbe2016-08-03 17:14:55 -0700124
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700125 if (drv->backend->init) {
126 ret = drv->backend->init(drv);
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700127 if (ret)
128 goto free_map_table;
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700129 }
130
131 return drv;
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700132
133free_map_table:
134 drmHashDestroy(drv->map_table);
135free_buffer_table:
136 drmHashDestroy(drv->buffer_table);
137free_lock:
138 pthread_mutex_destroy(&drv->table_lock);
139free_driver:
140 free(drv);
141 return NULL;
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700142}
143
144void drv_destroy(struct driver *drv)
145{
146 if (drv->backend->close)
147 drv->backend->close(drv);
148
Gurchetan Singh1647fbe2016-08-03 17:14:55 -0700149 pthread_mutex_destroy(&drv->table_lock);
150 drmHashDestroy(drv->buffer_table);
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700151 drmHashDestroy(drv->map_table);
Gurchetan Singh1647fbe2016-08-03 17:14:55 -0700152
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700153 free(drv);
154}
155
156int drv_get_fd(struct driver *drv)
157{
158 return drv->fd;
159}
160
161const char *
162drv_get_name(struct driver *drv)
163{
164 return drv->backend->name;
165}
166
167int 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
188struct 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
212struct 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;
Gurchetan Singh1647fbe2016-08-03 17:14:55 -0700216 size_t plane;
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700217 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
Gurchetan Singh1647fbe2016-08-03 17:14:55 -0700231 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
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700238 return bo;
239}
240
241void drv_bo_destroy(struct bo *bo)
242{
Gurchetan Singh1647fbe2016-08-03 17:14:55 -0700243 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
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700260 free(bo);
261}
262
263struct bo *drv_bo_import(struct driver *drv, struct drv_import_fd_data *data)
264{
265 int ret;
Gurchetan Singhb72badb2016-08-19 16:26:46 -0700266 size_t plane;
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700267 struct bo *bo;
268 struct drm_prime_handle prime_handle;
269
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700270 bo = drv_bo_new(drv, data->width, data->height, data->format);
271
Gurchetan Singhb72badb2016-08-19 16:26:46 -0700272 if (!bo)
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700273 return NULL;
Gurchetan Singhb72badb2016-08-19 16:26:46 -0700274
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];
Kristian H. Kristensen33459772016-09-16 11:14:16 -0700301 bo->format_modifiers[plane] = data->format_modifiers[plane];
Gurchetan Singh2e786ad2016-08-24 18:31:23 -0700302 bo->total_size += data->sizes[plane];
Gurchetan Singhb72badb2016-08-19 16:26:46 -0700303
304 pthread_mutex_lock(&drv->table_lock);
305 drv_increment_reference_count(drv, bo, plane);
306 pthread_mutex_unlock(&drv->table_lock);
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700307 }
308
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700309 return bo;
310}
311
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700312void *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
348success:
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
359int 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
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700380uint32_t drv_bo_get_width(struct bo *bo)
381{
382 return bo->width;
383}
384
385uint32_t drv_bo_get_height(struct bo *bo)
386{
387 return bo->height;
388}
389
390uint32_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
395size_t drv_bo_get_num_planes(struct bo *bo)
396{
397 return bo->num_planes;
398}
399
400union 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
409int 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
422uint32_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
428uint32_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
434uint32_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
440uint64_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}
Gurchetan Singhbfba8c22016-08-16 17:57:10 -0700445
Gurchetan Singh2e786ad2016-08-24 18:31:23 -0700446drv_format_t drv_bo_get_format(struct bo *bo)
447{
448 return bo->format;
449}
450
Gurchetan Singhbfba8c22016-08-16 17:57:10 -0700451drv_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}
Gurchetan Singh2e786ad2016-08-24 18:31:23 -0700458
459/*
460 * This function returns the stride for a given format, width and plane.
461 */
462int drv_stride_from_format(uint32_t format, uint32_t width, size_t plane)
463{
Gurchetan Singh2a119342016-11-02 10:40:51 -0700464 int stride = width * DIV_ROUND_UP(drv_bpp_from_format(format, plane),
465 8);
Gurchetan Singh2e786ad2016-08-24 18:31:23 -0700466
467 /*
Gurchetan Singh2a119342016-11-02 10:40:51 -0700468 * Only downsample for certain multiplanar formats which have horizontal
469 * subsampling for chroma planes. Only formats supported by our drivers
470 * are listed here -- add more as needed.
Gurchetan Singh2e786ad2016-08-24 18:31:23 -0700471 */
472 if (plane != 0) {
473 switch (format) {
Gurchetan Singh2a119342016-11-02 10:40:51 -0700474 case DRV_FORMAT_NV12:
Gurchetan Singh2e786ad2016-08-24 18:31:23 -0700475 case DRV_FORMAT_YVU420:
476 stride = stride / 2;
477 break;
478 }
479 }
480
481 return stride;
482}
483
Gurchetan Singh2a119342016-11-02 10:40:51 -0700484size_t drv_num_planes_from_format(uint32_t format)
485{
486 switch (format) {
487 case DRV_FORMAT_C8:
488 case DRV_FORMAT_R8:
489 case DRV_FORMAT_RG88:
490 case DRV_FORMAT_GR88:
491 case DRV_FORMAT_RGB332:
492 case DRV_FORMAT_BGR233:
493 case DRV_FORMAT_XRGB4444:
494 case DRV_FORMAT_XBGR4444:
495 case DRV_FORMAT_RGBX4444:
496 case DRV_FORMAT_BGRX4444:
497 case DRV_FORMAT_ARGB4444:
498 case DRV_FORMAT_ABGR4444:
499 case DRV_FORMAT_RGBA4444:
500 case DRV_FORMAT_BGRA4444:
501 case DRV_FORMAT_XRGB1555:
502 case DRV_FORMAT_XBGR1555:
503 case DRV_FORMAT_RGBX5551:
504 case DRV_FORMAT_BGRX5551:
505 case DRV_FORMAT_ARGB1555:
506 case DRV_FORMAT_ABGR1555:
507 case DRV_FORMAT_RGBA5551:
508 case DRV_FORMAT_BGRA5551:
509 case DRV_FORMAT_RGB565:
510 case DRV_FORMAT_BGR565:
511 case DRV_FORMAT_YUYV:
512 case DRV_FORMAT_YVYU:
513 case DRV_FORMAT_UYVY:
514 case DRV_FORMAT_VYUY:
515 case DRV_FORMAT_RGB888:
516 case DRV_FORMAT_BGR888:
517 case DRV_FORMAT_XRGB8888:
518 case DRV_FORMAT_XBGR8888:
519 case DRV_FORMAT_RGBX8888:
520 case DRV_FORMAT_BGRX8888:
521 case DRV_FORMAT_ARGB8888:
522 case DRV_FORMAT_ABGR8888:
523 case DRV_FORMAT_RGBA8888:
524 case DRV_FORMAT_BGRA8888:
525 case DRV_FORMAT_XRGB2101010:
526 case DRV_FORMAT_XBGR2101010:
527 case DRV_FORMAT_RGBX1010102:
528 case DRV_FORMAT_BGRX1010102:
529 case DRV_FORMAT_ARGB2101010:
530 case DRV_FORMAT_ABGR2101010:
531 case DRV_FORMAT_RGBA1010102:
532 case DRV_FORMAT_BGRA1010102:
533 case DRV_FORMAT_AYUV:
534 return 1;
535 case DRV_FORMAT_NV12:
536 return 2;
537 case DRV_FORMAT_YVU420:
538 return 3;
539 }
540
541 fprintf(stderr, "drv: UNKNOWN FORMAT %d\n", format);
542 return 0;
543}
544
545uint32_t drv_size_from_format(drv_format_t format, uint32_t stride,
546 uint32_t height, size_t plane)
547{
548 assert(plane < drv_num_planes_from_format(format));
549 uint32_t vertical_subsampling;
550
551 switch (format) {
552 case DRV_FORMAT_YVU420:
553 case DRV_FORMAT_NV12:
554 vertical_subsampling = (plane == 0) ? 1 : 2;
555 break;
556 default:
557 vertical_subsampling = 1;
558 }
559
560 return stride * DIV_ROUND_UP(height, vertical_subsampling);
561}
562
Gurchetan Singh2e786ad2016-08-24 18:31:23 -0700563uint32_t drv_num_buffers_per_bo(struct bo *bo)
564{
565 uint32_t count = 0;
566 size_t plane, p;
567
568 for (plane = 0; plane < bo->num_planes; plane++) {
569 for (p = 0; p < plane; p++)
570 if (bo->handles[p].u32 == bo->handles[plane].u32)
571 break;
572 if (p == plane)
573 count++;
574 }
575
576 return count;
577}