Fix null check after deref
[platform/core/uifw/libtdm.git] / src / tdm_capture.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_backend.h"
42 #include "tdm_private.h"
43
44 #define CAPTURE_FUNC_ENTRY() \
45     tdm_func_capture *func_capture; \
46     tdm_private_display *private_display; \
47     tdm_private_capture *private_capture; \
48     tdm_error ret = TDM_ERROR_NONE; \
49     TDM_RETURN_VAL_IF_FAIL(capture != NULL, TDM_ERROR_INVALID_PARAMETER); \
50     private_capture = (tdm_private_capture*)capture; \
51     private_display = private_capture->private_display; \
52     func_capture = &private_display->func_capture
53
54 static tdm_error
55 _tdm_capture_check_if_exist(tdm_private_capture *private_capture,
56                             tbm_surface_h buffer)
57 {
58         tdm_buffer_info *buf_info = NULL;
59
60         LIST_FOR_EACH_ENTRY(buf_info, &private_capture->buffer_list, link) {
61                 if (buf_info->buffer == buffer) {
62                         TDM_ERR("%p attached twice", buffer);
63                         return TDM_ERROR_BAD_REQUEST;
64                 }
65         }
66
67         LIST_FOR_EACH_ENTRY(buf_info, &private_capture->pending_buffer_list, link) {
68                 if (buf_info->buffer == buffer) {
69                         TDM_ERR("%p attached twice", buffer);
70                         return TDM_ERROR_BAD_REQUEST;
71                 }
72         }
73
74         return TDM_ERROR_NONE;
75 }
76
77 INTERN void
78 tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer,
79                     void *user_data)
80 {
81         tdm_private_capture *private_capture = user_data;
82         tdm_private_display *private_display = private_capture->private_display;
83         tdm_buffer_info *buf_info;
84         tbm_surface_h first_entry;
85
86         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
87
88         if (private_capture->owner_tid != syscall(SYS_gettid)) {
89                 tdm_thread_cb_capture_done capture_done;
90                 tdm_error ret;
91
92                 capture_done.base.type = TDM_THREAD_CB_PP_DONE;
93                 capture_done.base.length = sizeof capture_done;
94                 capture_done.capture_stamp = private_capture->stamp;
95                 capture_done.buffer = buffer;
96                 capture_done.user_data = user_data;
97
98                 ret = tdm_thread_send_cb(private_display->private_loop, &capture_done.base);
99                 TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
100
101                 return;
102         }
103
104         if (private_capture->owner_tid != syscall(SYS_gettid))
105                 TDM_NEVER_GET_HERE();
106
107         if (tdm_debug_buffer)
108                 TDM_INFO("capture(%p) done: %p", private_capture, buffer);
109
110         first_entry = tdm_buffer_list_get_first_entry(&private_capture->buffer_list);
111         if (first_entry != buffer)
112                 TDM_ERR("%p is skipped", first_entry);
113
114         if ((buf_info = tdm_buffer_get_info(buffer)))
115                 LIST_DEL(&buf_info->link);
116
117         _pthread_mutex_unlock(&private_display->lock);
118         tdm_buffer_unref_backend(buffer);
119         _pthread_mutex_lock(&private_display->lock);
120 }
121
122 INTERN tdm_private_capture *
123 tdm_capture_find_stamp(tdm_private_display *private_display, unsigned long stamp)
124 {
125         tdm_private_capture *private_capture = NULL;
126
127         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
128
129         LIST_FOR_EACH_ENTRY(private_capture, &private_display->capture_list, link) {
130                 if (private_capture->stamp == stamp)
131                         return private_capture;
132         }
133
134         return NULL;
135 }
136
137 INTERN tdm_private_capture *
138 tdm_capture_create_output_internal(tdm_private_output *private_output,
139                                    tdm_error *error)
140 {
141         tdm_private_display *private_display = private_output->private_display;
142         tdm_func_output *func_output = &private_display->func_output;
143         tdm_func_capture *func_capture = &private_display->func_capture;
144         tdm_private_capture *private_capture = NULL;
145         tdm_capture *capture_backend = NULL;
146         tdm_error ret = TDM_ERROR_NONE;
147
148         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
149
150         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) {
151                 TDM_ERR("no capture capability");
152                 if (error)
153                         *error = TDM_ERROR_NO_CAPABILITY;
154                 return NULL;
155         }
156
157         capture_backend = func_output->output_create_capture(
158                                   private_output->output_backend, &ret);
159         if (ret != TDM_ERROR_NONE) {
160                 if (error)
161                         *error = ret;
162                 return NULL;
163         }
164
165         private_capture = calloc(1, sizeof(tdm_private_capture));
166         if (!private_capture) {
167                 TDM_ERR("failed: alloc memory");
168                 func_capture->capture_destroy(capture_backend);
169                 if (error)
170                         *error = TDM_ERROR_OUT_OF_MEMORY;
171                 return NULL;
172         }
173
174         ret = func_capture->capture_set_done_handler(capture_backend,
175                         tdm_capture_cb_done, private_capture);
176         if (ret != TDM_ERROR_NONE) {
177                 TDM_ERR("capture(%p) set capture_done_handler failed", private_capture);
178                 func_capture->capture_destroy(capture_backend);
179                 if (error)
180                         *error = ret;
181                 return NULL;
182         }
183
184         private_capture->stamp = tdm_helper_get_time_in_millis();
185         while (tdm_capture_find_stamp(private_display, private_capture->stamp))
186                 private_capture->stamp++;
187
188         LIST_ADD(&private_capture->link, &private_output->capture_list);
189         LIST_ADD(&private_capture->display_link, &private_display->capture_list);
190
191         private_capture->target = TDM_CAPTURE_TARGET_OUTPUT;
192         private_capture->private_display = private_display;
193         private_capture->private_output = private_output;
194         private_capture->private_layer = NULL;
195         private_capture->capture_backend = capture_backend;
196         private_capture->owner_tid = syscall(SYS_gettid);
197
198         LIST_INITHEAD(&private_capture->pending_buffer_list);
199         LIST_INITHEAD(&private_capture->buffer_list);
200
201         if (error)
202                 *error = TDM_ERROR_NONE;
203
204         return private_capture;
205 }
206
207 INTERN tdm_private_capture *
208 tdm_capture_create_layer_internal(tdm_private_layer *private_layer,
209                                   tdm_error *error)
210 {
211         tdm_private_output *private_output = private_layer->private_output;
212         tdm_private_display *private_display = private_output->private_display;
213         tdm_func_layer *func_layer = &private_display->func_layer;
214         tdm_func_capture *func_capture = &private_display->func_capture;
215         tdm_private_capture *private_capture = NULL;
216         tdm_capture *capture_backend = NULL;
217         tdm_error ret = TDM_ERROR_NONE;
218
219         TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL);
220
221         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) {
222                 TDM_ERR("no capture capability");
223                 if (error)
224                         *error = TDM_ERROR_NO_CAPABILITY;
225                 return NULL;
226         }
227
228         capture_backend = func_layer->layer_create_capture(private_layer->layer_backend,
229                           &ret);
230         if (ret != TDM_ERROR_NONE)
231                 return NULL;
232
233         private_capture = calloc(1, sizeof(tdm_private_capture));
234         if (!private_capture) {
235                 TDM_ERR("failed: alloc memory");
236                 func_capture->capture_destroy(capture_backend);
237                 if (error)
238                         *error = TDM_ERROR_OUT_OF_MEMORY;
239                 return NULL;
240         }
241
242         private_capture->stamp = tdm_helper_get_time_in_millis();
243         while (tdm_capture_find_stamp(private_display, private_capture->stamp))
244                 private_capture->stamp++;
245
246         LIST_ADD(&private_capture->link, &private_layer->capture_list);
247         LIST_ADD(&private_capture->display_link, &private_display->capture_list);
248
249         private_capture->target = TDM_CAPTURE_TARGET_LAYER;
250         private_capture->private_display = private_display;
251         private_capture->private_output = private_output;
252         private_capture->private_layer = private_layer;
253         private_capture->capture_backend = capture_backend;
254         private_capture->owner_tid = syscall(SYS_gettid);
255
256         LIST_INITHEAD(&private_capture->pending_buffer_list);
257         LIST_INITHEAD(&private_capture->buffer_list);
258
259         if (error)
260                 *error = TDM_ERROR_NONE;
261
262         return private_capture;
263 }
264
265 INTERN void
266 tdm_capture_destroy_internal(tdm_private_capture *private_capture)
267 {
268         tdm_private_display *private_display;
269         tdm_func_capture *func_capture;
270         tdm_buffer_info *b = NULL, *bb = NULL;
271
272         TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
273
274         if (!private_capture)
275                 return;
276
277         private_display = private_capture->private_display;
278
279         LIST_DEL(&private_capture->link);
280         LIST_DEL(&private_capture->display_link);
281
282         func_capture = &private_capture->private_display->func_capture;
283         func_capture->capture_destroy(private_capture->capture_backend);
284
285         if (!LIST_IS_EMPTY(&private_capture->pending_buffer_list)) {
286                 TDM_WRN("capture(%p) not finished:", private_capture);
287                 tdm_buffer_list_dump(&private_capture->pending_buffer_list);
288
289                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
290                         LIST_DEL(&b->link);
291                         _pthread_mutex_unlock(&private_display->lock);
292                         tdm_buffer_unref_backend(b->buffer);
293                         _pthread_mutex_lock(&private_display->lock);
294                 }
295         }
296
297         if (!LIST_IS_EMPTY(&private_capture->buffer_list)) {
298                 TDM_WRN("capture(%p) not finished:", private_capture);
299                 tdm_buffer_list_dump(&private_capture->buffer_list);
300
301                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->buffer_list, link) {
302                         LIST_DEL(&b->link);
303                         _pthread_mutex_unlock(&private_display->lock);
304                         tdm_buffer_unref_backend(b->buffer);
305                         _pthread_mutex_lock(&private_display->lock);
306                 }
307         }
308
309         private_capture->stamp = 0;
310         free(private_capture);
311 }
312
313 EXTERN void
314 tdm_capture_destroy(tdm_capture *capture)
315 {
316         tdm_private_capture *private_capture = capture;
317         tdm_private_display *private_display;
318
319         if (!private_capture)
320                 return;
321
322         private_display = private_capture->private_display;
323
324         _pthread_mutex_lock(&private_display->lock);
325         tdm_capture_destroy_internal(private_capture);
326         _pthread_mutex_unlock(&private_display->lock);
327 }
328
329 EXTERN tdm_error
330 tdm_capture_set_info(tdm_capture *capture, tdm_info_capture *info)
331 {
332         CAPTURE_FUNC_ENTRY();
333
334         TDM_RETURN_VAL_IF_FAIL(info != NULL, TDM_ERROR_INVALID_PARAMETER);
335
336         _pthread_mutex_lock(&private_display->lock);
337
338         if (!func_capture->capture_set_info) {
339                 _pthread_mutex_unlock(&private_display->lock);
340                 TDM_DBG("failed: not implemented!!");
341                 return TDM_ERROR_NOT_IMPLEMENTED;
342         }
343
344         ret = func_capture->capture_set_info(private_capture->capture_backend, info);
345         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
346
347         _pthread_mutex_unlock(&private_display->lock);
348
349         return ret;
350 }
351
352 EXTERN tdm_error
353 tdm_capture_attach(tdm_capture *capture, tbm_surface_h buffer)
354 {
355         CAPTURE_FUNC_ENTRY();
356
357         TDM_RETURN_VAL_IF_FAIL(buffer != NULL, TDM_ERROR_INVALID_PARAMETER);
358
359         _pthread_mutex_lock(&private_display->lock);
360
361         if (!func_capture->capture_attach) {
362                 _pthread_mutex_unlock(&private_display->lock);
363                 TDM_DBG("failed: not implemented!!");
364                 return TDM_ERROR_NOT_IMPLEMENTED;
365         }
366
367         ret = _tdm_capture_check_if_exist(private_capture, buffer);
368         if (ret != TDM_ERROR_NONE) {
369                 _pthread_mutex_unlock(&private_display->lock);
370                 return ret;
371         }
372
373         ret = func_capture->capture_attach(private_capture->capture_backend, buffer);
374         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
375
376         if (ret == TDM_ERROR_NONE) {
377                 tdm_buffer_info *buf_info;
378
379                 if ((buf_info = tdm_buffer_get_info(buffer)))
380                         LIST_ADDTAIL(&buf_info->link, &private_capture->pending_buffer_list);
381
382                 if (tdm_debug_buffer) {
383                         TDM_INFO("capture(%p) attached:", private_capture);
384                         tdm_buffer_list_dump(&private_capture->buffer_list);
385                 }
386         }
387
388         _pthread_mutex_unlock(&private_display->lock);
389
390         return ret;
391 }
392
393 EXTERN tdm_error
394 tdm_capture_commit(tdm_capture *capture)
395 {
396         tdm_buffer_info *b = NULL, *bb = NULL;
397         tdm_private_output *private_output;
398
399         CAPTURE_FUNC_ENTRY();
400
401         _pthread_mutex_lock(&private_display->lock);
402
403         private_output = private_capture->private_output;
404         if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) {
405                 TDM_ERR("output(%d) dpms: %s", private_output->pipe,
406                         dpms_str(private_output->current_dpms_value));
407                 _pthread_mutex_unlock(&private_display->lock);
408                 return TDM_ERROR_BAD_REQUEST;
409         }
410
411         if (!func_capture->capture_commit) {
412                 _pthread_mutex_unlock(&private_display->lock);
413                 TDM_DBG("failed: not implemented!!");
414                 return TDM_ERROR_NOT_IMPLEMENTED;
415         }
416
417         ret = func_capture->capture_commit(private_capture->capture_backend);
418         TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
419
420         if (ret == TDM_ERROR_NONE) {
421                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link) {
422                         LIST_DEL(&b->link);
423                         tdm_buffer_ref_backend(b->buffer);
424                         LIST_ADDTAIL(&b->link, &private_capture->buffer_list);
425                 }
426         } else {
427                 LIST_FOR_EACH_ENTRY_SAFE(b, bb, &private_capture->pending_buffer_list, link)
428                         LIST_DEL(&b->link);
429         }
430
431         _pthread_mutex_unlock(&private_display->lock);
432
433         return ret;
434 }