enhance log for buffer debugging
[platform/core/uifw/libtdm.git] / src / tdm_buffer.c
1 /**************************************************************************
2
3 libtdm
4
5 Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8          JinYoung Jeon <jy0.jeon@samsung.com>,
9          Taeheon Kim <th908.kim@samsung.com>,
10          YoungJun Cho <yj44.cho@samsung.com>,
11          SooChan Lim <sc1.lim@samsung.com>,
12          Boram Park <sc1.lim@samsung.com>
13
14 Permission is hereby granted, free of charge, to any person obtaining a
15 copy of this software and associated documentation files (the
16 "Software"), to deal in the Software without restriction, including
17 without limitation the rights to use, copy, modify, merge, publish,
18 distribute, sub license, and/or sell copies of the Software, and to
19 permit persons to whom the Software is furnished to do so, subject to
20 the following conditions:
21
22 The above copyright notice and this permission notice (including the
23 next paragraph) shall be included in all copies or substantial portions
24 of the Software.
25
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33
34 **************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "tdm.h"
41 #include "tdm_private.h"
42 #include "tdm_list.h"
43
44 static int tdm_buffer_key;
45 #define TDM_BUFFER_KEY ((unsigned long)&tdm_buffer_key)
46
47 typedef struct _tdm_buffer_func_info {
48         tdm_buffer_release_handler release_func;
49         tdm_buffer_destroy_handler destroy_func;
50         void *user_data;
51
52         struct list_head link;
53 } tdm_buffer_func_info;
54
55 typedef struct _tdm_buffer_info {
56         tbm_surface_h buffer;
57
58         /* ref_count for backend */
59         int backend_ref_count;
60
61         struct list_head release_funcs;
62         struct list_head destroy_funcs;
63
64         struct list_head link;
65 } tdm_buffer_info;
66
67 static void
68 _tdm_buffer_destroy_info(void *user_data)
69 {
70         tdm_buffer_info *buf_info = (tdm_buffer_info *)user_data;
71         tdm_buffer_func_info *func_info = NULL, *next = NULL;
72
73         if (buf_info->backend_ref_count > 0)
74                 TDM_NEVER_GET_HERE();
75
76         LIST_FOR_EACH_ENTRY_SAFE(func_info, next, &buf_info->release_funcs, link) {
77                 LIST_DEL(&func_info->link);
78                 free(func_info);
79         }
80
81         LIST_FOR_EACH_ENTRY_SAFE(func_info, next, &buf_info->destroy_funcs, link)
82         func_info->destroy_func(buf_info->buffer, func_info->user_data);
83
84         LIST_FOR_EACH_ENTRY_SAFE(func_info, next, &buf_info->destroy_funcs, link) {
85                 LIST_DEL(&func_info->link);
86                 free(func_info);
87         }
88
89         LIST_DEL(&buf_info->link);
90
91         free(buf_info);
92 }
93
94 static tdm_buffer_info *
95 _tdm_buffer_get_info(tbm_surface_h buffer)
96 {
97         tdm_buffer_info *buf_info = NULL;
98         tbm_bo bo;
99
100         bo = tbm_surface_internal_get_bo(buffer, 0);
101         TDM_RETURN_VAL_IF_FAIL(bo != NULL, NULL);
102
103         tbm_bo_get_user_data(bo, TDM_BUFFER_KEY, (void **)&buf_info);
104
105         if (!buf_info) {
106                 buf_info = calloc(1, sizeof(tdm_buffer_info));
107                 TDM_RETURN_VAL_IF_FAIL(buf_info != NULL, NULL);
108
109                 buf_info->buffer = buffer;
110
111                 LIST_INITHEAD(&buf_info->release_funcs);
112                 LIST_INITHEAD(&buf_info->destroy_funcs);
113                 LIST_INITHEAD(&buf_info->link);
114
115                 tbm_bo_add_user_data(bo, TDM_BUFFER_KEY, _tdm_buffer_destroy_info);
116                 tbm_bo_set_user_data(bo, TDM_BUFFER_KEY, buf_info);
117         }
118
119         return buf_info;
120 }
121
122 EXTERN tdm_error
123 tdm_buffer_add_release_handler(tbm_surface_h buffer,
124                                tdm_buffer_release_handler func, void *user_data)
125 {
126         tdm_buffer_info *buf_info;
127         tdm_buffer_func_info *func_info;
128
129         TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
130         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
131
132         buf_info = _tdm_buffer_get_info(buffer);
133         TDM_RETURN_VAL_IF_FAIL(buf_info != NULL, TDM_ERROR_OUT_OF_MEMORY);
134
135         func_info = calloc(1, sizeof(tdm_buffer_func_info));
136         TDM_RETURN_VAL_IF_FAIL(func_info != NULL, TDM_ERROR_OUT_OF_MEMORY);
137
138         func_info->release_func = func;
139         func_info->user_data = user_data;
140
141         LIST_ADD(&func_info->link, &buf_info->release_funcs);
142
143         return TDM_ERROR_NONE;
144 }
145
146 EXTERN void
147 tdm_buffer_remove_release_handler(tbm_surface_h buffer,
148                                   tdm_buffer_release_handler func, void *user_data)
149 {
150         tdm_buffer_info *buf_info;
151         tdm_buffer_func_info *func_info = NULL, *next = NULL;
152
153         TDM_RETURN_IF_FAIL(buffer != NULL);
154         TDM_RETURN_IF_FAIL(func != NULL);
155
156         buf_info = _tdm_buffer_get_info(buffer);
157         TDM_RETURN_IF_FAIL(buf_info != NULL);
158
159         LIST_FOR_EACH_ENTRY_SAFE(func_info, next, &buf_info->release_funcs, link) {
160                 if (func_info->release_func != func || func_info->user_data != user_data)
161                         continue;
162
163                 LIST_DEL(&func_info->link);
164                 free(func_info);
165
166                 return;
167         }
168 }
169
170
171 EXTERN tbm_surface_h
172 tdm_buffer_ref_backend(tbm_surface_h buffer)
173 {
174         tdm_buffer_info *buf_info;
175
176         TDM_RETURN_VAL_IF_FAIL(buffer != NULL, NULL);
177
178         buf_info = _tdm_buffer_get_info(buffer);
179         TDM_RETURN_VAL_IF_FAIL(buf_info != NULL, NULL);
180
181         buf_info->backend_ref_count++;
182
183         return buffer;
184 }
185
186 EXTERN void
187 tdm_buffer_unref_backend(tbm_surface_h buffer)
188 {
189         tdm_buffer_info *buf_info;
190         tdm_buffer_func_info *func_info = NULL, *next = NULL;
191
192         TDM_RETURN_IF_FAIL(buffer != NULL);
193
194         buf_info = _tdm_buffer_get_info(buffer);
195         TDM_RETURN_IF_FAIL(buf_info != NULL);
196
197         buf_info->backend_ref_count--;
198
199         if (buf_info->backend_ref_count > 0)
200                 return;
201
202         LIST_FOR_EACH_ENTRY_SAFE(func_info, next, &buf_info->release_funcs, link) {
203                 tbm_surface_internal_ref(buffer);
204                 func_info->release_func(buffer, func_info->user_data);
205                 tbm_surface_internal_unref(buffer);
206         }
207 }
208
209 EXTERN tdm_error
210 tdm_buffer_add_destroy_handler(tbm_surface_h buffer,
211                                tdm_buffer_destroy_handler func, void *user_data)
212 {
213         tdm_buffer_info *buf_info;
214         tdm_buffer_func_info *func_info;
215
216         TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
217         TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
218
219         buf_info = _tdm_buffer_get_info(buffer);
220         TDM_RETURN_VAL_IF_FAIL(buf_info != NULL, TDM_ERROR_OUT_OF_MEMORY);
221
222         func_info = calloc(1, sizeof(tdm_buffer_func_info));
223         TDM_RETURN_VAL_IF_FAIL(func_info != NULL, TDM_ERROR_OUT_OF_MEMORY);
224
225         func_info->destroy_func = func;
226         func_info->user_data = user_data;
227
228         LIST_ADD(&func_info->link, &buf_info->destroy_funcs);
229
230         return TDM_ERROR_NONE;
231 }
232
233 EXTERN void
234 tdm_buffer_remove_destroy_handler(tbm_surface_h buffer,
235                                   tdm_buffer_destroy_handler func, void *user_data)
236 {
237         tdm_buffer_info *buf_info;
238         tdm_buffer_func_info *func_info = NULL, *next = NULL;
239
240         TDM_RETURN_IF_FAIL(buffer != NULL);
241         TDM_RETURN_IF_FAIL(func != NULL);
242
243         buf_info = _tdm_buffer_get_info(buffer);
244         TDM_RETURN_IF_FAIL(buf_info != NULL);
245
246         LIST_FOR_EACH_ENTRY_SAFE(func_info, next, &buf_info->destroy_funcs, link) {
247                 if (func_info->destroy_func != func || func_info->user_data != user_data)
248                         continue;
249
250                 LIST_DEL(&func_info->link);
251                 free(func_info);
252
253                 return;
254         }
255 }
256
257 INTERN void
258 tdm_buffer_add_list(struct list_head *list, tbm_surface_h buffer)
259 {
260         tdm_buffer_info *buf_info;
261
262         TDM_RETURN_IF_FAIL(list != NULL);
263         TDM_RETURN_IF_FAIL(buffer != NULL);
264
265         buf_info = _tdm_buffer_get_info(buffer);
266         TDM_RETURN_IF_FAIL(buf_info != NULL);
267
268         if (buf_info->link.prev != buf_info->link.next) {
269                 TDM_ERR("%p already added other list\n", buffer);
270                 return;
271         }
272
273         LIST_ADD(&buf_info->link, list);
274 }
275
276 INTERN void
277 tdm_buffer_remove_list(struct list_head *list, tbm_surface_h buffer)
278 {
279         tdm_buffer_info *buf_info, *b = NULL, *bb = NULL;
280
281         TDM_RETURN_IF_FAIL(list != NULL);
282
283         if (!buffer)
284                 return;
285
286         buf_info = _tdm_buffer_get_info(buffer);
287         TDM_RETURN_IF_FAIL(buf_info != NULL);
288
289         LIST_FOR_EACH_ENTRY_SAFE(b, bb, list, link) {
290                 if (b == buf_info) {
291                         LIST_DEL(&buf_info->link);
292                         return;
293                 }
294         }
295 }
296
297 INTERN void
298 tdm_buffer_dump_list(struct list_head *list, char *str, int len)
299 {
300         tdm_buffer_info *buf_info = NULL;
301
302         TDM_RETURN_IF_FAIL(list != NULL);
303
304         LIST_FOR_EACH_ENTRY(buf_info, list, link) {
305                 if (len > 0) {
306                         int l = snprintf(str, len, " %p", buf_info->buffer);
307                         str += l;
308                         len -= l;
309                 }
310                 else
311                         break;
312         }
313 }