e_linux_dmabuf: add first implementation of ds_linux_dmabuf interface
[platform/upstream/enlightenment.git] / src / bin / e_comp_wl_buffer.c
1
2 #include "e_comp_wl_buffer_intern.h"
3 #include "e_tbm_gbm_server_intern.h"
4 #include "e_linux_dmabuf_intern.h"
5 #include "e_explicit_sync_intern.h"
6
7 #include <libds/single_pixel_buffer_v1.h>
8
9 #include <wayland-tbm-server.h>
10
11 typedef struct _E_Buffer E_Buffer;
12
13 struct _E_Buffer
14 {
15    E_Comp_Wl_Buffer base;
16    struct ds_buffer *ds_buffer;
17
18    void (*lock)(E_Buffer *buffer);
19    void (*release)(E_Buffer *buffer);
20 };
21
22 static void _e_comp_wl_buffer_ref(E_Comp_Wl_Buffer *buffer);
23 static void _e_comp_wl_buffer_unref(E_Comp_Wl_Buffer *buffer);
24 static void _e_comp_wl_buffer_reference_cb_destroy(struct wl_listener *listener, void *data);
25
26 static E_Buffer *_e_buffer_create_with_ds_buffer(struct ds_buffer *ds_buffer);
27 static E_Buffer *_e_buffer_create_with_tbm_surface(tbm_surface_h tbm_surface);
28 static E_Buffer *_e_buffer_from_base(E_Comp_Wl_Buffer *base);
29 static E_Buffer *_e_buffer_from_buffer(struct ds_buffer *ds_buffer);
30 static void _e_buffer_destroy(E_Buffer *buffer);
31 static void _e_buffer_cb_resource_destroy(struct wl_listener *listener, void *data);
32 static void _e_buffer_transform_update(E_Buffer *buffer);
33 static void _e_buffer_tbm_surface_destroy(E_Buffer *buffer);
34
35 E_API void
36 e_comp_wl_buffer_reference(E_Comp_Wl_Buffer_Ref *ref, E_Comp_Wl_Buffer *buffer)
37 {
38    if (ref->buffer == buffer)
39      return;
40
41    if (ref->buffer)
42      {
43         wl_list_remove(&ref->destroy_listener.link);
44         _e_comp_wl_buffer_unref(ref->buffer);
45      }
46
47    if (buffer)
48      {
49         _e_comp_wl_buffer_ref(buffer);
50
51         ref->destroy_listener.notify = _e_comp_wl_buffer_reference_cb_destroy;
52         wl_signal_add(&buffer->destroy_signal, &ref->destroy_listener);
53      }
54
55    ref->buffer = buffer;
56 }
57
58 EINTERN E_Comp_Wl_Buffer *
59 e_comp_wl_buffer_get(struct ds_buffer *ds_buffer)
60 {
61    E_Buffer *buffer;
62
63    buffer = _e_buffer_from_buffer(ds_buffer);
64    if (buffer)
65      goto done;
66
67    buffer = _e_buffer_create_with_ds_buffer(ds_buffer);
68    if (!buffer)
69      {
70         ERR("Failed to create E_Comp_Wl_Buffer");
71         return NULL;
72      }
73
74 done:
75    _e_buffer_transform_update(buffer);
76
77    return &buffer->base;
78 }
79
80 EINTERN E_Comp_Wl_Buffer *
81 e_comp_wl_buffer_create_with_tbm_surface(tbm_surface_h tbm_surface)
82 {
83    E_Buffer *buffer;
84
85    EINA_SAFETY_ON_NULL_RETURN_VAL(tbm_surface, NULL);
86
87    buffer = _e_buffer_create_with_tbm_surface(tbm_surface);
88    if (!buffer)
89      return NULL;
90
91    DBG("Create Buffer(%p) with tbm_surface(%p)", buffer, tbm_surface);
92
93    return &buffer->base;
94 }
95
96 EINTERN void
97 e_comp_wl_buffer_destroy(E_Comp_Wl_Buffer *comp_buffer)
98 {
99    E_Buffer *buffer;
100
101    EINA_SAFETY_ON_NULL_RETURN(comp_buffer);
102
103    buffer = _e_buffer_from_base(comp_buffer);
104    EINA_SAFETY_ON_NULL_RETURN(buffer);
105
106    if (buffer->ds_buffer)
107      {
108         ERR("Cannot destroy the buffer(%p) associated with ds_buffer", buffer);
109         return;
110      }
111
112    _e_buffer_tbm_surface_destroy(buffer);
113 }
114
115 EINTERN void *
116 e_comp_wl_buffer_single_pixel_buffer_data_get(E_Comp_Wl_Buffer *comp_buffer)
117 {
118    E_Buffer *buffer;
119    uint32_t format;
120    size_t stride;
121    void *data;
122
123    EINA_SAFETY_ON_NULL_RETURN_VAL(comp_buffer, NULL);
124    EINA_SAFETY_ON_FALSE_RETURN_VAL(comp_buffer->type == E_COMP_WL_BUFFER_TYPE_SINGLE_PIXEL, NULL);
125
126    buffer = _e_buffer_from_base(comp_buffer);
127    EINA_SAFETY_ON_NULL_RETURN_VAL(buffer, NULL);
128
129    if (!ds_buffer_begin_data_ptr_access(buffer->ds_buffer,
130                                         DS_BUFFER_DATA_PTR_ACCESS_READ,
131                                         &data, &format, &stride))
132      {
133         ERR("Could not access data of buffer(%p)", buffer);
134         return NULL;
135      }
136
137    ds_buffer_end_data_ptr_access(buffer->ds_buffer);
138
139    return data;
140 }
141
142 static void
143 _e_comp_wl_buffer_ref(E_Comp_Wl_Buffer *base)
144 {
145    E_Buffer *buffer;
146
147    base->busy++;
148    if (base->busy == 1)
149      {
150         buffer = _e_buffer_from_base(base);
151         if (buffer && buffer->lock)
152           buffer->lock(buffer);
153      }
154 }
155
156 static void
157 _e_comp_wl_buffer_release(E_Comp_Wl_Buffer *base)
158 {
159    E_Buffer *buffer;
160
161    if (base->buffer_release)
162      {
163         e_explicit_sync_buffer_release_destroy(base->buffer_release);
164         base->buffer_release = NULL;
165      }
166
167    buffer = _e_buffer_from_base(base);
168    if (buffer)
169      buffer->release(buffer);
170 }
171
172 static void
173 _e_comp_wl_buffer_unref(E_Comp_Wl_Buffer *base)
174 {
175    base->busy--;
176    if (base->busy != 0)
177      return;
178
179    _e_comp_wl_buffer_release(base);
180 }
181
182 static void
183 _e_comp_wl_buffer_reference_cb_destroy(struct wl_listener *listener, void *data)
184 {
185    E_Comp_Wl_Buffer_Ref *ref;
186
187    ref = container_of(listener, E_Comp_Wl_Buffer_Ref, destroy_listener);
188    wl_list_remove(&ref->destroy_listener.link);
189    ref->buffer = NULL;
190 }
191
192 static Eina_Bool
193 _e_comp_wl_buffer_tbm_type_get(E_Comp_Wl_Buffer *base, struct ds_buffer *ds_buffer)
194 {
195    tbm_surface_h tsurface;
196
197    tsurface = e_tbm_gbm_server_tbm_surface_get_from_buffer(ds_buffer);
198
199    if (!tsurface)
200      tsurface = e_linux_dmabuf_tbm_surface_get_from_buffer(ds_buffer);
201
202    if (!tsurface)
203      return EINA_FALSE;
204
205    base->type = E_COMP_WL_BUFFER_TYPE_TBM;
206    base->format = tbm_surface_get_format(tsurface);
207    base->tbm_surface = tsurface;
208
209    return EINA_TRUE;
210 }
211
212 static void
213 _e_comp_wl_buffer_init(E_Comp_Wl_Buffer *base, int32_t width, int32_t height)
214 {
215    base->w = width;
216    base->h = height;
217    wl_signal_init(&base->destroy_signal);
218    wl_list_init(&base->destroy_listener.link);
219 }
220
221 static Eina_Bool
222 _e_comp_wl_buffer_init_with_ds_buffer(E_Comp_Wl_Buffer *base, struct ds_buffer *ds_buffer)
223 {
224    struct wl_shm_buffer *shmbuff;
225    struct wl_resource *resource;
226    int32_t width, height;
227
228    ds_buffer_get_size(ds_buffer, &width, &height);
229    _e_comp_wl_buffer_init(base, width, height);
230
231    resource = ds_buffer_get_resource(ds_buffer);
232    if (!resource)
233      return EINA_FALSE;
234
235    shmbuff = wl_shm_buffer_get(resource);
236    if (shmbuff)
237      {
238         base->type = E_COMP_WL_BUFFER_TYPE_SHM;
239         base->format = wl_shm_buffer_get_format(shmbuff);
240         base->shm_buffer = shmbuff;
241      }
242    else if (ds_single_pixel_buffer_v1_from_buffer(ds_buffer))
243      {
244         base->type = E_COMP_WL_BUFFER_TYPE_SINGLE_PIXEL;
245         base->format = WL_SHM_FORMAT_ARGB8888;
246      }
247    else if (!_e_comp_wl_buffer_tbm_type_get(base, ds_buffer))
248      {
249         ERR("Invalid resource:%u", wl_resource_get_id(resource));
250         return EINA_FALSE;
251      }
252
253    base->resource = resource;
254
255    base->destroy_listener.notify = _e_buffer_cb_resource_destroy;
256    wl_resource_add_destroy_listener(resource, &base->destroy_listener);
257
258    return EINA_TRUE;
259 }
260
261 static void
262 _e_comp_wl_buffer_finish(E_Comp_Wl_Buffer *base)
263 {
264    wl_signal_emit(&base->destroy_signal, base);
265
266    if (base->buffer_release)
267      e_explicit_sync_buffer_release_destroy(base->buffer_release);
268
269    wl_list_remove(&base->destroy_listener.link);
270 }
271
272 static void
273 _e_buffer_ds_buffer_lock(E_Buffer *buffer)
274 {
275    ds_buffer_lock(buffer->ds_buffer);
276 }
277
278 static void
279 _e_buffer_ds_buffer_unlock(E_Buffer *buffer)
280 {
281    ds_buffer_unlock(buffer->ds_buffer);
282 }
283
284 static E_Buffer *
285 _e_buffer_create_with_ds_buffer(struct ds_buffer *ds_buffer)
286 {
287    E_Buffer *buffer;
288
289    buffer = E_NEW(E_Buffer, 1);
290    if (!buffer)
291      return NULL;
292
293    buffer->ds_buffer = ds_buffer;
294    buffer->lock = _e_buffer_ds_buffer_lock;
295    buffer->release = _e_buffer_ds_buffer_unlock;
296
297    if (!_e_comp_wl_buffer_init_with_ds_buffer(&buffer->base, ds_buffer))
298      {
299         free(buffer);
300         return NULL;
301      }
302
303    DBG("Create Buffer(%p) with ds_buffer(%p)", buffer, ds_buffer);
304
305    return buffer;
306 }
307
308 static void
309 _e_buffer_destroy(E_Buffer *buffer)
310 {
311    DBG("Destroy Buffer(%p)", buffer);
312
313    _e_comp_wl_buffer_finish(&buffer->base);
314    free(buffer);
315 }
316
317 static E_Buffer *
318 _e_buffer_from_base(E_Comp_Wl_Buffer *base)
319 {
320    E_Buffer *buffer;
321
322    if (base->destroy_listener.notify == _e_buffer_cb_resource_destroy)
323      return wl_container_of(base, buffer, base);
324    return NULL;
325 }
326
327 static void
328 _e_buffer_cb_resource_destroy(struct wl_listener *listener, void *data)
329 {
330    E_Buffer *buffer;
331
332    buffer = wl_container_of(listener, buffer, base.destroy_listener);
333
334    if (buffer->base.busy > 0)
335      ds_buffer_unlock(buffer->ds_buffer);
336
337    _e_buffer_destroy(buffer);
338 }
339
340 static E_Buffer *
341 _e_buffer_from_buffer(struct ds_buffer *ds_buffer)
342 {
343    E_Buffer *buffer;
344    struct wl_resource *resource;
345    struct wl_listener *listener;
346
347    resource = ds_buffer_get_resource(ds_buffer);
348    if (!resource)
349      return NULL;
350
351    listener = wl_resource_get_destroy_listener(resource, _e_buffer_cb_resource_destroy);
352    if (listener)
353      return wl_container_of(listener, buffer, base.destroy_listener);
354    return NULL;
355 }
356
357 static void
358 _e_buffer_transform_update(E_Buffer *buffer)
359 {
360    if (buffer->base.tbm_surface)
361      buffer->base.transform = wayland_tbm_server_buffer_get_buffer_transform(NULL, buffer->base.resource);
362 }
363
364 static void
365 _e_buffer_tbm_surface_destroy(E_Buffer *buffer)
366 {
367    tbm_surface_internal_unref(buffer->base.tbm_surface);
368    _e_buffer_destroy(buffer);
369 }
370
371 static void
372 _e_comp_wl_buffer_init_with_tbm_surface(E_Comp_Wl_Buffer *base, tbm_surface_h tbm_surface)
373 {
374    _e_comp_wl_buffer_init(base,
375                           tbm_surface_get_width(tbm_surface),
376                           tbm_surface_get_height(tbm_surface));
377
378    base->type = E_COMP_WL_BUFFER_TYPE_TBM;
379    base->tbm_surface = tbm_surface;
380    tbm_surface_internal_ref(tbm_surface);
381
382    // This is NOT to add a destroy listener, but to idendify the E_Buffer from
383    // E_Comp_Wl_Buffer.
384    base->destroy_listener.notify = _e_buffer_cb_resource_destroy;
385 }
386
387 static E_Buffer *
388 _e_buffer_create_with_tbm_surface(tbm_surface_h tbm_surface)
389 {
390    E_Buffer *buffer;
391
392    buffer = E_NEW(E_Buffer, 1);
393    if (!buffer)
394      return NULL;
395
396    buffer->release = _e_buffer_tbm_surface_destroy;
397
398    _e_comp_wl_buffer_init_with_tbm_surface(&buffer->base, tbm_surface);
399
400    return buffer;
401 }