rearrange the directories of git repository
[platform/core/uifw/libds-tizen.git] / src / backend / tdm / tdm_buffer_queue.c
1 #include <assert.h>
2 #include <errno.h>
3 #include <stdlib.h>
4 #include <sys/eventfd.h>
5
6 #include <libds/log.h>
7 #include "libds/interfaces/buffer.h"
8
9 #include "tdm.h"
10 #include "tdm_buffer_queue.h"
11
12 static void
13 buffer_queue_handle_acquirable(tbm_surface_queue_h surface_queue,
14         void *data);
15 static struct ds_tdm_queue_buffer *
16 create_queue_buffer(struct ds_tdm_buffer_queue *queue,
17         tbm_surface_h surface);
18 static void queue_buffer_destroy(struct ds_tdm_queue_buffer *buffer);
19 static void queue_buffer_drop(struct ds_tdm_queue_buffer *buffer);
20 static struct ds_buffer *
21 queue_buffer_acquire(struct ds_tdm_queue_buffer *buffer);
22 static int buffer_queue_handle_acquirable_efd(int fd, uint32_t mask,
23         void *data);
24
25 WL_EXPORT void *
26 ds_tdm_buffer_queue_get_native_queue(struct ds_tdm_buffer_queue *queue)
27 {
28     return (void *)queue->tbm_surface_queue;
29 }
30
31 WL_EXPORT struct ds_buffer *
32 ds_tdm_buffer_queue_acquire(struct ds_tdm_buffer_queue *queue)
33 {
34     struct ds_tdm_queue_buffer *buffer;
35     tbm_surface_h surface;
36     tbm_surface_queue_error_e err;
37
38     if (!tbm_surface_queue_can_acquire(queue->tbm_surface_queue, 0))
39         return NULL;
40
41     err = tbm_surface_queue_acquire(queue->tbm_surface_queue, &surface);
42     if (err != TBM_SURFACE_QUEUE_ERROR_NONE ||
43             surface == NULL) {
44         ds_err("Could not acquire tbm_surface from queue(%p)", queue);
45         return NULL;
46     }
47
48     wl_list_for_each(buffer, &queue->buffers, link) {
49         if (buffer->surface == surface)
50             return queue_buffer_acquire(buffer);
51     }
52
53     buffer = create_queue_buffer(queue, surface);
54     if (!buffer) {
55         ds_err("Could not create tbm_queue_buffer with queue(%p)", queue);
56         return NULL;
57     }
58
59     wl_list_insert(&queue->buffers, &buffer->link);
60
61     return queue_buffer_acquire(buffer);
62 }
63
64 WL_EXPORT void
65 ds_tdm_buffer_queue_add_acquirable_listener(struct ds_tdm_buffer_queue *queue,
66         struct wl_listener *listener)
67 {
68     wl_signal_add(&queue->events.acquirable, listener);
69 }
70
71 struct ds_tdm_buffer_queue *
72 create_buffer_queue(struct ds_tdm_output *output)
73 {
74     struct ds_tdm_buffer_queue *queue;
75     tdm_error err;
76
77     queue = calloc(1, sizeof *queue);
78     if (!queue)
79         return NULL;
80
81     wl_list_init(&queue->buffers);
82
83     wl_signal_init(&queue->events.acquirable);
84
85     queue->tbm_surface_queue =
86         tdm_hwc_get_client_target_buffer_queue(output->tdm.hwc, &err);
87     if (err != TDM_ERROR_NONE ||
88             queue->tbm_surface_queue == NULL) {
89         ds_err("Could not get target buffer queue: err(%d)", err);
90         free(queue);
91         return NULL;
92     }
93
94     tbm_surface_queue_reset(queue->tbm_surface_queue,
95             output->base.pending.mode->width,
96             output->base.pending.mode->height,
97             tbm_surface_queue_get_format(queue->tbm_surface_queue));
98
99     /* The callback function for tbm_surface_queue_add_acquirable_cb() may be
100      * called on different thread. This eventfd is to emit a signal of
101      * events.acquirable on the thread getting this buffer queue. */
102     queue->acquirable_efd = eventfd(0, EFD_NONBLOCK);
103     if (queue->acquirable_efd < 0) {
104         ds_log_errno(DS_ERR,
105                 "Could not create eventfd for acquirable callback");
106         free(queue);
107         return NULL;
108     }
109
110     queue->acquirable_source = wl_event_loop_add_fd(
111             wl_display_get_event_loop(output->backend->wl_display),
112             queue->acquirable_efd,
113             WL_EVENT_READABLE,
114             buffer_queue_handle_acquirable_efd,
115             queue);
116
117     tbm_surface_queue_add_acquirable_cb(queue->tbm_surface_queue,
118             buffer_queue_handle_acquirable, (void *)queue);
119
120     return queue;
121 }
122
123 void
124 buffer_queue_destroy(struct ds_tdm_buffer_queue *queue)
125 {
126     struct ds_tdm_queue_buffer *buffer, *buffer_tmp;
127
128     wl_list_for_each_safe(buffer, buffer_tmp, &queue->buffers, link)
129         queue_buffer_drop(buffer);
130
131     wl_event_source_remove(queue->acquirable_source);
132     close(queue->acquirable_efd);
133     tbm_surface_queue_destroy(queue->tbm_surface_queue);
134     free(queue);
135 }
136
137 struct ds_tdm_queue_buffer *
138 buffer_queue_find_buffer(struct ds_tdm_buffer_queue *queue,
139         struct ds_buffer *ds_buffer)
140 {
141     struct ds_tdm_queue_buffer *buffer;
142
143     wl_list_for_each(buffer, &queue->buffers, link) {
144         if (&buffer->base == ds_buffer)
145             return buffer;
146     }
147
148     return NULL;
149 }
150
151 static void
152 buffer_queue_handle_acquirable(tbm_surface_queue_h surface_queue, void *data)
153 {
154     struct ds_tdm_buffer_queue *queue = data;
155     uint64_t acquirable = 1;
156     int ret;
157
158     ret = write(queue->acquirable_efd, &acquirable, sizeof(acquirable));
159     if (ret < 0)
160         ds_log_errno(DS_ERR, "Could not write eventfd for acquirable buffer");
161 }
162
163 static const struct ds_buffer_interface queue_buffer_iface;
164
165 static struct ds_tdm_queue_buffer *
166 create_queue_buffer(struct ds_tdm_buffer_queue *queue, tbm_surface_h surface)
167 {
168     struct ds_tdm_queue_buffer *buffer;
169
170     buffer = calloc(1, sizeof *buffer);
171     if (!buffer)
172         return NULL;
173
174     ds_buffer_init(&buffer->base, &queue_buffer_iface,
175             tbm_surface_get_width(surface),
176             tbm_surface_get_height(surface));
177
178     buffer->queue = queue;
179     buffer->surface = surface;
180
181     return buffer;
182 }
183
184 static void
185 queue_buffer_destroy(struct ds_tdm_queue_buffer *buffer)
186 {
187     free(buffer);
188 }
189
190 static struct ds_tdm_queue_buffer *
191 queue_buffer_from_buffer(struct ds_buffer *ds_buffer)
192 {
193     assert(ds_buffer->iface == &queue_buffer_iface);
194     return (struct ds_tdm_queue_buffer *)ds_buffer;
195 }
196
197 static void
198 queue_buffer_iface_destroy(struct ds_buffer *ds_buffer)
199 {
200     struct ds_tdm_queue_buffer *buffer;
201
202     buffer = queue_buffer_from_buffer(ds_buffer);
203     queue_buffer_destroy(buffer);
204 }
205
206 static bool
207 queue_buffer_iface_begin_data_ptr_access(struct ds_buffer *ds_buffer,
208         uint32_t flags, void **data, uint32_t *format, size_t *stride)
209 {
210     struct ds_tdm_queue_buffer *buffer;
211     tbm_surface_info_s info;
212     int tbm_access_flags = 0;
213     int ret;
214
215     buffer = queue_buffer_from_buffer(ds_buffer);
216
217     if (!buffer->surface) {
218         ds_err("No tbm_surface. It's a dropped buffer(%p)", buffer);
219         return false;
220     }
221
222     if (flags & DS_BUFFER_DATA_PTR_ACCESS_READ)
223         tbm_access_flags |= TBM_OPTION_READ;
224     else if (flags & DS_BUFFER_DATA_PTR_ACCESS_WRITE)
225         tbm_access_flags |= TBM_OPTION_WRITE;
226
227     ret = tbm_surface_map(buffer->surface, tbm_access_flags, &info);
228     if (ret != TBM_SURFACE_ERROR_NONE) {
229         ds_err("Could not map tbm_surface of buffer(%p)", buffer);
230         return false;
231     }
232
233     *data = info.planes[0].ptr;
234     *format = info.format;
235     *stride = info.planes[0].stride;
236
237     return true;
238 }
239
240 static void
241 queue_buffer_iface_end_data_ptr_access(struct ds_buffer *ds_buffer)
242 {
243     struct ds_tdm_queue_buffer *buffer;
244
245     buffer = queue_buffer_from_buffer(ds_buffer);
246     if (!buffer->surface) {
247         ds_err("No tbm_surface. It's a dropped buffer(%p)", buffer);
248         return;
249     }
250
251     tbm_surface_unmap(buffer->surface);
252 }
253
254 static const struct ds_buffer_interface queue_buffer_iface =
255 {
256     .destroy = queue_buffer_iface_destroy,
257     .begin_data_ptr_access = queue_buffer_iface_begin_data_ptr_access,
258     .end_data_ptr_access = queue_buffer_iface_end_data_ptr_access,
259 };
260
261 static void
262 queue_buffer_handle_buffer_release(struct wl_listener *listener, void *data)
263 {
264     struct ds_tdm_queue_buffer *buffer;
265
266     buffer = wl_container_of(listener, buffer, buffer_release);
267
268     wl_list_remove(&buffer->buffer_release.link);
269     buffer->acquired = false;
270
271     tbm_surface_queue_release(buffer->queue->tbm_surface_queue,
272             buffer->surface);
273 }
274
275 static void
276 queue_buffer_drop(struct ds_tdm_queue_buffer *buffer)
277 {
278     if (buffer->acquired)
279         wl_list_remove(&buffer->buffer_release.link);
280
281     wl_list_remove(&buffer->link);
282     ds_buffer_drop(&buffer->base);
283     buffer->surface = NULL;
284 }
285
286 static struct ds_buffer *
287 queue_buffer_acquire(struct ds_tdm_queue_buffer *buffer)
288 {
289     assert(!buffer->acquired);
290
291     buffer->acquired = true;
292     buffer->buffer_release.notify = queue_buffer_handle_buffer_release;
293     ds_buffer_add_release_listener(&buffer->base, &buffer->buffer_release);
294
295     return ds_buffer_lock(&buffer->base);
296 }
297
298 static int
299 buffer_queue_handle_acquirable_efd(int fd, uint32_t mask, void *data)
300 {
301     struct ds_tdm_buffer_queue *queue = data;
302     uint64_t acquirable_event;
303
304     if (read(fd, &acquirable_event, sizeof(acquirable_event)) < 0 &&
305             errno != EAGAIN)
306         return -1;
307
308     wl_signal_emit(&queue->events.acquirable, queue);
309
310     return 0;
311 }