Implementation for SwapInterval is zero
[platform/core/uifw/libtpl-egl.git] / src / tpl_surface.c
1 #include "tpl_internal.h"
2
3 static void
4 __tpl_surface_fini(tpl_surface_t *surface)
5 {
6         TPL_ASSERT(surface);
7
8         surface->backend.fini(surface);
9         __tpl_runtime_remove_surface(surface);
10 }
11
12 static void
13 __tpl_surface_free(void *data)
14 {
15         TPL_ASSERT(data);
16
17         __tpl_surface_fini((tpl_surface_t *) data);
18
19         TPL_LOG_F("tpl_surface_t(%p) free", data);
20         free(data);
21 }
22
23 static tpl_surface_t *
24 __tpl_surface_internal_create(tpl_display_t *display, tpl_handle_t handle,
25                                                           tpl_surface_type_t type, tbm_format format,
26                                                           int num_buffers)
27 {
28         tpl_surface_t *surface = NULL;
29
30         if (!display) {
31                 TPL_ERR("Display is NULL!");
32                 return NULL;
33         }
34
35         if (!handle) {
36                 TPL_ERR("Handle is NULL!");
37                 return NULL;
38         }
39
40         if (num_buffers < TPL_SURFACE_MIN_BUFFER_COUNT) {
41                 TPL_ERR("num_buffers(%d) must be >= 2", num_buffers);
42                 return NULL;
43         }
44
45         surface = (tpl_surface_t *) calloc(1, sizeof(tpl_surface_t));
46         if (!surface) {
47                 TPL_ERR("Failed to allocate memory for surface!");
48                 return NULL;
49         }
50
51         if (__tpl_object_init(&surface->base, TPL_OBJECT_SURFACE,
52                                                   __tpl_surface_free) != TPL_ERROR_NONE) {
53                 TPL_ERR("Failed to initialize surface's base class!");
54                 free(surface);
55                 return NULL;
56         }
57
58         surface->display = display;
59         surface->native_handle = handle;
60         surface->type = type;
61         surface->format = format;
62
63         surface->post_interval = 1;
64
65         surface->dump_count = 0;
66         surface->num_buffers = num_buffers;
67
68         /* Intialize backend. */
69         __tpl_surface_init_backend(surface, display->backend.type);
70
71         if ((!surface->backend.init)
72                         || (surface->backend.init(surface) != TPL_ERROR_NONE)) {
73                 TPL_ERR("Failed to initialize surface's backend!");
74                 __tpl_object_fini(&surface->base);
75                 free(surface);
76                 return NULL;
77         }
78
79         /* vulkan feature */
80         /* vulkan can create more than one tpl_surface with one native surface
81          * for supporting oldSwapchain.
82          */
83         if (tpl_surface_get(display, handle) == NULL) {
84                 tpl_result_t ret = TPL_ERROR_NONE;
85                 /* Add it to the runtime. */
86                 ret = __tpl_runtime_add_surface(surface);
87                 if (ret != TPL_ERROR_NONE) {
88                         TPL_ERR("Failed to add surface to runtime list!");
89                         tpl_object_unreference((tpl_object_t *) surface);
90                         return NULL;
91                 }
92         }
93
94         return surface;
95 }
96
97 tpl_surface_t *
98 tpl_surface_create(tpl_display_t *display, tpl_handle_t handle,
99                                    tpl_surface_type_t type, tbm_format format)
100 {
101         tpl_surface_t *surface = NULL;
102
103         surface = __tpl_surface_internal_create(display, handle,
104                                                                                         type, format,
105                                                                                         TPL_SURFACE_DEFAULT_BUFFER_COUNT);
106         if (surface) {
107                 TPL_LOG_F("tpl_display_t(%p) tpl_surface_t(%p) native_handle(%p) format(%d) num_buffers(%d)",
108                                   display, surface, handle, format, TPL_SURFACE_DEFAULT_BUFFER_COUNT);
109         } else
110                 TPL_ERR("Failed to create tpl_surface with native window(%p)", handle);
111         return surface;
112 }
113
114 tpl_surface_t *
115 tpl_surface_create_with_num_buffers(tpl_display_t *display, tpl_handle_t handle,
116                                                                         tpl_surface_type_t type, tbm_format format,
117                                                                         int num_buffers)
118 {
119         tpl_surface_t *surface = NULL;
120
121         surface = __tpl_surface_internal_create(display, handle,
122                                                                                         type, format,
123                                                                                         num_buffers);
124         if (surface) {
125                 TPL_LOG_F("tpl_display_t(%p) tpl_surface_t(%p) native_handle(%p) format(%d)  num_buffers(%d)",
126                                   display, surface, handle, format, num_buffers);
127         } else
128                 TPL_ERR("Failed to create tpl_surface with native window(%p)", handle);
129         return surface;
130 }
131
132 tpl_surface_t *
133 tpl_surface_get(tpl_display_t *display, tpl_handle_t handle)
134 {
135         tpl_surface_t *surface = NULL;
136
137         if (!display) {
138                 TPL_ERR("Display is NULL!");
139                 return NULL;
140         }
141
142         if (!handle) {
143                 TPL_ERR("Handle is NULL!");
144                 return NULL;
145         }
146
147         surface = __tpl_runtime_find_surface(display->backend.type, handle);
148         if (surface) {
149                 TPL_LOG_F("[REUSE] tpl_display_t(%p) tpl_surface_t(%p) native_handle(%p)",
150                                   display, surface, handle);
151         }
152
153         return surface;
154 }
155
156 tpl_display_t *
157 tpl_surface_get_display(tpl_surface_t *surface)
158 {
159         if (!surface) {
160                 TPL_ERR("Surface is NULL!");
161                 return NULL;
162         }
163
164         return surface->display;
165 }
166
167 tpl_handle_t
168 tpl_surface_get_native_handle(tpl_surface_t *surface)
169 {
170         if (!surface) {
171                 TPL_ERR("Surface is NULL!");
172                 return NULL;
173         }
174
175         return surface->native_handle;
176 }
177
178 tpl_surface_type_t
179 tpl_surface_get_type(tpl_surface_t *surface)
180 {
181         if (!surface) {
182                 TPL_ERR("Surface is NULL!");
183                 return TPL_SURFACE_ERROR;
184         }
185
186         return surface->type;
187 }
188
189 tpl_result_t
190 tpl_surface_get_size(tpl_surface_t *surface, int *width, int *height)
191 {
192         if (!surface) {
193                 TPL_ERR("Surface is NULL!");
194                 return TPL_ERROR_INVALID_PARAMETER;
195         }
196
197         if (surface->backend.get_size) {
198                 surface->backend.get_size(surface, width, height);
199         }
200         else {
201                 if (width) *width = surface->width;
202                 if (height) *height = surface->height;
203         }
204
205         return TPL_ERROR_NONE;
206 }
207
208 tpl_result_t
209 tpl_surface_get_rotation(tpl_surface_t *surface, int *rotation)
210 {
211         if (!surface) {
212                 TPL_ERR("Surface is NULL!");
213                 return TPL_ERROR_INVALID_PARAMETER;
214         }
215
216         if (rotation) *rotation = surface->rotation;
217
218         return TPL_ERROR_NONE;
219 }
220
221 tpl_bool_t
222 tpl_surface_validate(tpl_surface_t *surface)
223 {
224         tpl_bool_t was_valid = TPL_TRUE;
225
226         if (!surface || (surface->type != TPL_SURFACE_TYPE_WINDOW)) {
227                 TPL_ERR("Invalid surface!");
228                 return TPL_FALSE;
229         }
230
231         if (!surface->backend.validate) {
232                 TPL_ERR("Backend for surface has not been initialized!");
233                 return TPL_FALSE;
234         }
235
236         TPL_OBJECT_LOCK(surface);
237
238         if (!surface->backend.validate(surface)) was_valid = TPL_FALSE;
239
240         TPL_OBJECT_UNLOCK(surface);
241
242         TPL_LOG_F("tpl_surface_t(%p) valid [%s]", surface,
243                           was_valid ? "TRUE" : "FALSE");
244
245         return was_valid;
246 }
247
248 tpl_result_t
249 tpl_surface_set_post_interval(tpl_surface_t *surface, int interval)
250 {
251         tpl_result_t ret = TPL_ERROR_NONE;
252
253         if (!surface || (surface->type != TPL_SURFACE_TYPE_WINDOW)) {
254                 TPL_ERR("Invalid surface!");
255                 return TPL_ERROR_INVALID_PARAMETER;
256         }
257
258         if (interval < 0)
259                 return TPL_ERROR_NONE;
260
261         TPL_OBJECT_LOCK(surface);
262
263         if (surface->post_interval != interval) {
264                 if (surface->backend.set_post_interval)
265                         ret = surface->backend.set_post_interval(surface, interval);
266
267                 if (ret == TPL_ERROR_NONE)
268                         surface->post_interval = interval;
269         }
270
271         TPL_OBJECT_UNLOCK(surface);
272
273         TPL_LOG_F("tpl_surface_t(%p) post_interval(%d)", surface, surface->post_interval);
274
275         return ret;
276 }
277
278 int
279 tpl_surface_get_post_interval(tpl_surface_t *surface)
280 {
281         int interval;
282
283         if (!surface || (surface->type != TPL_SURFACE_TYPE_WINDOW)) {
284                 TPL_ERR("Invalid surface!");
285                 return -1;
286         }
287
288         TPL_OBJECT_LOCK(surface);
289         interval = surface->post_interval;
290         TPL_OBJECT_UNLOCK(surface);
291
292         TPL_LOG_F("tpl_surface_t(%p) post_interval(%d)", surface, interval);
293
294         return interval;
295 }
296
297
298 tpl_result_t
299 tpl_surface_cancel_dequeued_buffer(tpl_surface_t *surface,
300                                                                    tbm_surface_h tbm_surface)
301 {
302         tpl_result_t ret = TPL_ERROR_NONE;
303
304         if (!surface || (surface->type != TPL_SURFACE_TYPE_WINDOW)) {
305                 TPL_ERR("Invalid surface(%p)", surface);
306                 return TPL_ERROR_INVALID_PARAMETER;
307         }
308
309         if (!surface->backend.cancel_dequeued_buffer) {
310                 TPL_ERR("TPL surface has not been initialized correctly!");
311                 return TPL_ERROR_INVALID_PARAMETER;
312         }
313
314         if (!tbm_surface) {
315                 TPL_ERR("Invalid parameter. tbm_surface(%p)", tbm_surface);
316                 return TPL_ERROR_INVALID_PARAMETER;
317         }
318
319         TPL_LOG_F("tpl_surface_t(%p) tbm_surface(%p)", surface, tbm_surface);
320
321         TPL_OBJECT_LOCK(surface);
322         ret = surface->backend.cancel_dequeued_buffer(surface, tbm_surface);
323         TPL_OBJECT_UNLOCK(surface);
324
325         return ret;
326 }
327
328 tbm_surface_h
329 tpl_surface_dequeue_buffer(tpl_surface_t *surface)
330 {
331         return tpl_surface_dequeue_buffer_with_sync(surface, UINT64_MAX, NULL);
332 }
333
334 tbm_surface_h
335 tpl_surface_dequeue_buffer_with_sync(tpl_surface_t *surface,
336                                                                          uint64_t timeout_ns,
337                                                                          tbm_fd *sync_fence)
338 {
339         TPL_ASSERT(surface);
340
341         tbm_surface_h tbm_surface = NULL;
342
343         if (!surface->backend.dequeue_buffer) {
344                 TPL_ERR("TPL surface has not been initialized correctly!");
345                 return NULL;
346         }
347
348         TRACE_BEGIN("TPL:DEQUEUE_BUFFER");
349         TPL_OBJECT_LOCK(surface);
350
351         tbm_surface = surface->backend.dequeue_buffer(surface, timeout_ns, sync_fence);
352
353         if (tbm_surface) {
354                 /* Update size of the surface. */
355                 surface->width = tbm_surface_get_width(tbm_surface);
356                 surface->height = tbm_surface_get_height(tbm_surface);
357         }
358
359         TPL_OBJECT_UNLOCK(surface);
360         TRACE_END();
361
362         TPL_LOG_F("tpl_surface_t(%p) tbm_surface(%p) (%dx%d)", surface, tbm_surface,
363                           surface->width, surface->height);
364
365         return tbm_surface;
366 }
367
368 tpl_result_t
369 tpl_surface_enqueue_buffer(tpl_surface_t *surface, tbm_surface_h tbm_surface)
370 {
371         return tpl_surface_enqueue_buffer_with_damage_and_sync(surface, tbm_surface,
372                                                                                                                    0, NULL, -1);
373 }
374
375 tpl_result_t
376 tpl_surface_enqueue_buffer_with_damage(tpl_surface_t *surface,
377                                                                            tbm_surface_h tbm_surface,
378                                                                            int num_rects, const int *rects)
379 {
380         return tpl_surface_enqueue_buffer_with_damage_and_sync(surface, tbm_surface,
381                                                                                                                    num_rects, rects, -1);
382 }
383
384 tpl_result_t
385 tpl_surface_enqueue_buffer_with_damage_and_sync(tpl_surface_t *surface,
386                                                                                                 tbm_surface_h tbm_surface,
387                                                                                                 int num_rects, const int *rects,
388                                                                                                 tbm_fd sync_fence)
389 {
390         tpl_result_t ret = TPL_ERROR_NONE;
391
392         if (!surface || (surface->type != TPL_SURFACE_TYPE_WINDOW)) {
393                 TPL_ERR("Invalid surface!");
394                 return TPL_ERROR_INVALID_PARAMETER;
395         }
396
397         if (!tbm_surface) {
398                 TPL_ERR("tbm surface is invalid.");
399                 return TPL_ERROR_INVALID_PARAMETER;
400         }
401
402         TRACE_BEGIN("TPL:ENQUEUE_BUFFER_WITH_DAMAGE");
403         TPL_OBJECT_LOCK(surface);
404
405         TPL_LOG_F("tpl_surface_t(%p) tbm_surface(%p) (%dx%d)", surface, tbm_surface,
406                           tbm_surface_get_width(tbm_surface),
407                           tbm_surface_get_height(tbm_surface));
408
409         /* Call backend post */
410         ret = surface->backend.enqueue_buffer(surface, tbm_surface, num_rects, rects,
411                                                                                   sync_fence);
412
413         TPL_OBJECT_UNLOCK(surface);
414         TRACE_END();
415
416         return ret;
417 }
418
419 tpl_result_t
420 tpl_surface_get_swapchain_buffers(tpl_surface_t *surface,
421                                                                   tbm_surface_h **buffers, int *buffer_count)
422 {
423         tpl_result_t ret = TPL_ERROR_INVALID_OPERATION;
424
425         if (!surface || (surface->type != TPL_SURFACE_TYPE_WINDOW)) {
426                 TPL_ERR("Invalid surface!");
427                 return TPL_ERROR_INVALID_PARAMETER;
428         }
429
430         if (!buffer_count) {
431                 TPL_ERR("Invalid buffer_count!");
432                 return TPL_ERROR_INVALID_PARAMETER;
433         }
434
435         if (!surface->backend.get_swapchain_buffers) {
436                 TPL_ERR("Backend does not support!");
437                 return TPL_ERROR_INVALID_OPERATION;
438         }
439
440         TPL_OBJECT_LOCK(surface);
441
442         ret = surface->backend.get_swapchain_buffers(surface, buffers, buffer_count);
443
444         TPL_OBJECT_UNLOCK(surface);
445
446         return ret;
447 }
448
449 tpl_result_t
450 tpl_surface_create_swapchain(tpl_surface_t *surface, tbm_format format,
451                                                          int width, int height, int buffer_count, int present_mode)
452 {
453         tpl_result_t ret = TPL_ERROR_INVALID_OPERATION;
454
455         if (!surface) {
456                 TPL_ERR("Invalid surface!");
457                 return TPL_ERROR_INVALID_PARAMETER;
458         }
459
460         if ((width <= 0) || (height <= 0)) {
461                 TPL_ERR("Invalid width or  height!");
462                 return TPL_ERROR_INVALID_PARAMETER;
463         }
464
465         if (!surface->backend.create_swapchain) {
466                 TPL_ERR("Backend does not support!");
467                 return TPL_ERROR_INVALID_OPERATION;
468         }
469
470         TPL_LOG_F("tpl_surface_t(%p) format(%d) buffer_count(%d) (%dx%d)",
471                           surface, format, buffer_count, width, height);
472
473         TPL_OBJECT_LOCK(surface);
474
475         ret = surface->backend.create_swapchain(surface, format, width, height,
476                                                                                         buffer_count, present_mode);
477
478         TPL_OBJECT_UNLOCK(surface);
479
480         return ret;
481 }
482
483 tpl_result_t
484 tpl_surface_destroy_swapchain(tpl_surface_t *surface)
485 {
486         tpl_result_t ret = TPL_ERROR_INVALID_OPERATION;
487
488         if (!surface) {
489                 TPL_ERR("Invalid surface!");
490                 return TPL_ERROR_INVALID_PARAMETER;
491         }
492
493         if (!surface->backend.destroy_swapchain) {
494                 TPL_ERR("Backend does not support!");
495                 return TPL_ERROR_INVALID_OPERATION;
496         }
497
498         TPL_LOG_F("tpl_surface_t(%p)", surface);
499
500         TPL_OBJECT_LOCK(surface);
501
502         ret = surface->backend.destroy_swapchain(surface);
503
504         TPL_OBJECT_UNLOCK(surface);
505
506         return ret;
507 }
508
509 tpl_result_t
510 tpl_surface_set_frontbuffer_mode(tpl_surface_t *surface, tpl_bool_t set)
511 {
512         tpl_result_t ret = TPL_ERROR_NONE;
513
514         if (!surface) {
515                 TPL_ERR("Invalid surface!");
516                 return TPL_ERROR_INVALID_PARAMETER;
517         }
518
519         TPL_OBJECT_LOCK(surface);
520
521         if (surface->is_frontbuffer_mode == set) {
522                 TPL_OBJECT_UNLOCK(surface);
523                 return ret;
524         } else {
525                 surface->is_frontbuffer_mode = set;
526         }
527         surface->frontbuffer = NULL;
528
529         TPL_OBJECT_UNLOCK(surface);
530
531         TPL_LOG_F("tpl_surface_t(%p) frontbuffer_mode [%s]",
532                           surface, set ? "ACTIVATED" : "DEACTIVATED");
533         return ret;
534 }
535
536 tpl_result_t
537 tpl_surface_set_reset_cb(tpl_surface_t *surface, void *data, tpl_surface_cb_func_t reset_cb)
538 {
539         tpl_result_t ret = TPL_ERROR_NONE;
540
541         if (!surface) {
542                 TPL_ERR("Invalid surface!");
543                 return TPL_ERROR_INVALID_PARAMETER;
544         }
545
546         TPL_OBJECT_LOCK(surface);
547
548         surface->reset_data = data;
549         surface->reset_cb = reset_cb;
550
551         TPL_OBJECT_UNLOCK(surface);
552
553         return ret;
554 }
555
556 tpl_result_t
557 tpl_surface_set_rotation_capability(tpl_surface_t *surface, tpl_bool_t set)
558 {
559         tpl_result_t ret = TPL_ERROR_NONE;
560
561         if (!surface || (surface->type != TPL_SURFACE_TYPE_WINDOW)) {
562                 TPL_ERR("Invalid surface!");
563                 return TPL_ERROR_INVALID_PARAMETER;
564         }
565
566         TPL_OBJECT_LOCK(surface);
567
568         if (surface->backend.set_rotation_capability)
569                 ret = surface->backend.set_rotation_capability(surface, set);
570         else
571                 surface->rotation_capability = set;
572
573         TPL_OBJECT_UNLOCK(surface);
574
575         return ret;
576 }
577
578 tpl_bool_t
579 tpl_surface_fence_sync_is_available(tpl_surface_t *surface)
580 {
581         tpl_bool_t ret = TPL_FALSE;
582
583         if (!surface || (surface->type != TPL_SURFACE_TYPE_WINDOW)) {
584                 TPL_ERR("Invalid surface!");
585                 return ret;
586         }
587
588         TPL_OBJECT_LOCK(surface);
589         if (surface->backend.fence_sync_is_available)
590                 ret = surface->backend.fence_sync_is_available(surface);
591
592         TPL_OBJECT_UNLOCK(surface);
593
594         return ret;
595 }