commit 5384214

Michael Forney  ·  2013-11-17 23:33:48 +0000 UTC
parent 365cdf2
drm: Add fallback dumb buffer support
7 files changed,  +330, -22
M drm.c
M drm.h
A dumb.c
+1, -1
1@@ -13,7 +13,7 @@ libwld_la_SOURCES = color.c drawable.c font.c
2 libwld_la_LIBADD = $(fontconfig_LIBS) $(freetype_LIBS) $(pixman_LIBS)
3 
4 if ENABLE_DRM
5-    libwld_la_SOURCES += drm.c
6+    libwld_la_SOURCES += drm.c dumb.c
7     pkginclude_HEADERS += drm.h
8 endif
9 
+1, -0
1@@ -68,6 +68,7 @@ struct wld_drm_context
2 #if WITH_DRM_INTEL
3 extern const struct wld_drm_interface intel_drm;
4 #endif
5+extern const struct wld_drm_interface dumb_drm;
6 
7 bool drm_initialize_context(struct wld_drm_context * context, int fd);
8 void drm_finalize_context(struct wld_drm_context * context);
M drm.c
+7, -1
 1@@ -26,8 +26,9 @@
 2 
 3 const static struct wld_drm_interface * drm_interfaces[] = {
 4 #if WITH_DRM_INTEL
 5-    &intel_drm
 6+    &intel_drm,
 7 #endif
 8+    &dumb_drm
 9 };
10 
11 static const struct wld_drm_interface * find_drm_interface(int fd)
12@@ -107,6 +108,11 @@ void wld_drm_destroy_context(struct wld_drm_context * drm)
13     free(drm);
14 }
15 
16+bool wld_drm_is_dumb(struct wld_drm_context * drm)
17+{
18+    return drm->interface == &dumb_drm;
19+}
20+
21 struct wld_drawable * wld_drm_create_drawable(struct wld_drm_context * drm,
22                                               uint32_t width, uint32_t height,
23                                               uint32_t format)
M drm.h
+3, -0
 1@@ -24,6 +24,7 @@
 2 #ifndef WLD_DRM_H
 3 #define WLD_DRM_H 1
 4 
 5+#include <stdbool.h>
 6 #include <stdint.h>
 7 
 8 struct wld_drm_context;
 9@@ -39,6 +40,8 @@ struct wld_drm_context * wld_drm_create_context(int fd);
10  */
11 void wld_drm_destroy_context(struct wld_drm_context * drm);
12 
13+bool wld_drm_is_dumb(struct wld_drm_context * drm);
14+
15 /**
16  * Create a new DRM drawable.
17  */
A dumb.c
+247, -0
  1@@ -0,0 +1,247 @@
  2+/* wld: dumb.c
  3+ *
  4+ * Copyright (c) 2013 Michael Forney
  5+ *
  6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
  7+ * of this software and associated documentation files (the "Software"), to deal
  8+ * in the Software without restriction, including without limitation the rights
  9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10+ * copies of the Software, and to permit persons to whom the Software is
 11+ * furnished to do so, subject to the following conditions:
 12+ *
 13+ * The above copyright notice and this permission notice shall be included in
 14+ * all copies or substantial portions of the Software.
 15+ *
 16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 22+ * SOFTWARE.
 23+ */
 24+
 25+#include "pixman.h"
 26+#include "pixman-private.h"
 27+#include "drm-private.h"
 28+
 29+#include <fcntl.h>
 30+#include <sys/mman.h>
 31+#include <xf86drm.h>
 32+
 33+#include <errno.h>
 34+
 35+struct dumb_context
 36+{
 37+    struct wld_pixman_context * pixman;
 38+    int fd;
 39+};
 40+
 41+struct dumb_drawable
 42+{
 43+    struct pixman_drawable pixman;
 44+    struct dumb_context * context;
 45+    uint32_t handle;
 46+};
 47+
 48+/* DRM implementation */
 49+static bool dumb_device_supported(uint32_t vendor_id, uint32_t device_id);
 50+static struct dumb_context * dumb_create_context(int drm_fd);
 51+static void dumb_destroy_context(struct dumb_context * context);
 52+static struct wld_drawable * dumb_create_drawable
 53+    (struct dumb_context * context, uint32_t width, uint32_t height,
 54+     uint32_t format);
 55+static struct wld_drawable * dumb_import
 56+    (struct dumb_context * context, uint32_t width, uint32_t height,
 57+     uint32_t format, int prime_fd, unsigned long pitch);
 58+static struct wld_drawable * dumb_import_gem
 59+    (struct dumb_context * context, uint32_t width, uint32_t height,
 60+     uint32_t format, uint32_t gem_name, unsigned long pitch);
 61+
 62+/* DRM drawable */
 63+static int dumb_export(struct wld_drawable * drawable);
 64+static uint32_t dumb_get_handle(struct wld_drawable * drawable);
 65+
 66+static struct drm_draw_interface dumb_draw = {
 67+    .export = &dumb_export,
 68+    .get_handle = &dumb_get_handle
 69+};
 70+static bool dumb_draw_initialized;
 71+
 72+const struct wld_drm_interface dumb_drm = {
 73+    .device_supported = &dumb_device_supported,
 74+    .create_context = (drm_create_context_func_t) &dumb_create_context,
 75+    .destroy_context = (drm_destroy_context_func_t) &dumb_destroy_context,
 76+    .create_drawable = (drm_create_drawable_func_t) &dumb_create_drawable,
 77+    .import = (drm_import_func_t) &dumb_import,
 78+    .import_gem = (drm_import_gem_func_t) &dumb_import_gem,
 79+};
 80+
 81+bool dumb_device_supported(uint32_t vendor_id, uint32_t device_id)
 82+{
 83+    return true;
 84+}
 85+
 86+struct dumb_context * dumb_create_context(int drm_fd)
 87+{
 88+    struct dumb_context * context;
 89+
 90+    if (!(context = malloc(sizeof *context)))
 91+        goto error0;
 92+
 93+    if (!(context->pixman = wld_pixman_create_context()))
 94+        goto error1;
 95+
 96+    context->fd = drm_fd;
 97+
 98+    if (!dumb_draw_initialized)
 99+    {
100+        dumb_draw.base = pixman_draw;
101+        dumb_draw_initialized = true;
102+    }
103+
104+    return context;
105+
106+  error1:
107+    free(context);
108+  error0:
109+    return NULL;
110+}
111+
112+void dumb_destroy_context(struct dumb_context * context)
113+{
114+    wld_pixman_destroy_context(context->pixman);
115+    free(context);
116+}
117+
118+static struct wld_drawable * new_drawable(struct dumb_context * context,
119+                                          uint32_t width, uint32_t height,
120+                                          uint32_t format, uint32_t handle,
121+                                          unsigned long pitch)
122+{
123+    struct dumb_drawable * drawable;
124+    struct drm_mode_map_dumb map_dumb_arg = { .handle = handle };
125+    void * data;
126+    size_t size = pitch * height;
127+    int ret;
128+
129+    if (!(drawable = malloc(sizeof *drawable)))
130+        goto error0;
131+
132+    ret = drmIoctl(context->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb_arg);
133+
134+    if (ret != 0)
135+        goto error1;
136+
137+    data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, context->fd,
138+                map_dumb_arg.offset);
139+
140+    if (data == MAP_FAILED)
141+        goto error1;
142+
143+    if (!pixman_initialize_drawable(context->pixman, &drawable->pixman,
144+                                    width, height, data, pitch, format))
145+    {
146+        goto error2;
147+    }
148+
149+    drawable->pixman.base.interface = (struct wld_draw_interface *) &dumb_draw;
150+    drawable->context = context;
151+    drawable->handle = handle;
152+
153+    return &drawable->pixman.base;
154+
155+  error2:
156+    munmap(data, size);
157+  error1:
158+    free(drawable);
159+  error0:
160+    return NULL;
161+}
162+
163+struct wld_drawable * dumb_create_drawable
164+    (struct dumb_context * context, uint32_t width, uint32_t height,
165+     uint32_t format)
166+{
167+    struct wld_drawable * drawable;
168+    struct drm_mode_create_dumb create_dumb_arg = {
169+        .height = height, .width = width,
170+        .bpp = format_bytes_per_pixel(format) * 8,
171+    };
172+    int ret;
173+
174+    ret = drmIoctl(context->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb_arg);
175+
176+    if (ret != 0)
177+        goto error0;
178+
179+    drawable = new_drawable(context, width, height, format,
180+                            create_dumb_arg.handle, create_dumb_arg.pitch);
181+
182+    if (!drawable)
183+        goto error1;
184+
185+    return drawable;
186+
187+  error1:
188+    {
189+        struct drm_mode_destroy_dumb destroy_dumb_arg = {
190+            .handle = create_dumb_arg.handle
191+        };
192+
193+        drmIoctl(context->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb_arg);
194+    }
195+  error0:
196+    return NULL;
197+}
198+
199+struct wld_drawable * dumb_import(struct dumb_context * context,
200+                                  uint32_t width, uint32_t height,
201+                                  uint32_t format,
202+                                  int prime_fd, unsigned long pitch)
203+{
204+    int ret;
205+    uint32_t handle;
206+
207+    ret = drmPrimeFDToHandle(context->fd, prime_fd, &handle);
208+
209+    if (ret != 0)
210+        goto error0;
211+
212+    return new_drawable(context, width, height, format, handle, pitch);
213+
214+  error0:
215+    return NULL;
216+}
217+
218+struct wld_drawable * dumb_import_gem(struct dumb_context * context,
219+                                      uint32_t width, uint32_t height,
220+                                      uint32_t format,
221+                                      uint32_t gem_name, unsigned long pitch)
222+{
223+    DEBUG("dumb: import_gem is not supported\n");
224+
225+    return NULL;
226+}
227+
228+static int dumb_export(struct wld_drawable * drawable)
229+{
230+    struct dumb_drawable * dumb = (void *) drawable;
231+    int prime_fd, ret;
232+
233+    ret = drmPrimeHandleToFD(dumb->context->fd, dumb->handle,
234+                             DRM_CLOEXEC, &prime_fd);
235+
236+    if (ret != 0)
237+        return -1;
238+
239+    return prime_fd;
240+}
241+
242+static uint32_t dumb_get_handle(struct wld_drawable * drawable)
243+{
244+    struct dumb_drawable * dumb = (void *) drawable;
245+
246+    return dumb->handle;
247+}
248+
+46, -0
 1@@ -0,0 +1,46 @@
 2+/* wld: pixman-private.h
 3+ *
 4+ * Copyright (c) 2013 Michael Forney
 5+ *
 6+ * Permission is hereby granted, free of charge, to any person obtaining a copy
 7+ * of this software and associated documentation files (the "Software"), to deal
 8+ * in the Software without restriction, including without limitation the rights
 9+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+ * copies of the Software, and to permit persons to whom the Software is
11+ * furnished to do so, subject to the following conditions:
12+ *
13+ * The above copyright notice and this permission notice shall be included in
14+ * all copies or substantial portions of the Software.
15+ *
16+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+ * SOFTWARE.
23+ */
24+
25+#ifndef WLD_PIXMAN_PRIVATE_H
26+#define WLD_PIXMAN_PRIVATE_H
27+
28+#include "wld.h"
29+
30+struct wld_pixman_context;
31+
32+struct pixman_drawable
33+{
34+    struct wld_drawable base;
35+    pixman_image_t * image;
36+    struct wld_pixman_context * context;
37+};
38+
39+extern const struct wld_draw_interface pixman_draw;
40+
41+bool pixman_initialize_drawable
42+    (struct wld_pixman_context * context, struct pixman_drawable * drawable,
43+     uint32_t width, uint32_t height,
44+     void * data, uint32_t pitch, uint32_t format);
45+
46+#endif
47+
+25, -20
 1@@ -22,6 +22,7 @@
 2  */
 3 
 4 #include "pixman.h"
 5+#include "pixman-private.h"
 6 #include "wld-private.h"
 7 
 8 #define PIXMAN_COLOR(c) {                   \
 9@@ -36,13 +37,6 @@ struct wld_pixman_context
10     pixman_glyph_cache_t * glyph_cache;
11 };
12 
13-struct pixman_drawable
14-{
15-    struct wld_drawable base;
16-    pixman_image_t * image;
17-    struct wld_pixman_context * context;
18-};
19-
20 static void pixman_fill_rectangle(struct wld_drawable * drawable,
21                                   uint32_t color, int32_t x, int32_t y,
22                                   uint32_t width, uint32_t height);
23@@ -68,7 +62,7 @@ static pixman_image_t * pixman_map(struct wld_drawable * drawable);
24 static void pixman_flush(struct wld_drawable * drawable);
25 static void pixman_destroy(struct wld_drawable * drawable);
26 
27-const static struct wld_draw_interface pixman_draw = {
28+const struct wld_draw_interface pixman_draw = {
29     .fill_rectangle = &pixman_fill_rectangle,
30     .fill_region = &pixman_fill_region,
31     .copy_rectangle = &pixman_copy_rectangle,
32@@ -100,6 +94,25 @@ void wld_pixman_destroy_context(struct wld_pixman_context * context)
33     free(context);
34 }
35 
36+bool pixman_initialize_drawable
37+    (struct wld_pixman_context * context, struct pixman_drawable * drawable,
38+     uint32_t width, uint32_t height,
39+     void * data, uint32_t pitch, uint32_t format)
40+{
41+    drawable->base.interface = &pixman_draw;
42+    drawable->base.width = width;
43+    drawable->base.height = height;
44+    drawable->base.format = format;
45+    drawable->base.pitch = pitch;
46+
47+    drawable->context = context;
48+    drawable->image = pixman_image_create_bits(pixman_format(format),
49+                                               width, height,
50+                                               (uint32_t *) data, pitch);
51+
52+    return drawable->image != NULL;
53+}
54+
55 struct wld_drawable * wld_pixman_create_drawable
56     (struct wld_pixman_context * context, uint32_t width, uint32_t height,
57      void * data, uint32_t pitch, uint32_t format)
58@@ -111,19 +124,11 @@ struct wld_drawable * wld_pixman_create_drawable
59     if (!pixman)
60         goto error0;
61 
62-    pixman->base.interface = &pixman_draw;
63-    pixman->base.width = width;
64-    pixman->base.height = height;
65-    pixman->base.format = format;
66-    pixman->base.pitch = pitch;
67-
68-    pixman->context = context;
69-    pixman->image = pixman_image_create_bits(pixman_format(format),
70-                                             width, height,
71-                                             (uint32_t *) data, pitch);
72-
73-    if (!pixman->image)
74+    if (!pixman_initialize_drawable(context, pixman, width, height,
75+                                    data, pitch, format))
76+    {
77         goto error1;
78+    }
79 
80     return &pixman->base;
81