blob: 168c38ae4369874e415725c7efc4007ddb3fbd03 [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;
45extern struct backend backend_virtio_gpu;
46
47static 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[] = {
Akshu Agrawal0337d9b2016-07-28 15:35:45 +053058#ifdef DRV_AMDGPU
59 &backend_amdgpu,
60#endif
Gurchetan Singh46faf6b2016-08-05 14:40:07 -070061 &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
96struct 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
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700109 if (!drv->backend)
110 goto free_driver;
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700111
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700112 if (pthread_mutex_init(&drv->table_lock, NULL))
113 goto free_driver;
Gurchetan Singh1647fbe2016-08-03 17:14:55 -0700114
115 drv->buffer_table = drmHashCreate();
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700116 if (!drv->buffer_table)
117 goto free_lock;
118
119 drv->map_table = drmHashCreate();
120 if (!drv->map_table)
121 goto free_buffer_table;
Gurchetan Singh1647fbe2016-08-03 17:14:55 -0700122
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700123 if (drv->backend->init) {
124 ret = drv->backend->init(drv);
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700125 if (ret)
126 goto free_map_table;
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700127 }
128
129 return drv;
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700130
131free_map_table:
132 drmHashDestroy(drv->map_table);
133free_buffer_table:
134 drmHashDestroy(drv->buffer_table);
135free_lock:
136 pthread_mutex_destroy(&drv->table_lock);
137free_driver:
138 free(drv);
139 return NULL;
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700140}
141
142void drv_destroy(struct driver *drv)
143{
144 if (drv->backend->close)
145 drv->backend->close(drv);
146
Gurchetan Singh1647fbe2016-08-03 17:14:55 -0700147 pthread_mutex_destroy(&drv->table_lock);
148 drmHashDestroy(drv->buffer_table);
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700149 drmHashDestroy(drv->map_table);
Gurchetan Singh1647fbe2016-08-03 17:14:55 -0700150
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700151 free(drv);
152}
153
154int drv_get_fd(struct driver *drv)
155{
156 return drv->fd;
157}
158
159const char *
160drv_get_name(struct driver *drv)
161{
162 return drv->backend->name;
163}
164
165int 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
186struct 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
210struct 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;
Gurchetan Singh1647fbe2016-08-03 17:14:55 -0700214 size_t plane;
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700215 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
Gurchetan Singh1647fbe2016-08-03 17:14:55 -0700229 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
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700236 return bo;
237}
238
239void drv_bo_destroy(struct bo *bo)
240{
Gurchetan Singh1647fbe2016-08-03 17:14:55 -0700241 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
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700258 free(bo);
259}
260
261struct bo *drv_bo_import(struct driver *drv, struct drv_import_fd_data *data)
262{
263 int ret;
Gurchetan Singhb72badb2016-08-19 16:26:46 -0700264 size_t plane;
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700265 struct bo *bo;
266 struct drm_prime_handle prime_handle;
267
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700268 bo = drv_bo_new(drv, data->width, data->height, data->format);
269
Gurchetan Singhb72badb2016-08-19 16:26:46 -0700270 if (!bo)
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700271 return NULL;
Gurchetan Singhb72badb2016-08-19 16:26:46 -0700272
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];
Gurchetan Singh2e786ad2016-08-24 18:31:23 -0700299 bo->total_size += data->sizes[plane];
Gurchetan Singhb72badb2016-08-19 16:26:46 -0700300
301 pthread_mutex_lock(&drv->table_lock);
302 drv_increment_reference_count(drv, bo, plane);
303 pthread_mutex_unlock(&drv->table_lock);
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700304 }
305
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700306 return bo;
307}
308
Gurchetan Singh1a31e602016-10-06 10:58:00 -0700309void *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
345success:
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
356int 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
Gurchetan Singh46faf6b2016-08-05 14:40:07 -0700377uint32_t drv_bo_get_width(struct bo *bo)
378{
379 return bo->width;
380}
381
382uint32_t drv_bo_get_height(struct bo *bo)
383{
384 return bo->height;
385}
386
387uint32_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
392size_t drv_bo_get_num_planes(struct bo *bo)
393{
394 return bo->num_planes;
395}
396
397union 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
406int 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
419uint32_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
425uint32_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
431uint32_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
437uint64_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}
Gurchetan Singhbfba8c22016-08-16 17:57:10 -0700442
Gurchetan Singh2e786ad2016-08-24 18:31:23 -0700443drv_format_t drv_bo_get_format(struct bo *bo)
444{
445 return bo->format;
446}
447
Gurchetan Singhbfba8c22016-08-16 17:57:10 -0700448drv_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}
Gurchetan Singh2e786ad2016-08-24 18:31:23 -0700455
456/*
457 * This function returns the stride for a given format, width and plane.
458 */
459int 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
480uint32_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}