1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2022 Roman Stratiienko (r.stratiienko@gmail.com)
5 * SPDX-License-Identifier: MIT
6 */
7
8 #include "u_gralloc_internal.h"
9
10 #include <assert.h>
11 #include <errno.h>
12
13 #include "drm-uapi/drm_fourcc.h"
14 #include "util/log.h"
15 #include "util/macros.h"
16 #include "util/simple_mtx.h"
17 #include "util/u_atomic.h"
18 #include "util/u_memory.h"
19
20 static simple_mtx_t u_gralloc_mutex = SIMPLE_MTX_INITIALIZER;
21
22 static const struct u_grallocs {
23 enum u_gralloc_type type;
24 struct u_gralloc *(*create)();
25 } u_grallocs[] = {
26 /* Prefer the CrOS API as it is significantly faster than IMapper4 */
27 {.type = U_GRALLOC_TYPE_CROS, .create = u_gralloc_cros_api_create},
28 #ifdef USE_IMAPPER4_METADATA_API
29 {.type = U_GRALLOC_TYPE_GRALLOC4, .create = u_gralloc_imapper_api_create},
30 #endif /* USE_IMAPPER4_METADATA_API */
31 {.type = U_GRALLOC_TYPE_FALLBACK, .create = u_gralloc_fallback_create},
32 };
33
34 static struct u_gralloc_cache {
35 struct u_gralloc *u_gralloc;
36 int refcount;
37 } u_gralloc_cache[U_GRALLOC_TYPE_COUNT] = {0};
38
39 struct u_gralloc *
u_gralloc_create(enum u_gralloc_type type)40 u_gralloc_create(enum u_gralloc_type type)
41 {
42 struct u_gralloc *out_gralloc = NULL;
43
44 simple_mtx_lock(&u_gralloc_mutex);
45
46 if (u_gralloc_cache[type].u_gralloc != NULL) {
47 u_gralloc_cache[type].refcount++;
48 out_gralloc = u_gralloc_cache[type].u_gralloc;
49 goto out;
50 }
51
52 for (int i = 0; i < ARRAY_SIZE(u_grallocs); i++) {
53 if (u_grallocs[i].type != type && type != U_GRALLOC_TYPE_AUTO)
54 continue;
55
56 u_gralloc_cache[type].u_gralloc = u_grallocs[i].create();
57 if (u_gralloc_cache[type].u_gralloc) {
58 assert(u_gralloc_cache[type].u_gralloc->ops.get_buffer_basic_info);
59 assert(u_gralloc_cache[type].u_gralloc->ops.destroy);
60
61 u_gralloc_cache[type].refcount = 1;
62
63 out_gralloc = u_gralloc_cache[type].u_gralloc;
64 goto out;
65 }
66 }
67
68 out:
69 simple_mtx_unlock(&u_gralloc_mutex);
70
71 return out_gralloc;
72 }
73
74 void
u_gralloc_destroy(struct u_gralloc ** gralloc NONNULL)75 u_gralloc_destroy(struct u_gralloc **gralloc NONNULL)
76 {
77 int i;
78
79 if (*gralloc == NULL)
80 return;
81
82 simple_mtx_lock(&u_gralloc_mutex);
83
84 for (i = 0; i < ARRAY_SIZE(u_gralloc_cache); i++) {
85 if (u_gralloc_cache[i].u_gralloc == *gralloc) {
86 u_gralloc_cache[i].refcount--;
87 if (u_gralloc_cache[i].refcount == 0) {
88 u_gralloc_cache[i].u_gralloc->ops.destroy(
89 u_gralloc_cache[i].u_gralloc);
90 u_gralloc_cache[i].u_gralloc = NULL;
91 }
92 break;
93 }
94 }
95
96 simple_mtx_unlock(&u_gralloc_mutex);
97
98 assert(i < ARRAY_SIZE(u_grallocs));
99
100 *gralloc = NULL;
101 }
102
103 inline int
u_gralloc_get_buffer_basic_info(struct u_gralloc * gralloc NONNULL,struct u_gralloc_buffer_handle * hnd NONNULL,struct u_gralloc_buffer_basic_info * out NONNULL)104 u_gralloc_get_buffer_basic_info(struct u_gralloc *gralloc NONNULL,
105 struct u_gralloc_buffer_handle *hnd NONNULL,
106 struct u_gralloc_buffer_basic_info *out
107 NONNULL)
108 {
109 struct u_gralloc_buffer_basic_info info = {0};
110 int ret;
111
112 ret = gralloc->ops.get_buffer_basic_info(gralloc, hnd, &info);
113
114 if (ret)
115 return ret;
116
117 *out = info;
118
119 return 0;
120 }
121
122 inline int
u_gralloc_get_buffer_color_info(struct u_gralloc * gralloc NONNULL,struct u_gralloc_buffer_handle * hnd NONNULL,struct u_gralloc_buffer_color_info * out NONNULL)123 u_gralloc_get_buffer_color_info(struct u_gralloc *gralloc NONNULL,
124 struct u_gralloc_buffer_handle *hnd NONNULL,
125 struct u_gralloc_buffer_color_info *out
126 NONNULL)
127 {
128 struct u_gralloc_buffer_color_info info = {0};
129 int ret;
130
131 if (!gralloc->ops.get_buffer_color_info)
132 return -ENOTSUP;
133
134 ret = gralloc->ops.get_buffer_color_info(gralloc, hnd, &info);
135
136 if (ret)
137 return ret;
138
139 *out = info;
140
141 return 0;
142 }
143
144 inline int
u_gralloc_get_front_rendering_usage(struct u_gralloc * gralloc NONNULL,uint64_t * out_usage NONNULL)145 u_gralloc_get_front_rendering_usage(struct u_gralloc *gralloc NONNULL,
146 uint64_t *out_usage NONNULL)
147 {
148 if (!gralloc->ops.get_front_rendering_usage)
149 return -ENOTSUP;
150
151 return gralloc->ops.get_front_rendering_usage(gralloc, out_usage);
152 }
153