Add gbm_server for supporting gbm_bo buffer
[platform/core/uifw/libds-tizen.git] / src / gbm_server / gbm_server.c
1 #include <assert.h>
2 #include <stdbool.h>
3 #include <stdlib.h>
4
5 #include <gbm.h>
6 #include <libds/log.h>
7 #include "shared/pixel_format.h"
8 #include "gbm_server.h"
9
10 static const struct ds_buffer_resource_interface gbm_buffer_resource_iface;
11 static const struct ds_buffer_interface gbm_client_buffer_iface;
12
13 static struct ds_gbm_server *gbm_server;
14
15 WL_EXPORT struct ds_gbm_server *
16 ds_gbm_server_create(int fd)
17 {
18     struct ds_gbm_server *gbm;
19
20     if (gbm_server) {
21         ds_inf("gbm server already created");
22         return gbm_server;
23     }
24
25     gbm = calloc(1, sizeof *gbm);
26     if (!gbm)
27         return NULL;
28
29     gbm->gbm_device = gbm_create_device(fd);
30     if (!gbm->gbm_device) {
31         free(gbm);
32         return NULL;
33     }
34
35     ds_buffer_register_resource_interface(&gbm_buffer_resource_iface);
36
37     gbm_server = gbm;
38
39     return gbm;
40 }
41
42 WL_EXPORT void
43 ds_gbm_server_destroy(struct ds_gbm_server *gbm)
44 {
45     gbm_device_destroy(gbm->gbm_device);
46
47     free(gbm);
48
49     gbm_server = NULL;
50 }
51
52 WL_EXPORT struct ds_gbm_client_buffer *
53 ds_gbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer)
54 {
55     if (ds_buffer->iface != &gbm_client_buffer_iface)
56         return NULL;
57     return (struct ds_gbm_client_buffer *)ds_buffer;
58 }
59
60 WL_EXPORT struct gbm_bo *
61 ds_gbm_client_buffer_get_gbm_bo(struct ds_gbm_client_buffer *buffer)
62 {
63     if (buffer->base.iface != &gbm_client_buffer_iface)
64         return NULL;
65     return buffer->gbm_bo;
66 }
67
68 static void
69 gbm_client_buffer_handle_release(struct wl_listener *listener, void *data)
70 {
71     struct ds_gbm_client_buffer *buffer;
72
73     buffer = wl_container_of(listener, buffer, buffer_release);
74     if (buffer->resource)
75         wl_buffer_send_release(buffer->resource);
76 }
77
78 static void
79 gbm_client_buffer_handle_resource_destroy(struct wl_listener *listener,
80         void *data)
81 {
82     struct ds_gbm_client_buffer *buffer;
83
84     buffer = wl_container_of(listener, buffer, resource_destroy);
85
86     buffer->resource = NULL;
87
88     wl_list_remove(&buffer->resource_destroy.link);
89     wl_list_init(&buffer->resource_destroy.link);
90
91     ds_buffer_drop(&buffer->base);
92 }
93
94 static struct ds_gbm_client_buffer *
95 gbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer)
96 {
97     assert(ds_buffer->iface == &gbm_client_buffer_iface);
98     return (struct ds_gbm_client_buffer *)ds_buffer;
99 }
100
101 static void
102 gbm_client_buffer_iface_destroy(struct ds_buffer *ds_buffer)
103 {
104     struct ds_gbm_client_buffer *buffer;
105
106     buffer = gbm_client_buffer_from_buffer(ds_buffer);
107
108     ds_dbg("Destroy gbm client buffer(%p)", buffer);
109
110     gbm_bo_destroy(buffer->gbm_bo);
111
112     wl_list_remove(&buffer->resource_destroy.link);
113     wl_list_remove(&buffer->buffer_release.link);
114     free(buffer);
115 }
116
117 static bool
118 gbm_client_buffer_iface_begin_data_ptr_access(struct ds_buffer *ds_buffer,
119         enum ds_buffer_data_ptr_access_flag flags, void **data,
120         uint32_t *format, size_t *stride)
121 {
122     struct ds_gbm_client_buffer *buffer;
123     uint32_t gbm_flags = 0, map_stride;
124     void *map, *map_data;
125
126     buffer = gbm_client_buffer_from_buffer(ds_buffer);
127
128     if (flags & DS_BUFFER_DATA_PTR_ACCESS_READ)
129         gbm_flags |= GBM_BO_TRANSFER_READ;
130
131     if (flags & DS_BUFFER_DATA_PTR_ACCESS_WRITE)
132         gbm_flags |= GBM_BO_TRANSFER_WRITE;
133
134     map = gbm_bo_map(buffer->gbm_bo, 0, 0, ds_buffer->width, ds_buffer->height,
135                      gbm_flags, &map_stride, &map_data);
136     if (!map) {
137         ds_err("Failed gbm_surface_map()");
138         return false;
139     }
140
141     buffer->map_data = map_data;
142
143     *format = convert_tbm_format_to_drm(buffer->format);
144     *stride = map_stride;
145     *data = map;
146
147     return true;
148 }
149
150 static void
151 gbm_client_buffer_iface_end_ptr_access(struct ds_buffer *ds_buffer)
152 {
153     struct ds_gbm_client_buffer *buffer;
154
155     buffer = gbm_client_buffer_from_buffer(ds_buffer);
156
157     gbm_bo_unmap(buffer->gbm_bo, buffer->map_data);
158
159     buffer->map_data = NULL;
160 }
161
162 static struct wl_resource *
163 gbm_client_buffer_iface_get_resource(struct ds_buffer *ds_buffer)
164 {
165     struct ds_gbm_client_buffer *buffer;
166
167     buffer = gbm_client_buffer_from_buffer(ds_buffer);
168
169     return buffer->resource;
170 }
171
172 static const struct ds_buffer_interface gbm_client_buffer_iface = {
173     .destroy = gbm_client_buffer_iface_destroy,
174     .begin_data_ptr_access = gbm_client_buffer_iface_begin_data_ptr_access,
175     .end_data_ptr_access = gbm_client_buffer_iface_end_ptr_access,
176     .get_resource = gbm_client_buffer_iface_get_resource,
177 };
178
179 static struct ds_gbm_client_buffer *
180 gbm_client_buffer_create(struct wl_resource *resource)
181 {
182     struct ds_gbm_client_buffer *buffer;
183     struct gbm_bo *gbm_bo;
184     int32_t width, height;
185
186     gbm_bo = gbm_bo_import(gbm_server->gbm_device, GBM_BO_IMPORT_WL_BUFFER,
187                            resource, GBM_BO_USE_RENDERING);
188     if (!gbm_bo) return NULL;
189
190     width = gbm_bo_get_width(gbm_bo);
191     height = gbm_bo_get_height(gbm_bo);
192
193     buffer = calloc(1, sizeof *buffer);
194     if (!buffer) {
195         gbm_bo_destroy(gbm_bo);
196         return NULL;
197     }
198
199     ds_buffer_init(&buffer->base, &gbm_client_buffer_iface, width, height);
200
201     buffer->resource = resource;
202     buffer->gbm_bo = gbm_bo;
203     buffer->format = gbm_bo_get_format(gbm_bo);
204     buffer->stride = gbm_bo_get_stride(gbm_bo);
205
206     buffer->buffer_release.notify = gbm_client_buffer_handle_release;
207     ds_buffer_add_release_listener(&buffer->base, &buffer->buffer_release);
208
209     buffer->resource_destroy.notify =
210         gbm_client_buffer_handle_resource_destroy;
211     wl_resource_add_destroy_listener(resource, &buffer->resource_destroy);
212
213     ds_dbg("gbm client buffer(%p) created", buffer);
214
215     return buffer;
216 }
217
218 static struct ds_gbm_client_buffer *
219 gbm_client_buffer_get_or_create(struct wl_resource *resource)
220 {
221     struct ds_gbm_client_buffer *buffer;
222     struct wl_listener *resource_destroy_listener;
223
224     resource_destroy_listener = wl_resource_get_destroy_listener(resource,
225             gbm_client_buffer_handle_resource_destroy);;
226     if (resource_destroy_listener) {
227         buffer = wl_container_of(resource_destroy_listener,
228                 buffer, resource_destroy);
229         return buffer;
230     }
231
232     return gbm_client_buffer_create(resource);
233 }
234
235 static bool
236 gbm_buffer_resource_iface_is_instance(struct wl_resource *resource)
237 {
238     if (!gbm_server) return false;
239
240     if (!gbm_client_buffer_get_or_create(resource))
241         return false;
242
243     return true;
244 }
245
246 static struct ds_buffer *
247 gbm_buffer_resource_iface_from_resource(struct wl_resource *resource)
248 {
249     struct ds_gbm_client_buffer *buffer;
250
251     buffer = gbm_client_buffer_get_or_create(resource);
252     if (!buffer) {
253         ds_err("Could not get or create ds_gbm_client_buffer");
254         return NULL;
255     }
256
257     return &buffer->base;
258 }
259
260 static const struct ds_buffer_resource_interface gbm_buffer_resource_iface = {
261     .name = "gbm",
262     .is_instance = gbm_buffer_resource_iface_is_instance,
263     .from_resource = gbm_buffer_resource_iface_from_resource,
264 };