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}