keyrouter: Fix wrong return value
[platform/core/uifw/libds-tizen.git] / src / libds / swapchain.c
1 #include <assert.h>
2 #include <stdbool.h>
3 #include <stdlib.h>
4
5 #include "libds/log.h"
6 #include "libds/allocator.h"
7
8 #define DS_SWAPCHAIN_CAP    4
9
10 struct ds_swapchain_slot
11 {
12     struct ds_buffer *buffer;
13
14     struct wl_listener buffer_release;
15
16     int age;
17     bool acquired;
18 };
19
20 struct ds_swapchain
21 {
22     struct ds_allocator *allocator;
23
24     struct ds_swapchain_slot slots[DS_SWAPCHAIN_CAP];
25
26     struct wl_listener allocator_destroy;
27
28     int width, height;
29     uint32_t format;
30 };
31
32 static void swapchain_handle_allocator_destroy(struct wl_listener *listener,
33         void *data);
34 static bool swapchain_has_buffer(struct ds_swapchain *swapchain,
35         struct ds_buffer *buffer);
36 static struct ds_buffer *swapchain_slot_acquire(struct ds_swapchain *swapchain,
37         struct ds_swapchain_slot *slot, int *age);
38 static void swapchain_slot_reset(struct ds_swapchain_slot *slot);
39
40 struct ds_swapchain *
41 ds_swapchain_create(struct ds_allocator *alloc, int width, int height,
42         uint32_t format)
43 {
44     struct ds_swapchain *swapchain;
45
46     swapchain = calloc(1, sizeof *swapchain);
47     if (!swapchain)
48         return NULL;
49
50     swapchain->allocator = alloc;
51     swapchain->width = width;
52     swapchain->height = height;
53     swapchain->format = format;
54
55     swapchain->allocator_destroy.notify =
56         swapchain_handle_allocator_destroy;
57     ds_allocator_add_destroy_listener(alloc,
58             &swapchain->allocator_destroy);
59
60     ds_inf("Swapchain(%p) created", swapchain);
61
62     return swapchain;
63 }
64
65 void
66 ds_swapchain_destroy(struct ds_swapchain *swapchain)
67 {
68     size_t i;
69
70     ds_dbg("Destroy swapchain(%p)", swapchain);
71
72     for (i = 0; i < DS_SWAPCHAIN_CAP; i++)
73         swapchain_slot_reset(&swapchain->slots[i]);
74
75     wl_list_remove(&swapchain->allocator_destroy.link);
76     free(swapchain);
77 }
78
79 struct ds_buffer *
80 ds_swapchain_acquire(struct ds_swapchain *swapchain, int *age)
81 {
82     struct ds_swapchain_slot *slot, *free_slot = NULL;
83     size_t i;
84
85     for (i = 0; i < DS_SWAPCHAIN_CAP; i++) {
86         slot = &swapchain->slots[i];
87         if (slot->acquired)
88             continue;
89
90         if (slot->buffer != NULL)
91             return swapchain_slot_acquire(swapchain, slot, age);
92
93         free_slot = slot;
94     }
95
96     if (free_slot == NULL) {
97         ds_err("No free output buffer slot");
98         return NULL;
99     }
100
101     if (!swapchain->allocator)
102         return NULL;
103
104     free_slot->buffer = ds_allocator_create_buffer(swapchain->allocator,
105             swapchain->width, swapchain->height, swapchain->format);
106     if (!free_slot->buffer) {
107         ds_err("Failed to allocate buffer");
108         return NULL;
109     }
110
111     ds_dbg("Allocating new swapchain buffer(%p)", free_slot->buffer);
112
113     return swapchain_slot_acquire(swapchain, free_slot, age);
114 }
115
116 void
117 ds_swapchain_set_buffer_submitted(struct ds_swapchain *swapchain,
118         struct ds_buffer *buffer)
119 {
120     struct ds_swapchain_slot *slot;
121     size_t i;
122
123     assert(buffer);
124
125     if (!swapchain_has_buffer(swapchain, buffer))
126         return;
127
128     for (i = 0; i < DS_SWAPCHAIN_CAP; i++) {
129         slot = &swapchain->slots[i];
130         if (slot->buffer == buffer)
131             slot->age = 1;
132         else if (slot->age > 0)
133             slot->age++;
134     }
135 }
136
137 static void
138 swapchain_handle_allocator_destroy(struct wl_listener *listener, void *data)
139 {
140     struct ds_swapchain *swapchain;
141
142     swapchain = wl_container_of(listener, swapchain, allocator_destroy);
143     swapchain->allocator = NULL;
144 }
145
146 static bool swapchain_has_buffer(struct ds_swapchain *swapchain,
147         struct ds_buffer *buffer)
148 {
149     struct ds_swapchain_slot *slot;
150     size_t i;
151
152     for (i = 0; i < DS_SWAPCHAIN_CAP; i++) {
153         slot = &swapchain->slots[i];
154         if (slot->buffer == buffer)
155             return true;
156     }
157
158     return false;
159 }
160
161 static void
162 swapchain_slot_handle_buffer_release(struct wl_listener *listener, void *data)
163 {
164     struct ds_swapchain_slot *slot;
165
166     slot = wl_container_of(listener, slot, buffer_release);
167
168     ds_dbg("Buffer(%p) released.", slot->buffer);
169
170     wl_list_remove(&slot->buffer_release.link);
171     slot->acquired = false;
172 }
173
174 static struct ds_buffer *
175 swapchain_slot_acquire(struct ds_swapchain *swapchain, struct ds_swapchain_slot *slot,
176         int *age)
177 {
178     assert(!slot->acquired);
179     assert(slot->buffer);
180
181     slot->acquired = true;
182
183     slot->buffer_release.notify = swapchain_slot_handle_buffer_release;
184     ds_buffer_add_release_listener(slot->buffer, &slot->buffer_release);
185
186     if (age != NULL)
187         *age = slot->age;
188
189     return ds_buffer_lock(slot->buffer);
190 }
191
192 static void
193 swapchain_slot_reset(struct ds_swapchain_slot *slot)
194 {
195     if (slot->acquired)
196         wl_list_remove(&slot->buffer_release.link);
197
198     if (slot->buffer)
199         ds_buffer_drop(slot->buffer);
200
201     memset(slot, 0, sizeof *slot);
202 }