1 /* SPDX-License-Identifier: Apache-2.0 OR MIT */
2 /*
3 * Copyright (c) 2015 Rockchip Electronics Co., Ltd.
4 */
5
6 #define MODULE_TAG "mpp_allocator"
7
8 #include "mpp_mem.h"
9 #include "mpp_debug.h"
10 #include "mpp_common.h"
11 #include "mpp_runtime.h"
12 #include "mpp_thread.h"
13 #include "mpp_allocator.h"
14
15 #include "allocator_std.h"
16 #include "allocator_ion.h"
17 #include "allocator_drm.h"
18 #include "allocator_ext_dma.h"
19 #include "allocator_dma_heap.h"
20
21 #include <linux/drm.h>
22
23 #define MPP_ALLOCATOR_LOCK(p) pthread_mutex_lock(&(p)->lock);
24 #define MPP_ALLOCATOR_UNLOCK(p) pthread_mutex_unlock(&(p)->lock);
25
26 typedef enum OsAllocatorApiId_e {
27 ALLOC_API_ALLOC,
28 ALLOC_API_FREE,
29 ALLOC_API_IMPORT,
30 ALLOC_API_RELEASE,
31 ALLOC_API_MMAP,
32 ALLOC_API_BUTT,
33 } OsAllocatorApiId;
34
35 typedef struct MppAllocatorImpl_t {
36 pthread_mutex_t lock;
37 MppBufferType type;
38 MppAllocFlagType flags;
39 size_t alignment;
40 os_allocator os_api;
41 void *ctx;
42 } MppAllocatorImpl;
43
mpp_allocator_api_wrapper(MppAllocator allocator,MppBufferInfo * info,OsAllocatorApiId id)44 static MPP_RET mpp_allocator_api_wrapper(MppAllocator allocator,
45 MppBufferInfo *info,
46 OsAllocatorApiId id)
47 {
48 MppAllocatorImpl *p = (MppAllocatorImpl *)allocator;
49 OsAllocatorFunc func;
50 MPP_RET ret = MPP_NOK;
51
52 if (!p || !info || id >= ALLOC_API_BUTT) {
53 mpp_err_f("invalid input: allocator %p info %p id %d\n",
54 allocator, info, id);
55 return MPP_ERR_UNKNOW;
56 }
57
58 MPP_ALLOCATOR_LOCK(p);
59 switch (id) {
60 case ALLOC_API_ALLOC : {
61 func = p->os_api.alloc;
62 } break;
63 case ALLOC_API_FREE : {
64 func = p->os_api.free;
65 } break;
66 case ALLOC_API_IMPORT : {
67 func = p->os_api.import;
68 } break;
69 case ALLOC_API_RELEASE : {
70 func = p->os_api.release;
71 } break;
72 case ALLOC_API_MMAP : {
73 func = p->os_api.mmap;
74 } break;
75 default : {
76 func = NULL;
77 } break;
78 }
79
80 if (func && p->ctx)
81 ret = func(p->ctx, info);
82
83 MPP_ALLOCATOR_UNLOCK(p);
84
85 return ret;
86 }
87
mpp_allocator_alloc(MppAllocator allocator,MppBufferInfo * info)88 static MPP_RET mpp_allocator_alloc(MppAllocator allocator, MppBufferInfo *info)
89 {
90 return mpp_allocator_api_wrapper(allocator, info, ALLOC_API_ALLOC);
91 }
92
mpp_allocator_free(MppAllocator allocator,MppBufferInfo * info)93 static MPP_RET mpp_allocator_free(MppAllocator allocator, MppBufferInfo *info)
94 {
95 return mpp_allocator_api_wrapper(allocator, info, ALLOC_API_FREE);
96 }
97
mpp_allocator_import(MppAllocator allocator,MppBufferInfo * info)98 static MPP_RET mpp_allocator_import(MppAllocator allocator, MppBufferInfo *info)
99 {
100 return mpp_allocator_api_wrapper(allocator, info, ALLOC_API_IMPORT);
101 }
102
mpp_allocator_release(MppAllocator allocator,MppBufferInfo * info)103 static MPP_RET mpp_allocator_release(MppAllocator allocator,
104 MppBufferInfo *info)
105 {
106 return mpp_allocator_api_wrapper(allocator, info, ALLOC_API_RELEASE);
107 }
108
mpp_allocator_mmap(MppAllocator allocator,MppBufferInfo * info)109 static MPP_RET mpp_allocator_mmap(MppAllocator allocator, MppBufferInfo *info)
110 {
111 return mpp_allocator_api_wrapper(allocator, info, ALLOC_API_MMAP);
112 }
113
114 static MppAllocatorApi mpp_allocator_api = {
115 .size = sizeof(mpp_allocator_api),
116 .version = 1,
117 .alloc = mpp_allocator_alloc,
118 .free = mpp_allocator_free,
119 .import = mpp_allocator_import,
120 .release = mpp_allocator_release,
121 .mmap = mpp_allocator_mmap,
122 };
123
mpp_allocator_get(MppAllocator * allocator,MppAllocatorApi ** api,MppBufferType type,MppAllocFlagType flags)124 MPP_RET mpp_allocator_get(MppAllocator *allocator, MppAllocatorApi **api,
125 MppBufferType type, MppAllocFlagType flags)
126 {
127 MppBufferType buffer_type = (MppBufferType)(type & MPP_BUFFER_TYPE_MASK);
128 MppAllocatorImpl *p = NULL;
129
130 do {
131 if (!allocator || !api || buffer_type >= MPP_BUFFER_TYPE_BUTT) {
132 mpp_err_f("invalid input: allocator %p api %p type %d\n",
133 allocator, api, buffer_type);
134 break;
135 }
136
137 p = mpp_malloc(MppAllocatorImpl, 1);
138 if (!p) {
139 mpp_err_f("failed to malloc allocator context\n");
140 break;
141 }
142
143 p->type = buffer_type;
144 p->flags = flags;
145
146 switch (buffer_type) {
147 case MPP_BUFFER_TYPE_NORMAL : {
148 p->os_api = allocator_std;
149 } break;
150 case MPP_BUFFER_TYPE_ION : {
151 p->os_api = (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_DMA_HEAP)) ? allocator_dma_heap :
152 (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_ION)) ? allocator_ion :
153 (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_DRM)) ? allocator_drm :
154 allocator_std;
155 } break;
156 case MPP_BUFFER_TYPE_EXT_DMA: {
157 p->os_api = allocator_ext_dma;
158 } break;
159 case MPP_BUFFER_TYPE_DRM : {
160 p->os_api = (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_DMA_HEAP)) ? allocator_dma_heap :
161 (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_DRM)) ? allocator_drm :
162 (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_ION)) ? allocator_ion :
163 allocator_std;
164 } break;
165 case MPP_BUFFER_TYPE_DMA_HEAP: {
166 p->os_api = (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_DMA_HEAP)) ? allocator_dma_heap :
167 (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_DRM)) ? allocator_drm :
168 (mpp_rt_allcator_is_valid(MPP_BUFFER_TYPE_ION)) ? allocator_ion :
169 allocator_std;
170 } break;
171 default : {
172 } break;
173 }
174
175 if (p->os_api.open(&p->ctx, SZ_4K, flags))
176 break;
177
178 /* update the real buffer type and flags */
179 p->type = p->os_api.type;
180 if (p->os_api.flags)
181 p->flags = p->os_api.flags(p->ctx);
182
183 {
184 pthread_mutexattr_t attr;
185
186 pthread_mutexattr_init(&attr);
187 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
188 pthread_mutex_init(&p->lock, &attr);
189 pthread_mutexattr_destroy(&attr);
190 }
191
192 *allocator = p;
193 *api = &mpp_allocator_api;
194
195 return MPP_OK;
196 } while (0);
197
198 MPP_FREE(p);
199 *allocator = NULL;
200 *api = NULL;
201
202 return MPP_NOK;
203 }
204
mpp_allocator_put(MppAllocator * allocator)205 MPP_RET mpp_allocator_put(MppAllocator *allocator)
206 {
207 MppAllocatorImpl *p = (MppAllocatorImpl *)*allocator;
208
209 if (!p) {
210 mpp_err_f("invalid input: allocator %p\n", allocator);
211 return MPP_ERR_NULL_PTR;
212 }
213
214 if (!p)
215 return MPP_OK;
216 *allocator = NULL;
217
218 if (p->os_api.close && p->ctx)
219 p->os_api.close(p->ctx);
220 pthread_mutex_destroy(&p->lock);
221 mpp_free(p);
222
223 return MPP_OK;
224 }
225
mpp_allocator_get_flags(const MppAllocator allocator)226 MppAllocFlagType mpp_allocator_get_flags(const MppAllocator allocator)
227 {
228 MppAllocatorImpl *p = (MppAllocatorImpl *)allocator;
229
230 return p ? p->flags : MPP_ALLOC_FLAG_NONE;
231 }
232