buffer: add addon set
[platform/core/uifw/libds.git] / src / buffer.c
1 #include <stdlib.h>
2
3 #include "libds/log.h"
4 #include "libds/interfaces/buffer.h"
5
6 #include "util.h"
7 #include "buffer.h"
8 #include "client_buffer.h"
9
10 static struct wl_array buffer_resource_interfaces = {0};
11
12 static void buffer_consider_destroy(struct ds_buffer *buffer);
13 static bool ds_resource_is_buffer(struct wl_resource *resource);
14 static const struct ds_buffer_resource_interface *
15 get_buffer_resource_iface(struct wl_resource *resource);
16
17 WL_EXPORT void
18 ds_buffer_init(struct ds_buffer *buffer,
19         const struct ds_buffer_interface *iface, int width, int height)
20 {
21     buffer->iface = iface;
22     buffer->width = width;
23     buffer->height = height;
24
25     wl_signal_init(&buffer->events.destroy);
26     wl_signal_init(&buffer->events.release);
27
28     ds_addon_set_init(&buffer->addons);
29 }
30
31 WL_EXPORT struct ds_buffer *
32 ds_buffer_from_resource(struct wl_resource *resource)
33 {
34     struct ds_buffer *buffer;
35     const struct ds_buffer_resource_interface *iface;
36
37     DS_ASSERT(resource && ds_resource_is_buffer(resource));
38
39     if (wl_shm_buffer_get(resource) != NULL) {
40         struct ds_shm_client_buffer *shm_client_buffer =
41             ds_shm_client_buffer_get_or_create(resource);
42         if (!shm_client_buffer) {
43             ds_err("Failed to create shm client buffer");
44             return NULL;
45         }
46
47         buffer = ds_buffer_lock(&shm_client_buffer->base);
48     }
49     else {
50         iface = get_buffer_resource_iface(resource);
51         if (!iface) {
52             ds_err("Unknown buffer type");
53             return NULL;
54         }
55
56         buffer = iface->from_resource(resource);
57         if (!buffer) {
58             ds_err("Failed to create %s buffer", iface->name);
59             return NULL;
60         }
61
62         buffer = ds_buffer_lock(buffer);
63     }
64
65     return buffer;
66 }
67
68 WL_EXPORT void
69 ds_buffer_drop(struct ds_buffer *buffer)
70 {
71     DS_ASSERT(!buffer->dropped);
72     buffer->dropped = true;
73     ds_dbg("Buffer(%p) dropped: n_locks(%zu)", buffer, buffer->n_locks);
74     buffer_consider_destroy(buffer);
75 }
76
77 WL_EXPORT struct ds_buffer *
78 ds_buffer_lock(struct ds_buffer *buffer)
79 {
80     buffer->n_locks++;
81     ds_dbg("Buffer(%p) n_locks(%zu)", buffer, buffer->n_locks);
82     return buffer;
83 }
84
85 WL_EXPORT void
86 ds_buffer_unlock(struct ds_buffer *buffer)
87 {
88     DS_ASSERT(buffer->n_locks > 0);
89     buffer->n_locks--;
90     ds_dbg("Buffer(%p) n_locks(%zu)", buffer, buffer->n_locks);
91
92     if (buffer->n_locks == 0)
93         wl_signal_emit_mutable(&buffer->events.release, NULL);
94
95     buffer_consider_destroy(buffer);
96 }
97
98 WL_EXPORT bool
99 ds_buffer_begin_data_ptr_access(struct ds_buffer *buffer, uint32_t flags,
100         void **data, uint32_t *format, size_t *stride)
101 {
102     DS_ASSERT(!buffer->accessing_data_ptr);
103     if (!buffer->iface->begin_data_ptr_access)
104         return false;
105     if (!buffer->iface->begin_data_ptr_access(buffer,
106                 flags, data, format, stride))
107         return false;
108     buffer->accessing_data_ptr = true;
109     return true;
110 }
111
112 WL_EXPORT void
113 ds_buffer_end_data_ptr_access(struct ds_buffer *buffer)
114 {
115     DS_ASSERT(buffer->accessing_data_ptr);
116     buffer->iface->end_data_ptr_access(buffer);
117     buffer->accessing_data_ptr = false;
118 }
119
120 WL_EXPORT void
121 ds_buffer_add_destroy_listener(struct ds_buffer *buffer,
122         struct wl_listener *listener)
123 {
124     wl_signal_add(&buffer->events.destroy, listener);
125 }
126
127 WL_EXPORT void
128 ds_buffer_add_release_listener(struct ds_buffer *buffer,
129         struct wl_listener *listener)
130 {
131     wl_signal_add(&buffer->events.release, listener);
132 }
133
134 WL_EXPORT bool
135 ds_buffer_get_shm(struct ds_buffer *buffer, struct ds_shm_attributes *attribs)
136 {
137     if (!buffer->iface->get_shm)
138         return false;
139
140     return buffer->iface->get_shm(buffer, attribs);
141 }
142
143 WL_EXPORT void
144 ds_buffer_get_size(struct ds_buffer *buffer, int *out_width, int *out_height)
145 {
146     if (out_width)
147         *out_width = buffer->width;
148     if (out_height)
149         *out_height = buffer->height;
150 }
151
152 WL_EXPORT void
153 ds_buffer_register_resource_interface(
154         const struct ds_buffer_resource_interface *iface)
155 {
156     const struct ds_buffer_resource_interface **iface_ptr;
157
158     DS_ASSERT(iface);
159     DS_ASSERT(iface->is_instance);
160     DS_ASSERT(iface->from_resource);
161
162     wl_array_for_each(iface_ptr, &buffer_resource_interfaces) {
163         if (*iface_ptr == iface) {
164             ds_dbg("ds_buffer_resource_interface %s has already "
165                     "been registered", iface->name);
166             return;
167         }
168     }
169
170     iface_ptr = wl_array_add(&buffer_resource_interfaces, sizeof(iface));
171     if (!iface_ptr) {
172         ds_err("Could not allocate memory");
173         return;
174     }
175
176     *iface_ptr = iface;
177 }
178
179 WL_EXPORT struct wl_resource *
180 ds_buffer_get_resource(struct ds_buffer *buffer)
181 {
182     if (!buffer->iface->get_resource)
183         return NULL;
184
185     return buffer->iface->get_resource(buffer);
186 }
187
188 static void
189 buffer_consider_destroy(struct ds_buffer *buffer)
190 {
191     if (!buffer->dropped || buffer->n_locks > 0)
192         return;
193
194     DS_ASSERT(!buffer->accessing_data_ptr);
195
196     ds_addon_set_finish(&buffer->addons);
197
198     wl_signal_emit_mutable(&buffer->events.destroy, NULL);
199     buffer->iface->destroy(buffer);
200 }
201
202 static bool
203 ds_resource_is_buffer(struct wl_resource *resource)
204 {
205     return strcmp(wl_resource_get_class(resource),
206             wl_buffer_interface.name) == 0;
207 }
208
209 static const struct ds_buffer_resource_interface *
210 get_buffer_resource_iface(struct wl_resource *resource)
211 {
212     struct ds_buffer_resource_interface **iface_ptr;
213
214     wl_array_for_each(iface_ptr, &buffer_resource_interfaces) {
215         if ((*iface_ptr)->is_instance(resource)) {
216             return *iface_ptr;
217         }
218     }
219
220     return NULL;
221 }