OSDN Git Service

minigbm/msm: Disable UBWC for video gtest
[android-x86/external-minigbm.git] / drv.c
1 /*
2  * Copyright 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 <errno.h>
8 #include <fcntl.h>
9 #include <pthread.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/mman.h>
15 #include <sys/types.h>
16 #include <unistd.h>
17 #include <xf86drm.h>
18
19 #ifdef __ANDROID__
20 #include <cutils/log.h>
21 #include <libgen.h>
22 #endif
23
24 #include "drv_priv.h"
25 #include "helpers.h"
26 #include "util.h"
27
28 #ifdef DRV_AMDGPU
29 extern const struct backend backend_amdgpu;
30 #endif
31 #ifdef DRV_EXYNOS
32 extern const struct backend backend_exynos;
33 #endif
34 #ifdef DRV_I915
35 extern const struct backend backend_i915;
36 #endif
37 #ifdef DRV_MEDIATEK
38 extern const struct backend backend_mediatek;
39 #endif
40 #ifdef DRV_MSM
41 extern const struct backend backend_msm;
42 #endif
43 #ifdef DRV_ROCKCHIP
44 extern const struct backend backend_rockchip;
45 #endif
46 #ifdef DRV_TEGRA
47 extern const struct backend backend_tegra;
48 #endif
49 #ifdef DRV_VC4
50 extern const struct backend backend_vc4;
51 #endif
52
53 // Dumb / generic drivers
54 extern const struct backend backend_evdi;
55 extern const struct backend backend_marvell;
56 extern const struct backend backend_meson;
57 extern const struct backend backend_nouveau;
58 extern const struct backend backend_komeda;
59 extern const struct backend backend_radeon;
60 extern const struct backend backend_synaptics;
61 extern const struct backend backend_virtio_gpu;
62 extern const struct backend backend_udl;
63
64 static const struct backend *drv_get_backend(int fd)
65 {
66         drmVersionPtr drm_version;
67         unsigned int i;
68
69         drm_version = drmGetVersion(fd);
70
71         if (!drm_version)
72                 return NULL;
73
74         const struct backend *backend_list[] = {
75 #ifdef DRV_AMDGPU
76                 &backend_amdgpu,
77 #endif
78 #ifdef DRV_EXYNOS
79                 &backend_exynos,
80 #endif
81 #ifdef DRV_I915
82                 &backend_i915,
83 #endif
84 #ifdef DRV_MEDIATEK
85                 &backend_mediatek,
86 #endif
87 #ifdef DRV_MSM
88                 &backend_msm,
89 #endif
90 #ifdef DRV_ROCKCHIP
91                 &backend_rockchip,
92 #endif
93 #ifdef DRV_VC4
94                 &backend_vc4,
95 #endif
96                 &backend_evdi,      &backend_marvell,    &backend_meson,
97                 &backend_nouveau,   &backend_komeda,     &backend_radeon,
98                 &backend_synaptics, &backend_virtio_gpu, &backend_udl,
99         };
100
101         for (i = 0; i < ARRAY_SIZE(backend_list); i++) {
102                 const struct backend *b = backend_list[i];
103                 // Exactly one of the main create functions must be defined.
104                 assert((b->bo_create != NULL) ^ (b->bo_create_from_metadata != NULL));
105                 // Either both or neither must be implemented.
106                 assert((b->bo_compute_metadata != NULL) == (b->bo_create_from_metadata != NULL));
107                 // Both can't be defined, but it's okay for neither to be (i.e. only bo_create).
108                 assert((b->bo_create_with_modifiers == NULL) ||
109                        (b->bo_create_from_metadata == NULL));
110
111                 if (!strcmp(drm_version->name, b->name)) {
112                         drmFreeVersion(drm_version);
113                         return b;
114                 }
115         }
116
117         drmFreeVersion(drm_version);
118         return NULL;
119 }
120
121 struct driver *drv_create(int fd)
122 {
123         struct driver *drv;
124         int ret;
125
126         drv = (struct driver *)calloc(1, sizeof(*drv));
127
128         if (!drv)
129                 return NULL;
130
131         drv->fd = fd;
132         drv->backend = drv_get_backend(fd);
133
134         if (!drv->backend)
135                 goto free_driver;
136
137         if (pthread_mutex_init(&drv->driver_lock, NULL))
138                 goto free_driver;
139
140         drv->buffer_table = drmHashCreate();
141         if (!drv->buffer_table)
142                 goto free_lock;
143
144         drv->mappings = drv_array_init(sizeof(struct mapping));
145         if (!drv->mappings)
146                 goto free_buffer_table;
147
148         drv->combos = drv_array_init(sizeof(struct combination));
149         if (!drv->combos)
150                 goto free_mappings;
151
152         if (drv->backend->init) {
153                 ret = drv->backend->init(drv);
154                 if (ret) {
155                         drv_array_destroy(drv->combos);
156                         goto free_mappings;
157                 }
158         }
159
160         return drv;
161
162 free_mappings:
163         drv_array_destroy(drv->mappings);
164 free_buffer_table:
165         drmHashDestroy(drv->buffer_table);
166 free_lock:
167         pthread_mutex_destroy(&drv->driver_lock);
168 free_driver:
169         free(drv);
170         return NULL;
171 }
172
173 void drv_destroy(struct driver *drv)
174 {
175         pthread_mutex_lock(&drv->driver_lock);
176
177         if (drv->backend->close)
178                 drv->backend->close(drv);
179
180         drmHashDestroy(drv->buffer_table);
181         drv_array_destroy(drv->mappings);
182         drv_array_destroy(drv->combos);
183
184         pthread_mutex_unlock(&drv->driver_lock);
185         pthread_mutex_destroy(&drv->driver_lock);
186
187         free(drv);
188 }
189
190 int drv_get_fd(struct driver *drv)
191 {
192         return drv->fd;
193 }
194
195 const char *drv_get_name(struct driver *drv)
196 {
197         return drv->backend->name;
198 }
199
200 struct combination *drv_get_combination(struct driver *drv, uint32_t format, uint64_t use_flags)
201 {
202         struct combination *curr, *best;
203
204         if (format == DRM_FORMAT_NONE || use_flags == BO_USE_NONE)
205                 return 0;
206
207         best = NULL;
208         uint32_t i;
209         for (i = 0; i < drv_array_size(drv->combos); i++) {
210                 curr = drv_array_at_idx(drv->combos, i);
211                 if ((format == curr->format) && use_flags == (curr->use_flags & use_flags))
212                         if (!best || best->metadata.priority < curr->metadata.priority)
213                                 best = curr;
214         }
215
216         return best;
217 }
218
219 struct bo *drv_bo_new(struct driver *drv, uint32_t width, uint32_t height, uint32_t format,
220                       uint64_t use_flags, bool is_test_buffer)
221 {
222
223         struct bo *bo;
224         bo = (struct bo *)calloc(1, sizeof(*bo));
225
226         if (!bo)
227                 return NULL;
228
229         bo->drv = drv;
230         bo->meta.width = width;
231         bo->meta.height = height;
232         bo->meta.format = format;
233         bo->meta.use_flags = use_flags;
234         bo->meta.num_planes = drv_num_planes_from_format(format);
235         bo->is_test_buffer = is_test_buffer;
236
237         if (!bo->meta.num_planes) {
238                 free(bo);
239                 return NULL;
240         }
241
242         return bo;
243 }
244
245 struct bo *drv_bo_create(struct driver *drv, uint32_t width, uint32_t height, uint32_t format,
246                          uint64_t use_flags)
247 {
248         int ret;
249         size_t plane;
250         struct bo *bo;
251         bool is_test_alloc;
252
253         is_test_alloc = use_flags & BO_USE_TEST_ALLOC;
254         use_flags &= ~BO_USE_TEST_ALLOC;
255
256         bo = drv_bo_new(drv, width, height, format, use_flags, is_test_alloc);
257
258         if (!bo)
259                 return NULL;
260
261         ret = -EINVAL;
262         if (drv->backend->bo_compute_metadata) {
263                 ret = drv->backend->bo_compute_metadata(bo, width, height, format, use_flags, NULL,
264                                                         0);
265                 if (!is_test_alloc && ret == 0)
266                         ret = drv->backend->bo_create_from_metadata(bo);
267         } else if (!is_test_alloc) {
268                 ret = drv->backend->bo_create(bo, width, height, format, use_flags);
269         }
270
271         if (ret) {
272                 free(bo);
273                 return NULL;
274         }
275
276         pthread_mutex_lock(&drv->driver_lock);
277
278         for (plane = 0; plane < bo->meta.num_planes; plane++) {
279                 if (plane > 0)
280                         assert(bo->meta.offsets[plane] >= bo->meta.offsets[plane - 1]);
281
282                 drv_increment_reference_count(drv, bo, plane);
283         }
284
285         pthread_mutex_unlock(&drv->driver_lock);
286
287         return bo;
288 }
289
290 struct bo *drv_bo_create_with_modifiers(struct driver *drv, uint32_t width, uint32_t height,
291                                         uint32_t format, const uint64_t *modifiers, uint32_t count)
292 {
293         int ret;
294         size_t plane;
295         struct bo *bo;
296
297         if (!drv->backend->bo_create_with_modifiers && !drv->backend->bo_compute_metadata) {
298                 errno = ENOENT;
299                 return NULL;
300         }
301
302         bo = drv_bo_new(drv, width, height, format, BO_USE_NONE, false);
303
304         if (!bo)
305                 return NULL;
306
307         ret = -EINVAL;
308         if (drv->backend->bo_compute_metadata) {
309                 ret = drv->backend->bo_compute_metadata(bo, width, height, format, BO_USE_NONE,
310                                                         modifiers, count);
311                 if (ret == 0)
312                         ret = drv->backend->bo_create_from_metadata(bo);
313         } else {
314                 ret = drv->backend->bo_create_with_modifiers(bo, width, height, format, modifiers,
315                                                              count);
316         }
317
318         if (ret) {
319                 free(bo);
320                 return NULL;
321         }
322
323         pthread_mutex_lock(&drv->driver_lock);
324
325         for (plane = 0; plane < bo->meta.num_planes; plane++) {
326                 if (plane > 0)
327                         assert(bo->meta.offsets[plane] >= bo->meta.offsets[plane - 1]);
328
329                 drv_increment_reference_count(drv, bo, plane);
330         }
331
332         pthread_mutex_unlock(&drv->driver_lock);
333
334         return bo;
335 }
336
337 void drv_bo_destroy(struct bo *bo)
338 {
339         int ret;
340         size_t plane;
341         uintptr_t total = 0;
342         struct driver *drv = bo->drv;
343
344         if (!bo->is_test_buffer) {
345                 pthread_mutex_lock(&drv->driver_lock);
346
347                 for (plane = 0; plane < bo->meta.num_planes; plane++)
348                         drv_decrement_reference_count(drv, bo, plane);
349
350                 for (plane = 0; plane < bo->meta.num_planes; plane++)
351                         total += drv_get_reference_count(drv, bo, plane);
352
353                 pthread_mutex_unlock(&drv->driver_lock);
354
355                 if (total == 0) {
356                         ret = drv_mapping_destroy(bo);
357                         assert(ret == 0);
358                         bo->drv->backend->bo_destroy(bo);
359                 }
360         }
361
362         free(bo);
363 }
364
365 struct bo *drv_bo_import(struct driver *drv, struct drv_import_fd_data *data)
366 {
367         int ret;
368         size_t plane;
369         struct bo *bo;
370         off_t seek_end;
371
372         bo = drv_bo_new(drv, data->width, data->height, data->format, data->use_flags, false);
373
374         if (!bo)
375                 return NULL;
376
377         ret = drv->backend->bo_import(bo, data);
378         if (ret) {
379                 free(bo);
380                 return NULL;
381         }
382
383         for (plane = 0; plane < bo->meta.num_planes; plane++) {
384                 pthread_mutex_lock(&bo->drv->driver_lock);
385                 drv_increment_reference_count(bo->drv, bo, plane);
386                 pthread_mutex_unlock(&bo->drv->driver_lock);
387         }
388
389         for (plane = 0; plane < bo->meta.num_planes; plane++) {
390                 bo->meta.strides[plane] = data->strides[plane];
391                 bo->meta.offsets[plane] = data->offsets[plane];
392                 bo->meta.format_modifiers[plane] = data->format_modifiers[plane];
393
394                 seek_end = lseek(data->fds[plane], 0, SEEK_END);
395                 if (seek_end == (off_t)(-1)) {
396                         drv_log("lseek() failed with %s\n", strerror(errno));
397                         goto destroy_bo;
398                 }
399
400                 lseek(data->fds[plane], 0, SEEK_SET);
401                 if (plane == bo->meta.num_planes - 1 || data->offsets[plane + 1] == 0)
402                         bo->meta.sizes[plane] = seek_end - data->offsets[plane];
403                 else
404                         bo->meta.sizes[plane] = data->offsets[plane + 1] - data->offsets[plane];
405
406                 if ((int64_t)bo->meta.offsets[plane] + bo->meta.sizes[plane] > seek_end) {
407                         drv_log("buffer size is too large.\n");
408                         goto destroy_bo;
409                 }
410
411                 bo->meta.total_size += bo->meta.sizes[plane];
412         }
413
414         return bo;
415
416 destroy_bo:
417         drv_bo_destroy(bo);
418         return NULL;
419 }
420
421 void *drv_bo_map(struct bo *bo, const struct rectangle *rect, uint32_t map_flags,
422                  struct mapping **map_data, size_t plane)
423 {
424         uint32_t i;
425         uint8_t *addr;
426         struct mapping mapping = { 0 };
427
428         assert(rect->width >= 0);
429         assert(rect->height >= 0);
430         assert(rect->x + rect->width <= drv_bo_get_width(bo));
431         assert(rect->y + rect->height <= drv_bo_get_height(bo));
432         assert(BO_MAP_READ_WRITE & map_flags);
433         /* No CPU access for protected buffers. */
434         assert(!(bo->meta.use_flags & BO_USE_PROTECTED));
435
436         if (bo->is_test_buffer) {
437                 return MAP_FAILED;
438         }
439
440         mapping.rect = *rect;
441         mapping.refcount = 1;
442
443         pthread_mutex_lock(&bo->drv->driver_lock);
444
445         for (i = 0; i < drv_array_size(bo->drv->mappings); i++) {
446                 struct mapping *prior = (struct mapping *)drv_array_at_idx(bo->drv->mappings, i);
447                 if (prior->vma->handle != bo->handles[plane].u32 ||
448                     prior->vma->map_flags != map_flags)
449                         continue;
450
451                 if (rect->x != prior->rect.x || rect->y != prior->rect.y ||
452                     rect->width != prior->rect.width || rect->height != prior->rect.height)
453                         continue;
454
455                 prior->refcount++;
456                 *map_data = prior;
457                 goto exact_match;
458         }
459
460         for (i = 0; i < drv_array_size(bo->drv->mappings); i++) {
461                 struct mapping *prior = (struct mapping *)drv_array_at_idx(bo->drv->mappings, i);
462                 if (prior->vma->handle != bo->handles[plane].u32 ||
463                     prior->vma->map_flags != map_flags)
464                         continue;
465
466                 prior->vma->refcount++;
467                 mapping.vma = prior->vma;
468                 goto success;
469         }
470
471         mapping.vma = calloc(1, sizeof(*mapping.vma));
472         memcpy(mapping.vma->map_strides, bo->meta.strides, sizeof(mapping.vma->map_strides));
473         addr = bo->drv->backend->bo_map(bo, mapping.vma, plane, map_flags);
474         if (addr == MAP_FAILED) {
475                 *map_data = NULL;
476                 free(mapping.vma);
477                 pthread_mutex_unlock(&bo->drv->driver_lock);
478                 return MAP_FAILED;
479         }
480
481         mapping.vma->refcount = 1;
482         mapping.vma->addr = addr;
483         mapping.vma->handle = bo->handles[plane].u32;
484         mapping.vma->map_flags = map_flags;
485
486 success:
487         *map_data = drv_array_append(bo->drv->mappings, &mapping);
488 exact_match:
489         drv_bo_invalidate(bo, *map_data);
490         addr = (uint8_t *)((*map_data)->vma->addr);
491         addr += drv_bo_get_plane_offset(bo, plane);
492         pthread_mutex_unlock(&bo->drv->driver_lock);
493         return (void *)addr;
494 }
495
496 int drv_bo_unmap(struct bo *bo, struct mapping *mapping)
497 {
498         uint32_t i;
499         int ret = 0;
500
501         pthread_mutex_lock(&bo->drv->driver_lock);
502
503         if (--mapping->refcount)
504                 goto out;
505
506         if (!--mapping->vma->refcount) {
507                 ret = bo->drv->backend->bo_unmap(bo, mapping->vma);
508                 free(mapping->vma);
509         }
510
511         for (i = 0; i < drv_array_size(bo->drv->mappings); i++) {
512                 if (mapping == (struct mapping *)drv_array_at_idx(bo->drv->mappings, i)) {
513                         drv_array_remove(bo->drv->mappings, i);
514                         break;
515                 }
516         }
517
518 out:
519         pthread_mutex_unlock(&bo->drv->driver_lock);
520         return ret;
521 }
522
523 int drv_bo_invalidate(struct bo *bo, struct mapping *mapping)
524 {
525         int ret = 0;
526
527         assert(mapping);
528         assert(mapping->vma);
529         assert(mapping->refcount > 0);
530         assert(mapping->vma->refcount > 0);
531
532         if (bo->drv->backend->bo_invalidate)
533                 ret = bo->drv->backend->bo_invalidate(bo, mapping);
534
535         return ret;
536 }
537
538 int drv_bo_flush(struct bo *bo, struct mapping *mapping)
539 {
540         int ret = 0;
541
542         assert(mapping);
543         assert(mapping->vma);
544         assert(mapping->refcount > 0);
545         assert(mapping->vma->refcount > 0);
546
547         if (bo->drv->backend->bo_flush)
548                 ret = bo->drv->backend->bo_flush(bo, mapping);
549
550         return ret;
551 }
552
553 int drv_bo_flush_or_unmap(struct bo *bo, struct mapping *mapping)
554 {
555         int ret = 0;
556
557         assert(mapping);
558         assert(mapping->vma);
559         assert(mapping->refcount > 0);
560         assert(mapping->vma->refcount > 0);
561         assert(!(bo->meta.use_flags & BO_USE_PROTECTED));
562
563         if (bo->drv->backend->bo_flush)
564                 ret = bo->drv->backend->bo_flush(bo, mapping);
565         else
566                 ret = drv_bo_unmap(bo, mapping);
567
568         return ret;
569 }
570
571 uint32_t drv_bo_get_width(struct bo *bo)
572 {
573         return bo->meta.width;
574 }
575
576 uint32_t drv_bo_get_height(struct bo *bo)
577 {
578         return bo->meta.height;
579 }
580
581 size_t drv_bo_get_num_planes(struct bo *bo)
582 {
583         return bo->meta.num_planes;
584 }
585
586 union bo_handle drv_bo_get_plane_handle(struct bo *bo, size_t plane)
587 {
588         return bo->handles[plane];
589 }
590
591 #ifndef DRM_RDWR
592 #define DRM_RDWR O_RDWR
593 #endif
594
595 int drv_bo_get_plane_fd(struct bo *bo, size_t plane)
596 {
597
598         int ret, fd;
599         assert(plane < bo->meta.num_planes);
600
601         if (bo->is_test_buffer) {
602                 return -EINVAL;
603         }
604
605         ret = drmPrimeHandleToFD(bo->drv->fd, bo->handles[plane].u32, DRM_CLOEXEC | DRM_RDWR, &fd);
606
607         // Older DRM implementations blocked DRM_RDWR, but gave a read/write mapping anyways
608         if (ret)
609                 ret = drmPrimeHandleToFD(bo->drv->fd, bo->handles[plane].u32, DRM_CLOEXEC, &fd);
610
611         return (ret) ? ret : fd;
612 }
613
614 uint32_t drv_bo_get_plane_offset(struct bo *bo, size_t plane)
615 {
616         assert(plane < bo->meta.num_planes);
617         return bo->meta.offsets[plane];
618 }
619
620 uint32_t drv_bo_get_plane_size(struct bo *bo, size_t plane)
621 {
622         assert(plane < bo->meta.num_planes);
623         return bo->meta.sizes[plane];
624 }
625
626 uint32_t drv_bo_get_plane_stride(struct bo *bo, size_t plane)
627 {
628         assert(plane < bo->meta.num_planes);
629         return bo->meta.strides[plane];
630 }
631
632 uint64_t drv_bo_get_plane_format_modifier(struct bo *bo, size_t plane)
633 {
634         assert(plane < bo->meta.num_planes);
635         return bo->meta.format_modifiers[plane];
636 }
637
638 uint32_t drv_bo_get_format(struct bo *bo)
639 {
640         return bo->meta.format;
641 }
642
643 size_t drv_bo_get_total_size(struct bo *bo)
644 {
645         return bo->meta.total_size;
646 }
647
648 uint32_t drv_resolve_format(struct driver *drv, uint32_t format, uint64_t use_flags)
649 {
650         if (drv->backend->resolve_format)
651                 return drv->backend->resolve_format(drv, format, use_flags);
652
653         return format;
654 }
655
656 uint32_t drv_num_buffers_per_bo(struct bo *bo)
657 {
658         uint32_t count = 0;
659         size_t plane, p;
660
661         if (bo->is_test_buffer) {
662                 return 0;
663         }
664
665         for (plane = 0; plane < bo->meta.num_planes; plane++) {
666                 for (p = 0; p < plane; p++)
667                         if (bo->handles[p].u32 == bo->handles[plane].u32)
668                                 break;
669                 if (p == plane)
670                         count++;
671         }
672
673         return count;
674 }
675
676 void drv_log_prefix(const char *prefix, const char *file, int line, const char *format, ...)
677 {
678         char buf[50];
679         snprintf(buf, sizeof(buf), "[%s:%s(%d)]", prefix, basename(file), line);
680
681         va_list args;
682         va_start(args, format);
683 #ifdef __ANDROID__
684         __android_log_vprint(ANDROID_LOG_ERROR, buf, format, args);
685 #else
686         fprintf(stderr, "%s ", buf);
687         vfprintf(stderr, format, args);
688 #endif
689         va_end(args);
690 }
691
692 int drv_resource_info(struct bo *bo, uint32_t strides[DRV_MAX_PLANES],
693                       uint32_t offsets[DRV_MAX_PLANES])
694 {
695         for (uint32_t plane = 0; plane < bo->meta.num_planes; plane++) {
696                 strides[plane] = bo->meta.strides[plane];
697                 offsets[plane] = bo->meta.offsets[plane];
698         }
699
700         if (bo->drv->backend->resource_info)
701                 return bo->drv->backend->resource_info(bo, strides, offsets);
702
703         return 0;
704 }