OSDN Git Service

minigbm: Add AMDGPU minigbm driver
[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                 free(drv);
111                 return NULL;
112         }
113
114         if (pthread_mutex_init(&drv->table_lock, NULL)) {
115                 free(drv);
116                 return NULL;
117         }
118
119         drv->buffer_table = drmHashCreate();
120         if (!drv->buffer_table) {
121                 free(drv);
122                 return NULL;
123         }
124
125         if (drv->backend->init) {
126                 ret = drv->backend->init(drv);
127                 if (ret) {
128                         free(drv);
129                         return NULL;
130                 }
131         }
132
133         return drv;
134 }
135
136 void drv_destroy(struct driver *drv)
137 {
138         if (drv->backend->close)
139                 drv->backend->close(drv);
140
141         pthread_mutex_destroy(&drv->table_lock);
142         drmHashDestroy(drv->buffer_table);
143
144         free(drv);
145 }
146
147 int drv_get_fd(struct driver *drv)
148 {
149         return drv->fd;
150 }
151
152 const char *
153 drv_get_name(struct driver *drv)
154 {
155         return drv->backend->name;
156 }
157
158 int drv_is_format_supported(struct driver *drv, drv_format_t format,
159                             uint64_t usage)
160 {
161         unsigned int i;
162
163         if (format == DRV_FORMAT_NONE || usage == DRV_BO_USE_NONE)
164                 return 0;
165
166         for (i = 0 ; i < ARRAY_SIZE(drv->backend->format_list); i++)
167         {
168                 if (!drv->backend->format_list[i].format)
169                         break;
170
171                 if (drv->backend->format_list[i].format == format &&
172                       (drv->backend->format_list[i].usage & usage) == usage)
173                         return 1;
174         }
175
176         return 0;
177 }
178
179 struct bo *drv_bo_new(struct driver *drv, uint32_t width, uint32_t height,
180                       drv_format_t format)
181 {
182
183         struct bo *bo;
184         bo = (struct bo *) calloc(1, sizeof(*bo));
185
186         if (!bo)
187                 return NULL;
188
189         bo->drv = drv;
190         bo->width = width;
191         bo->height = height;
192         bo->format = format;
193         bo->num_planes = drv_num_planes_from_format(format);
194
195         if (!bo->num_planes) {
196                 free(bo);
197                 return NULL;
198         }
199
200         return bo;
201 }
202
203 struct bo *drv_bo_create(struct driver *drv, uint32_t width, uint32_t height,
204                          drv_format_t format, uint64_t flags)
205 {
206         int ret;
207         size_t plane;
208         struct bo *bo;
209
210         bo = drv_bo_new(drv, width, height, format);
211
212         if (!bo)
213                 return NULL;
214
215         ret = drv->backend->bo_create(bo, width, height, format, flags);
216
217         if (ret) {
218                 free(bo);
219                 return NULL;
220         }
221
222         pthread_mutex_lock(&drv->table_lock);
223
224         for (plane = 0; plane < bo->num_planes; plane++)
225                 drv_increment_reference_count(drv, bo, plane);
226
227         pthread_mutex_unlock(&drv->table_lock);
228
229         return bo;
230 }
231
232 void drv_bo_destroy(struct bo *bo)
233 {
234         size_t plane;
235         uintptr_t total = 0;
236         struct driver *drv = bo->drv;
237
238         pthread_mutex_lock(&drv->table_lock);
239
240         for (plane = 0; plane < bo->num_planes; plane++)
241                 drv_decrement_reference_count(drv, bo, plane);
242
243         for (plane = 0; plane < bo->num_planes; plane++)
244                 total += drv_get_reference_count(drv, bo, plane);
245
246         pthread_mutex_unlock(&drv->table_lock);
247
248         if (total == 0)
249                 bo->drv->backend->bo_destroy(bo);
250
251         free(bo);
252 }
253
254 void *
255 drv_bo_map(struct bo *bo)
256 {
257         assert(drv_num_buffers_per_bo(bo) == 1);
258
259         if (!bo->map_data || bo->map_data == MAP_FAILED)
260                 bo->map_data = bo->drv->backend->bo_map(bo);
261
262         return bo->map_data;
263 }
264
265 int
266 drv_bo_unmap(struct bo *bo)
267 {
268         int ret = -1;
269
270         assert(drv_num_buffers_per_bo(bo) == 1);
271
272         if (bo->map_data && bo->map_data != MAP_FAILED)
273                 ret = munmap(bo->map_data, bo->total_size);
274
275         bo->map_data = NULL;
276
277         return ret;
278 }
279
280 struct bo *drv_bo_import(struct driver *drv, struct drv_import_fd_data *data)
281 {
282         int ret;
283         size_t plane;
284         struct bo *bo;
285         struct drm_prime_handle prime_handle;
286
287         bo = drv_bo_new(drv, data->width, data->height, data->format);
288
289         if (!bo)
290                 return NULL;
291
292         for (plane = 0; plane < bo->num_planes; plane++) {
293
294                 memset(&prime_handle, 0, sizeof(prime_handle));
295                 prime_handle.fd = data->fds[plane];
296
297                 ret = drmIoctl(drv->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE,
298                                &prime_handle);
299
300                 if (ret) {
301                         fprintf(stderr, "drv: DRM_IOCTL_PRIME_FD_TO_HANDLE failed "
302                                 "(fd=%u)\n", prime_handle.fd);
303
304                         if (plane > 0) {
305                                 bo->num_planes = plane;
306                                 drv_bo_destroy(bo);
307                         } else {
308                                 free(bo);
309                         }
310
311                         return NULL;
312                 }
313
314                 bo->handles[plane].u32 = prime_handle.handle;
315                 bo->strides[plane] = data->strides[plane];
316                 bo->offsets[plane] = data->offsets[plane];
317                 bo->sizes[plane] = data->sizes[plane];
318
319                 pthread_mutex_lock(&drv->table_lock);
320                 drv_increment_reference_count(drv, bo, plane);
321                 pthread_mutex_unlock(&drv->table_lock);
322         }
323
324         return bo;
325 }
326
327 uint32_t drv_bo_get_width(struct bo *bo)
328 {
329         return bo->width;
330 }
331
332 uint32_t drv_bo_get_height(struct bo *bo)
333 {
334         return bo->height;
335 }
336
337 uint32_t drv_bo_get_stride_or_tiling(struct bo *bo)
338 {
339         return bo->tiling ? bo->tiling : drv_bo_get_plane_stride(bo, 0);
340 }
341
342 size_t drv_bo_get_num_planes(struct bo *bo)
343 {
344         return bo->num_planes;
345 }
346
347 union bo_handle drv_bo_get_plane_handle(struct bo *bo, size_t plane)
348 {
349         return bo->handles[plane];
350 }
351
352 #ifndef DRM_RDWR
353 #define DRM_RDWR O_RDWR
354 #endif
355
356 int drv_bo_get_plane_fd(struct bo *bo, size_t plane)
357 {
358
359         int ret, fd;
360         assert(plane < bo->num_planes);
361
362         ret = drmPrimeHandleToFD(bo->drv->fd, bo->handles[plane].u32,
363                                  DRM_CLOEXEC | DRM_RDWR, &fd);
364
365         return (ret) ? ret : fd;
366
367 }
368
369 uint32_t drv_bo_get_plane_offset(struct bo *bo, size_t plane)
370 {
371         assert(plane < bo->num_planes);
372         return bo->offsets[plane];
373 }
374
375 uint32_t drv_bo_get_plane_size(struct bo *bo, size_t plane)
376 {
377         assert(plane < bo->num_planes);
378         return bo->sizes[plane];
379 }
380
381 uint32_t drv_bo_get_plane_stride(struct bo *bo, size_t plane)
382 {
383         assert(plane < bo->num_planes);
384         return bo->strides[plane];
385 }
386
387 uint64_t drv_bo_get_plane_format_modifier(struct bo *bo, size_t plane)
388 {
389         assert(plane < bo->num_planes);
390         return bo->format_modifiers[plane];
391 }
392
393 drv_format_t drv_resolve_format(struct driver *drv, drv_format_t format)
394 {
395         if (drv->backend->resolve_format)
396                 return drv->backend->resolve_format(format);
397
398         return format;
399 }