main
dumb.c
1/* wld: dumb.c
2 *
3 * Copyright (c) 2013, 2014 Michael Forney
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include "drm-private.h"
25#include "drm.h"
26#include "pixman.h"
27
28#include <fcntl.h>
29#include <sys/mman.h>
30#include <unistd.h>
31#include <xf86drm.h>
32
33#include <errno.h>
34
35struct dumb_context {
36 struct wld_context base;
37 int fd;
38};
39
40struct dumb_buffer {
41 struct buffer base;
42 struct wld_exporter exporter;
43 struct dumb_context *context;
44 uint32_t handle;
45};
46
47#include "interface/buffer.h"
48#include "interface/context.h"
49#define DRM_DRIVER_NAME dumb
50#include "interface/drm.h"
51IMPL(dumb_context, wld_context)
52IMPL(dumb_buffer, wld_buffer)
53
54const struct wld_context_impl *dumb_context_impl = &wld_context_impl;
55
56bool
57driver_device_supported(uint32_t vendor_id, uint32_t device_id)
58{
59 return true;
60}
61
62struct wld_context *
63driver_create_context(int drm_fd)
64{
65 struct dumb_context *context;
66
67 if (!(context = malloc(sizeof *context)))
68 return NULL;
69
70 context_initialize(&context->base, &wld_context_impl);
71 context->fd = drm_fd;
72
73 return &context->base;
74}
75
76struct wld_renderer *
77context_create_renderer(struct wld_context *context)
78{
79 return wld_create_renderer(wld_pixman_context);
80}
81
82static bool export(struct wld_exporter *exporter, struct wld_buffer *base,
83 uint32_t type, union wld_object *object)
84{
85 struct dumb_buffer *buffer = dumb_buffer(base);
86
87 switch (type) {
88 case WLD_DRM_OBJECT_HANDLE:
89 object->u32 = buffer->handle;
90 return true;
91 case WLD_DRM_OBJECT_PRIME_FD:
92 if (drmPrimeHandleToFD(buffer->context->fd, buffer->handle,
93 DRM_CLOEXEC, &object->i)
94 != 0) {
95 return false;
96 }
97
98 return true;
99 default:
100 return false;
101 }
102}
103
104static struct buffer *
105new_buffer(struct dumb_context *context,
106 uint32_t width, uint32_t height,
107 uint32_t format, uint32_t handle,
108 unsigned long pitch)
109{
110 struct dumb_buffer *buffer;
111
112 if (!(buffer = malloc(sizeof *buffer)))
113 return NULL;
114
115 buffer_initialize(&buffer->base, &wld_buffer_impl,
116 width, height, format, pitch);
117 buffer->context = context;
118 buffer->handle = handle;
119 buffer->exporter.export = &export;
120 wld_buffer_add_exporter(&buffer->base.base, &buffer->exporter);
121
122 return &buffer->base;
123}
124
125struct buffer *
126context_create_buffer(struct wld_context *base,
127 uint32_t width, uint32_t height,
128 uint32_t format, uint32_t flags)
129{
130 struct dumb_context *context = dumb_context(base);
131 struct buffer *buffer;
132 struct drm_mode_create_dumb create_dumb = {
133 .height = height,
134 .width = width,
135 .bpp = format_bytes_per_pixel(format) * 8,
136 };
137
138 if (drmIoctl(context->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb) != 0)
139 goto error0;
140
141 buffer = new_buffer(context, width, height, format,
142 create_dumb.handle, create_dumb.pitch);
143
144 if (!buffer)
145 goto error1;
146
147 return buffer;
148
149error1 : {
150 struct drm_mode_destroy_dumb destroy_dumb = {
151 .handle = create_dumb.handle
152 };
153
154 drmIoctl(context->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
155}
156error0:
157 return NULL;
158}
159
160struct buffer *
161context_import_buffer(struct wld_context *base,
162 uint32_t type, union wld_object object,
163 uint32_t width, uint32_t height,
164 uint32_t format, uint32_t pitch)
165{
166 struct dumb_context *context = dumb_context(base);
167 uint32_t handle;
168
169 switch (type) {
170 case WLD_DRM_OBJECT_PRIME_FD:
171 if (drmPrimeFDToHandle(context->fd, object.i, &handle) != 0)
172 return NULL;
173 break;
174 default:
175 return NULL;
176 }
177
178 return new_buffer(context, width, height, format, handle, pitch);
179}
180
181void
182context_destroy(struct wld_context *base)
183{
184 struct dumb_context *context = dumb_context(base);
185
186 close(context->fd);
187 free(context);
188}
189
190/**** Buffer ****/
191
192bool
193buffer_map(struct buffer *base)
194{
195 struct dumb_buffer *buffer = dumb_buffer(&base->base);
196 struct drm_mode_map_dumb map_dumb = { .handle = buffer->handle };
197 void *data;
198
199 if (drmIoctl(buffer->context->fd, DRM_IOCTL_MODE_MAP_DUMB,
200 &map_dumb)
201 != 0) {
202 return false;
203 }
204
205 data = mmap(NULL, buffer->base.base.pitch * buffer->base.base.height,
206 PROT_READ | PROT_WRITE, MAP_SHARED,
207 buffer->context->fd, map_dumb.offset);
208
209 if (data == MAP_FAILED)
210 return false;
211
212 buffer->base.base.map = data;
213
214 return true;
215}
216
217bool
218buffer_unmap(struct buffer *buffer)
219{
220 if (munmap(buffer->base.map,
221 buffer->base.pitch * buffer->base.height)
222 == -1) {
223 return false;
224 }
225
226 buffer->base.map = NULL;
227
228 return true;
229}
230
231void
232buffer_destroy(struct buffer *base)
233{
234 struct dumb_buffer *buffer = dumb_buffer(&base->base);
235 struct drm_mode_destroy_dumb destroy_dumb = {
236 .handle = buffer->handle
237 };
238
239 drmIoctl(buffer->context->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
240 free(buffer);
241}