commit 3333dfd

Michael Forney  ·  2014-02-07 12:07:06 +0000 UTC
parent cae8594
shm: Use our own wl_shm implementation
2 files changed,  +213, -77
+213, -3
  1@@ -1,6 +1,10 @@
  2 /* swc: libswc/shm.c
  3  *
  4- * Copyright (c) 2013 Michael Forney
  5+ * Copyright (c) 2013, 2014 Michael Forney
  6+ *
  7+ * Based in part upon wayland-shm.c from wayland, which is:
  8+ *
  9+ *     Copyright © 2008 Kristian Høgsberg
 10  *
 11  * Permission is hereby granted, free of charge, to any person obtaining a copy
 12  * of this software and associated documentation files (the "Software"), to deal
 13@@ -23,13 +27,210 @@
 14 
 15 #include "shm.h"
 16 #include "internal.h"
 17+#include "util.h"
 18+#include "wayland_buffer.h"
 19 
 20-#include <stddef.h>
 21-#include <wld/wld.h>
 22+#include <errno.h>
 23+#include <stdlib.h>
 24+#include <sys/mman.h>
 25+#include <wayland-server.h>
 26 #include <wld/pixman.h>
 27+#include <wld/wld.h>
 28 
 29 struct swc_shm swc_shm;
 30 
 31+static struct
 32+{
 33+    struct wl_global * global;
 34+} shm;
 35+
 36+struct pool
 37+{
 38+    struct wl_resource * resource;
 39+    void * data;
 40+    uint32_t size;
 41+    unsigned references;
 42+};
 43+
 44+struct pool_reference
 45+{
 46+    struct wld_destructor destructor;
 47+    struct pool * pool;
 48+};
 49+
 50+static void unref_pool(struct wl_resource * resource)
 51+{
 52+    struct pool * pool = wl_resource_get_user_data(resource);
 53+
 54+    if (--pool->references > 0)
 55+        return;
 56+
 57+    munmap(pool->data, pool->size);
 58+    free(pool);
 59+}
 60+
 61+static void handle_buffer_destroy(struct wld_destructor * destructor)
 62+{
 63+    struct pool_reference * reference
 64+        = CONTAINER_OF(destructor, typeof(*reference), destructor);
 65+
 66+    unref_pool(reference->pool->resource);
 67+}
 68+
 69+static inline uint32_t format_shm_to_wld(uint32_t format)
 70+{
 71+    switch (format)
 72+    {
 73+        case WL_SHM_FORMAT_ARGB8888:
 74+            return WLD_FORMAT_ARGB8888;
 75+        case WL_SHM_FORMAT_XRGB8888:
 76+            return WLD_FORMAT_XRGB8888;
 77+        default:
 78+            return format;
 79+    }
 80+}
 81+
 82+static void create_buffer(struct wl_client * client,
 83+                          struct wl_resource * resource, uint32_t id,
 84+                          int32_t offset, int32_t width, int32_t height,
 85+                          int32_t stride, uint32_t format)
 86+{
 87+    struct pool * pool = wl_resource_get_user_data(resource);
 88+    struct pool_reference * reference;
 89+    struct wld_buffer * buffer;
 90+    struct wl_resource * buffer_resource;
 91+    union wld_object object;
 92+
 93+    if (offset > pool->size || offset < 0)
 94+    {
 95+        wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_STRIDE,
 96+                               "offset is too big or negative");
 97+        return;
 98+    }
 99+
100+    object.ptr = (void *)((uintptr_t) pool->data + offset);
101+    buffer = wld_import_buffer(swc.shm->context, WLD_OBJECT_DATA, object,
102+                               width, height, format_shm_to_wld(format),
103+                               stride);
104+
105+    if (!buffer)
106+        goto error0;
107+
108+    buffer_resource = swc_wayland_buffer_create_resource(client, id, buffer);
109+
110+    if (!buffer_resource)
111+        goto error1;
112+
113+    if (!(reference = malloc(sizeof *reference)))
114+        goto error2;
115+
116+    reference->pool = pool;
117+    reference->destructor.destroy = &handle_buffer_destroy;
118+    wld_buffer_add_destructor(buffer, &reference->destructor);
119+    ++pool->references;
120+
121+    return;
122+
123+  error2:
124+    wl_resource_destroy(buffer_resource);
125+  error1:
126+    wld_buffer_unreference(buffer);
127+  error0:
128+    wl_resource_post_no_memory(resource);
129+}
130+
131+static void destroy(struct wl_client * client, struct wl_resource * resource)
132+{
133+    wl_resource_destroy(resource);
134+}
135+
136+static void resize(struct wl_client * client, struct wl_resource * resource,
137+                   int32_t size)
138+{
139+    struct pool * pool = wl_resource_get_user_data(resource);
140+    void * data;
141+
142+    data = mremap(pool->data, pool->size, size, MREMAP_MAYMOVE);
143+
144+    if (data == MAP_FAILED)
145+    {
146+        wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FD,
147+                               "mremap failed: %s", strerror(errno));
148+        return;
149+    }
150+
151+    pool->data = data;
152+    pool->size = size;
153+}
154+
155+static struct wl_shm_pool_interface shm_pool_implementation = {
156+    .create_buffer = &create_buffer,
157+    .destroy = &destroy,
158+    .resize = &resize
159+};
160+
161+static void create_pool(struct wl_client * client,
162+                        struct wl_resource * resource, uint32_t id,
163+                        int32_t fd, int32_t size)
164+{
165+    struct pool * pool;
166+
167+    if (!(pool = malloc(sizeof *pool)))
168+    {
169+        wl_resource_post_no_memory(resource);
170+        return;
171+    }
172+
173+    pool->resource = wl_resource_create(client, &wl_shm_pool_interface,
174+                                        wl_resource_get_version(resource), id);
175+
176+    if (!pool->resource)
177+    {
178+        wl_resource_post_no_memory(resource);
179+        goto error0;
180+    }
181+
182+    wl_resource_set_implementation(pool->resource, &shm_pool_implementation,
183+                                   pool, &unref_pool);
184+    pool->data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
185+
186+    if (pool->data == MAP_FAILED)
187+    {
188+        wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FD,
189+                               "mmap failed: %s", strerror(errno));
190+        goto error1;
191+    }
192+
193+    pool->size = size;
194+    pool->references = 1;
195+
196+    return;
197+
198+  error1:
199+    wl_resource_destroy(pool->resource);
200+  error0:
201+    free(pool);
202+}
203+
204+static struct wl_shm_interface shm_implementation = {
205+    .create_pool = &create_pool
206+};
207+
208+static void bind_shm(struct wl_client * client, void * data, uint32_t version,
209+                     uint32_t id)
210+{
211+    struct wl_resource * resource;
212+
213+    if (version >= 1)
214+        version = 1;
215+
216+    resource = wl_resource_create(client, &wl_shm_interface, version, id);
217+    wl_resource_set_implementation(resource, &shm_implementation, NULL, NULL);
218+
219+    wl_shm_send_format(resource, WL_SHM_FORMAT_XRGB8888);
220+    wl_shm_send_format(resource, WL_SHM_FORMAT_ARGB8888);
221+}
222+
223 bool swc_shm_initialize()
224 {
225     if (!(swc.shm->context = wld_pixman_create_context()))
226@@ -38,8 +239,16 @@ bool swc_shm_initialize()
227     if (!(swc.shm->renderer = wld_create_renderer(swc.shm->context)))
228         goto error1;
229 
230+    shm.global = wl_global_create(swc.display, &wl_shm_interface, 1,
231+                                  NULL, &bind_shm);
232+
233+    if (!shm.global)
234+        goto error2;
235+
236     return true;
237 
238+  error2:
239+    wld_destroy_renderer(swc.shm->renderer);
240   error1:
241     wld_destroy_context(swc.shm->context);
242   error0:
243@@ -48,6 +257,7 @@ bool swc_shm_initialize()
244 
245 void swc_shm_finalize()
246 {
247+    wl_global_destroy(shm.global);
248     wld_destroy_renderer(swc.shm->renderer);
249     wld_destroy_context(swc.shm->context);
250 }
+0, -74
 1@@ -29,12 +29,6 @@
 2 #include <wld/wld.h>
 3 #include <wld/pixman.h>
 4 
 5-struct wayland_buffer
 6-{
 7-    struct wld_buffer * wld;
 8-    struct wl_listener destroy_listener;
 9-};
10-
11 static void destroy(struct wl_client * client, struct wl_resource * resource)
12 {
13     wl_resource_destroy(resource);
14@@ -44,30 +38,6 @@ static const struct wl_buffer_interface buffer_implementation = {
15     .destroy = &destroy
16 };
17 
18-/* NOTE: Needed because the implementation for SHM buffers comes from
19- *       libwayland-server. */
20-static void handle_buffer_destroy(struct wl_listener * listener, void * data)
21-{
22-    struct wayland_buffer * buffer
23-        = CONTAINER_OF(listener, typeof(*buffer), destroy_listener);
24-
25-    wld_buffer_unreference(buffer->wld);
26-    free(buffer);
27-}
28-
29-static inline uint32_t format_shm_to_wld(uint32_t format)
30-{
31-    switch (format)
32-    {
33-        case WL_SHM_FORMAT_ARGB8888:
34-            return WLD_FORMAT_ARGB8888;
35-        case WL_SHM_FORMAT_XRGB8888:
36-            return WLD_FORMAT_XRGB8888;
37-        default:
38-            return format;
39-    }
40-}
41-
42 struct wld_buffer * swc_wayland_buffer_get(struct wl_resource * resource)
43 {
44     if (wl_resource_instance_of(resource, &wl_buffer_interface,
45@@ -76,50 +46,6 @@ struct wld_buffer * swc_wayland_buffer_get(struct wl_resource * resource)
46         return wl_resource_get_user_data(resource);
47     }
48 
49-    struct wl_listener * listener;
50-    struct wayland_buffer * buffer;
51-
52-    listener = wl_resource_get_destroy_listener(resource,
53-                                                &handle_buffer_destroy);
54-
55-    if (listener)
56-    {
57-        buffer = CONTAINER_OF(listener, typeof(*buffer), destroy_listener);
58-
59-        return buffer->wld;
60-    }
61-
62-    if (!(buffer = malloc(sizeof *buffer)))
63-        goto error0;
64-
65-    struct wl_shm_buffer * shm_buffer;
66-
67-    if ((shm_buffer = wl_shm_buffer_get(resource)))
68-    {
69-        union wld_object object = {
70-            .ptr = wl_shm_buffer_get_data(shm_buffer)
71-        };
72-
73-        buffer->wld = wld_import_buffer
74-            (swc.shm->context, WLD_OBJECT_DATA, object,
75-             wl_shm_buffer_get_width(shm_buffer),
76-             wl_shm_buffer_get_height(shm_buffer),
77-             format_shm_to_wld(wl_shm_buffer_get_format(shm_buffer)),
78-             wl_shm_buffer_get_stride(shm_buffer));
79-    }
80-
81-    if (!buffer->wld)
82-        goto error1;
83-
84-    buffer->destroy_listener.notify = &handle_buffer_destroy;
85-    wl_resource_add_destroy_listener(resource,
86-                                     &buffer->destroy_listener);
87-
88-    return buffer->wld;
89-
90-  error1:
91-    free(buffer);
92-  error0:
93     return NULL;
94 }
95