Move un-namespaced container_of into private header
[profile/ivi/wayland.git] / src / wayland-shm.c
1 /*
2  * Copyright © 2008 Kristian Høgsberg
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  *
22  * Authors:
23  *    Kristian Høgsberg <krh@bitplanet.net>
24  *    Benjamin Franzke <benjaminfranzke@googlemail.com>
25  *
26  */
27
28 #define _GNU_SOURCE
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/mman.h>
34 #include <unistd.h>
35
36 #include "wayland-private.h"
37 #include "wayland-server.h"
38
39 struct wl_shm_pool {
40         struct wl_resource resource;
41         int refcount;
42         char *data;
43         int size;
44 };
45
46 struct wl_shm_buffer {
47         struct wl_buffer buffer;
48         int32_t stride;
49         uint32_t format;
50         int offset;
51         struct wl_shm_pool *pool;
52 };
53
54 static void
55 shm_pool_unref(struct wl_shm_pool *pool)
56 {
57         pool->refcount--;
58         if (pool->refcount)
59                 return;
60
61         munmap(pool->data, pool->size);
62         free(pool);
63 }
64
65 static void
66 destroy_buffer(struct wl_resource *resource)
67 {
68         struct wl_shm_buffer *buffer =
69                 container_of(resource, struct wl_shm_buffer, buffer.resource);
70
71         if (buffer->pool)
72                 shm_pool_unref(buffer->pool);
73         free(buffer);
74 }
75
76 static void
77 shm_buffer_destroy(struct wl_client *client, struct wl_resource *resource)
78 {
79         wl_resource_destroy(resource);
80 }
81
82 static const struct wl_buffer_interface shm_buffer_interface = {
83         shm_buffer_destroy
84 };
85
86 static void
87 shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource,
88                        uint32_t id, int32_t offset,
89                        int32_t width, int32_t height,
90                        int32_t stride, uint32_t format)
91 {
92         struct wl_shm_pool *pool = resource->data;
93         struct wl_shm_buffer *buffer;
94
95         switch (format) {
96         case WL_SHM_FORMAT_ARGB8888:
97         case WL_SHM_FORMAT_XRGB8888:
98                 break;
99         default:
100                 wl_resource_post_error(resource,
101                                        WL_SHM_ERROR_INVALID_FORMAT,
102                                        "invalid format");
103                 return;
104         }
105
106         if (offset < 0 || width <= 0 || height <= 0 || stride < width ||
107             INT32_MAX / stride <= height ||
108             offset > pool->size - stride * height) {
109                 wl_resource_post_error(resource,
110                                        WL_SHM_ERROR_INVALID_STRIDE,
111                                        "invalid width, height or stride (%dx%d, %u)",
112                                        width, height, stride);
113                 return;
114         }
115
116         buffer = malloc(sizeof *buffer);
117         if (buffer == NULL) {
118                 wl_resource_post_no_memory(resource);
119                 return;
120         }
121
122         buffer->buffer.width = width;
123         buffer->buffer.height = height;
124         buffer->buffer.busy_count = 0;
125         buffer->format = format;
126         buffer->stride = stride;
127         buffer->offset = offset;
128         buffer->pool = pool;
129         pool->refcount++;
130
131         buffer->buffer.resource.object.id = id;
132         buffer->buffer.resource.object.interface = &wl_buffer_interface;
133         buffer->buffer.resource.object.implementation = (void (**)(void))
134                 &shm_buffer_interface;
135
136         buffer->buffer.resource.data = buffer;
137         buffer->buffer.resource.client = resource->client;
138         buffer->buffer.resource.destroy = destroy_buffer;
139
140         wl_client_add_resource(client, &buffer->buffer.resource);
141 }
142
143 static void
144 destroy_pool(struct wl_resource *resource)
145 {
146         struct wl_shm_pool *pool = resource->data;
147
148         shm_pool_unref(pool);
149 }
150
151 static void
152 shm_pool_destroy(struct wl_client *client, struct wl_resource *resource)
153 {
154         wl_resource_destroy(resource);
155 }
156
157 static void
158 shm_pool_resize(struct wl_client *client, struct wl_resource *resource,
159                 int32_t size)
160 {
161         struct wl_shm_pool *pool = resource->data;
162         void *data;
163
164         data = mremap(pool->data, pool->size, size, MREMAP_MAYMOVE);
165
166         if (data == MAP_FAILED) {
167                 wl_resource_post_error(resource,
168                                        WL_SHM_ERROR_INVALID_FD,
169                                        "failed mremap");
170                 return;
171         }
172
173         pool->data = data;
174         pool->size = size;
175 }
176
177 struct wl_shm_pool_interface shm_pool_interface = {
178         shm_pool_create_buffer,
179         shm_pool_destroy,
180         shm_pool_resize
181 };
182
183 static void
184 shm_create_pool(struct wl_client *client, struct wl_resource *resource,
185                 uint32_t id, int fd, int32_t size)
186 {
187         struct wl_shm_pool *pool;
188
189         pool = malloc(sizeof *pool);
190         if (pool == NULL) {
191                 wl_resource_post_no_memory(resource);
192                 goto err_close;
193         }
194
195         if (size <= 0) {
196                 wl_resource_post_error(resource,
197                                        WL_SHM_ERROR_INVALID_STRIDE,
198                                        "invalid size (%d)", size);
199                 goto err_free;
200         }
201
202         pool->refcount = 1;
203         pool->size = size;
204         pool->data = mmap(NULL, size,
205                           PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
206         if (pool->data == MAP_FAILED) {
207                 wl_resource_post_error(resource,
208                                        WL_SHM_ERROR_INVALID_FD,
209                                        "failed mmap fd %d", fd);
210                 goto err_free;
211         }
212         close(fd);
213
214         pool->resource.object.id = id;
215         pool->resource.object.interface = &wl_shm_pool_interface;
216         pool->resource.object.implementation =
217                 (void (**)(void)) &shm_pool_interface;
218
219         pool->resource.data = pool;
220         pool->resource.client = client;
221         pool->resource.destroy = destroy_pool;
222
223         wl_client_add_resource(client, &pool->resource);
224
225         return;
226
227 err_close:
228         close(fd);
229 err_free:
230         free(pool);
231 }
232
233 static const struct wl_shm_interface shm_interface = {
234         shm_create_pool
235 };
236
237 static void
238 bind_shm(struct wl_client *client,
239          void *data, uint32_t version, uint32_t id)
240 {
241         struct wl_resource *resource;
242
243         resource = wl_client_add_object(client, &wl_shm_interface,
244                                         &shm_interface, id, data);
245
246         wl_shm_send_format(resource, WL_SHM_FORMAT_ARGB8888);
247         wl_shm_send_format(resource, WL_SHM_FORMAT_XRGB8888);
248 }
249
250 WL_EXPORT int
251 wl_display_init_shm(struct wl_display *display)
252 {
253         if (!wl_display_add_global(display, &wl_shm_interface, NULL, bind_shm))
254                 return -1;
255
256         return 0;
257 }
258
259 WL_EXPORT struct wl_buffer *
260 wl_shm_buffer_create(struct wl_client *client,
261                      uint32_t id, int32_t width, int32_t height,
262                      int32_t stride, uint32_t format)
263 {
264         struct wl_shm_buffer *buffer;
265                              
266         switch (format) {
267         case WL_SHM_FORMAT_ARGB8888:
268         case WL_SHM_FORMAT_XRGB8888:
269                 break;
270         default:
271                 return NULL;
272         }
273
274         buffer = malloc(sizeof *buffer + stride * height);
275         if (buffer == NULL)
276                 return NULL;
277
278         buffer->buffer.width = width;
279         buffer->buffer.height = height;
280         buffer->buffer.busy_count = 0;
281         buffer->format = format;
282         buffer->stride = stride;
283         buffer->offset = 0;
284         buffer->pool = NULL;
285
286         buffer->buffer.resource.object.id = id;
287         buffer->buffer.resource.object.interface = &wl_buffer_interface;
288         buffer->buffer.resource.object.implementation = (void (**)(void))
289                 &shm_buffer_interface;
290
291         buffer->buffer.resource.data = buffer;
292         buffer->buffer.resource.client = client;
293         buffer->buffer.resource.destroy = destroy_buffer;
294
295         wl_client_add_resource(client, &buffer->buffer.resource);
296
297         return &buffer->buffer;
298 }
299
300 WL_EXPORT int
301 wl_buffer_is_shm(struct wl_buffer *buffer)
302 {
303         return buffer->resource.object.implementation == 
304                 (void (**)(void)) &shm_buffer_interface;
305 }
306
307 WL_EXPORT int32_t
308 wl_shm_buffer_get_stride(struct wl_buffer *buffer_base)
309 {
310         struct wl_shm_buffer *buffer = (struct wl_shm_buffer *) buffer_base;
311
312         if (!wl_buffer_is_shm(buffer_base))
313                 return 0;
314
315         return buffer->stride;
316 }
317
318 WL_EXPORT void *
319 wl_shm_buffer_get_data(struct wl_buffer *buffer_base)
320 {
321         struct wl_shm_buffer *buffer = (struct wl_shm_buffer *) buffer_base;
322
323         if (!wl_buffer_is_shm(buffer_base))
324                 return NULL;
325
326         if (buffer->pool)
327                 return buffer->pool->data + buffer->offset;
328         else
329                 return buffer + 1;
330 }
331
332 WL_EXPORT uint32_t
333 wl_shm_buffer_get_format(struct wl_buffer *buffer_base)
334 {
335         struct wl_shm_buffer *buffer = (struct wl_shm_buffer *) buffer_base;
336
337         return buffer->format;
338 }
339
340 WL_EXPORT int32_t
341 wl_shm_buffer_get_width(struct wl_buffer *buffer_base)
342 {
343         struct wl_shm_buffer *buffer = (struct wl_shm_buffer *) buffer_base;
344
345         return buffer->buffer.width;
346 }
347
348 WL_EXPORT int32_t
349 wl_shm_buffer_get_height(struct wl_buffer *buffer_base)
350 {
351         struct wl_shm_buffer *buffer = (struct wl_shm_buffer *) buffer_base;
352
353         return buffer->buffer.height;
354 }