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