Merge branch 'devel' into tizen
[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 typedef struct _tdm_buffer_func_info
45 {
46     tdm_buffer_release_handler func;
47     void *user_data;
48
49     struct list_head link;
50 } tdm_buffer_func_info;
51
52 typedef struct _tdm_buffer_info
53 {
54     tbm_surface_h buffer;
55
56     /* ref_count for frontend */
57     int ref_count;
58
59     /* ref_count for backend */
60     int backend_ref_count;
61
62     struct list_head release_funcs;
63     struct list_head link;
64 } tdm_buffer_info;
65
66 static int buffer_list_init;
67 static struct list_head buffer_list;
68
69 static void
70 _tdm_buffer_destroy(tdm_buffer_info *buf_info)
71 {
72     tdm_buffer_func_info *func_info = NULL, *next = NULL;
73
74     TDM_WARNING_IF_FAIL(buf_info->ref_count == 0);
75     TDM_WARNING_IF_FAIL(buf_info->backend_ref_count == 0);
76
77     LIST_FOR_EACH_ENTRY_SAFE(func_info, next, &buf_info->release_funcs, link)
78     {
79         LIST_DEL(&func_info->link);
80         free(func_info);
81     }
82
83     LIST_DEL(&buf_info->link);
84
85     tbm_surface_internal_unref(buf_info->buffer);
86     free(buf_info);
87 }
88
89 EXTERN tdm_buffer*
90 tdm_buffer_create(tbm_surface_h buffer, tdm_error *error)
91 {
92     tdm_buffer_info *buf_info;
93
94     if (!buffer_list_init)
95     {
96         LIST_INITHEAD(&buffer_list);
97         buffer_list_init = 1;
98     }
99
100     if (!buffer)
101     {
102         if (error)
103             *error = TDM_ERROR_INVALID_PARAMETER;
104
105         TDM_ERR("'buffer != NULL' failed");
106
107         return NULL;
108     }
109
110     buf_info = calloc(1, sizeof(tdm_buffer_info));
111     if (!buf_info)
112     {
113         if (error)
114             *error = TDM_ERROR_OUT_OF_MEMORY;
115
116         TDM_ERR("'buf_info != NULL' failed");
117
118         return NULL;
119     }
120
121     buf_info->ref_count = 1;
122
123     tbm_surface_internal_ref(buffer);
124     buf_info->buffer = buffer;
125
126     LIST_INITHEAD(&buf_info->release_funcs);
127     LIST_ADDTAIL(&buf_info->link, &buffer_list);
128
129     if (error)
130         *error = TDM_ERROR_NONE;
131
132     return (tdm_buffer*)buf_info;
133 }
134
135 EXTERN tdm_buffer*
136 tdm_buffer_ref(tdm_buffer *buffer, tdm_error *error)
137 {
138     tdm_buffer_info *buf_info;
139
140     if (!buffer)
141     {
142         if (error)
143             *error = TDM_ERROR_INVALID_PARAMETER;
144
145         TDM_ERR("'buffer != NULL' failed");
146
147         return NULL;
148     }
149
150     buf_info = buffer;
151     buf_info->ref_count++;
152
153     if (error)
154         *error = TDM_ERROR_NONE;
155
156     return buffer;
157 }
158
159 EXTERN void
160 tdm_buffer_unref(tdm_buffer *buffer)
161 {
162     tdm_buffer_info *buf_info;
163
164     if (!buffer)
165         return;
166
167     buf_info = buffer;
168     TDM_RETURN_IF_FAIL (buf_info->ref_count > 0);
169
170     buf_info->ref_count--;
171
172     /* destroy tdm_buffer when both ref_count and backend_ref_count are 0. */
173     if (buf_info->ref_count > 0 || buf_info->backend_ref_count > 0)
174         return;
175
176     _tdm_buffer_destroy(buf_info);
177 }
178
179 EXTERN tdm_error
180 tdm_buffer_add_release_handler(tdm_buffer *buffer,
181                                tdm_buffer_release_handler func, void *user_data)
182 {
183     tdm_buffer_info *buf_info;
184     tdm_buffer_func_info *func_info;
185
186     TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
187     TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
188
189     func_info = calloc(1, sizeof(tdm_buffer_func_info));
190     TDM_RETURN_VAL_IF_FAIL(func_info != NULL, TDM_ERROR_OUT_OF_MEMORY);
191
192     func_info->func = func;
193     func_info->user_data = user_data;
194
195     buf_info = buffer;
196     LIST_ADD(&func_info->link, &buf_info->release_funcs);
197
198     return TDM_ERROR_NONE;
199 }
200
201 EXTERN void
202 tdm_buffer_remove_release_handler(tdm_buffer *buffer, tdm_buffer_release_handler func, void *user_data)
203 {
204     tdm_buffer_info *buf_info;
205     tdm_buffer_func_info *func_info = NULL, *next = NULL;
206
207     TDM_RETURN_IF_FAIL(buffer != NULL);
208     TDM_RETURN_IF_FAIL(func != NULL);
209
210     buf_info = buffer;
211     LIST_FOR_EACH_ENTRY_SAFE(func_info, next, &buf_info->release_funcs, link)
212     {
213         if (func_info->func != func || func_info->user_data != user_data)
214             continue;
215
216         LIST_DEL(&func_info->link);
217         free(func_info);
218
219         return;
220     }
221 }
222
223
224 INTERN tdm_buffer*
225 tdm_buffer_ref_backend(tdm_buffer *buffer)
226 {
227     tdm_buffer_info *buf_info;
228
229     TDM_RETURN_VAL_IF_FAIL(buffer != NULL, NULL);
230
231     buf_info = buffer;
232     buf_info->backend_ref_count++;
233
234     return buffer;
235 }
236
237 INTERN void
238 tdm_buffer_unref_backend(tdm_buffer *buffer)
239 {
240     tdm_buffer_info *buf_info;
241     tdm_buffer_func_info *func_info = NULL, *next = NULL;
242     int old_ref_count;
243
244     TDM_RETURN_IF_FAIL(buffer != NULL);
245
246     buf_info = buffer;
247     buf_info->backend_ref_count--;
248
249     if (buf_info->backend_ref_count > 0)
250         return;
251
252     /* ref_count can become 0 in user release function. In that case, buf_info
253      * will be destroyed in tbm_buffer_unref. So we destroy buf_info in this
254      * function only in case that old_ref_count is 0.
255      */
256     old_ref_count = buf_info->ref_count;
257
258     LIST_FOR_EACH_ENTRY_SAFE(func_info, next, &buf_info->release_funcs, link)
259         func_info->func(buffer, func_info->user_data);
260
261     /* finally, both ref_count and backend_ref_count are 0. destroy tdm_buffer */
262     if (old_ref_count == 0 && buf_info->ref_count == 0)
263         _tdm_buffer_destroy(buf_info);
264 }
265
266 INTERN tbm_surface_h
267 tdm_buffer_get_surface(tdm_buffer *buffer)
268 {
269     tdm_buffer_info *buf_info = buffer;
270
271     TDM_RETURN_VAL_IF_FAIL(buf_info != NULL, NULL);
272
273     return buf_info->buffer;
274 }
275
276 INTERN tdm_buffer*
277 tdm_buffer_get(tbm_surface_h buffer)
278 {
279     tdm_buffer_info *found;
280
281     TDM_RETURN_VAL_IF_FAIL(buffer != NULL, NULL);
282
283     if (!buffer_list_init)
284     {
285         LIST_INITHEAD(&buffer_list);
286         buffer_list_init = 1;
287     }
288
289     LIST_FOR_EACH_ENTRY(found, &buffer_list, link)
290     {
291         if (found->buffer == buffer)
292             return found;
293     }
294
295     return NULL;
296 }