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