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