2 * Copyright (c) 2013 Renesas Solutions Corp.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 * 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
22 * DEALINGS IN THE SOFTWARE.
25 * Takanari Hayama <taki@igel.co.jp>
35 #include <sys/types.h>
45 #include <wayland-kms.h>
48 #include "common_drm.h"
49 #include "gbm_kmsint.h"
52 # define GBM_DEBUG(s, x...) { printf(s, ## x); }
54 # define GBM_DEBUG(s, x...) { }
60 static void gbm_kms_destroy(struct gbm_device *gbm)
66 * Check if the given format is supported
68 * Weston requires GBM_FORMAT_XRGB8888 only for now.
70 static int gbm_kms_is_format_supported(struct gbm_device *gbm,
71 uint32_t format, uint32_t usage)
76 case GBM_FORMAT_ARGB8888:
77 case GBM_FORMAT_XRGB8888:
84 static void gbm_kms_bo_destroy(struct gbm_bo *_bo)
86 struct gbm_kms_bo *bo = (struct gbm_kms_bo*)_bo;
92 kms_bo_unmap(bo->addr);
95 kms_bo_destroy(&bo->bo);
102 static struct gbm_bo *gbm_kms_bo_create(struct gbm_device *gbm,
103 uint32_t width, uint32_t height,
104 uint32_t format, uint32_t usage)
106 struct gbm_kms_device *dev = (struct gbm_kms_device*)gbm;
107 struct gbm_kms_bo *bo;
109 KMS_BO_TYPE, KMS_BO_TYPE_SCANOUT_X8R8G8B8,
112 KMS_TERMINATE_PROP_LIST
115 GBM_DEBUG("%s: %s: %d\n", __FILE__, __func__, __LINE__);
117 if (!(bo = calloc(1, sizeof(struct gbm_kms_bo))))
122 case GBM_FORMAT_ARGB8888:
123 case GBM_FORMAT_XRGB8888:
130 if (usage & GBM_BO_USE_CURSOR_64X64)
131 attr[1] = KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8;
136 if (kms_bo_create(dev->kms, attr, &bo->bo))
140 bo->base.width = width;
141 bo->base.height = height;
142 bo->base.format = format;
144 kms_bo_get_prop(bo->bo, KMS_HANDLE, &bo->base.handle.u32);
145 kms_bo_get_prop(bo->bo, KMS_PITCH, &bo->base.stride);
147 bo->size = bo->base.stride * bo->base.height;
149 // TODO: We have to export the handle.
150 // drmPrimeHandleToFd() or DRM_IOCTL_GEM_FLINK
153 if (drmPrimeHandleToFD(dev->base.base.fd, bo->base.handle.u32, DRM_CLOEXEC, &bo->fd)) {
154 // export failed...anything we can do?
158 struct drm_gem_flink fl;
161 fl.handle = bo->base.handle.u32;
164 ret = drmIoctl( dev->base.base.fd, DRM_IOCTL_GEM_FLINK, &fl );
166 GBM_DEBUG("%s: %s: DRM_IOCTL_GEM_FLINK failed. %s\n", __FILE__, __func__, strerror(errno));
173 // Map to the user space for bo_write
174 if (usage & GBM_BO_USE_WRITE) {
175 if (kms_bo_map(bo->bo, &bo->addr))
179 return (struct gbm_bo*)bo;
182 GBM_DEBUG("%s: %s: %d: ERROR!!!!\n", __FILE__, __func__, __LINE__);
183 gbm_kms_bo_destroy((struct gbm_bo*)bo);
187 static int gbm_kms_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
189 struct gbm_kms_bo *bo = (struct gbm_kms_bo*)_bo;
194 memcpy(bo->addr, buf, count);
199 static struct gbm_bo *gbm_kms_bo_import(struct gbm_device *gbm,
200 uint32_t type, void *_buffer,
203 struct gbm_kms_device *dev = (struct gbm_kms_device*)gbm;
204 struct gbm_kms_bo *bo;
205 struct wl_kms_buffer *buffer;
208 * We need to import only wl_buffer for Weston, i.e. client's
211 * To make gbm_kms backend to be agnostic to none-DRM/KMS as much as
212 * possible, wl_buffer that we receive must be DRM BO, nothing else.
213 * We are already kind of wayland dependent which is enough.
215 if (type != GBM_BO_IMPORT_WL_BUFFER)
218 if (!(buffer = wayland_kms_buffer_get((struct wl_resource*)_buffer)))
221 // XXX: BO handle is imported in wayland-kms.
222 if (!(bo = calloc(1, sizeof(struct gbm_kms_bo))))
226 bo->base.width = buffer->width;
227 bo->base.height = buffer->height;
228 bo->base.format = buffer->format;
229 bo->base.stride = buffer->stride;
230 bo->base.handle.u32 = buffer->handle;
232 return (struct gbm_bo*)bo;
241 static struct gbm_surface *gbm_kms_surface_create(struct gbm_device *gbm,
247 struct gbm_kms_device *dev = (struct gbm_kms_device*)gbm;
248 struct gbm_kms_surface *surface;
249 GBM_DEBUG("%s: %s: %d\n", __FILE__, __func__, __LINE__);
251 if (!(surface = calloc(1, sizeof(struct gbm_kms_surface))))
254 surface->base.gbm = gbm;
255 surface->base.width = width;
256 surface->base.height = height;
257 surface->base.format = format;
258 surface->base.flags = flags;
261 flags |= GBM_BO_USE_WRITE;
262 surface->bo[0] = (struct gbm_kms_bo*)gbm_kms_bo_create(gbm, width, height, format, flags);
263 surface->bo[1] = (struct gbm_kms_bo*)gbm_kms_bo_create(gbm, width, height, format, flags);
265 GBM_DEBUG("%s: %s: %d: created surface %dx%d\n", __FILE__, __func__, __LINE__, width, height);
268 return (struct gbm_surface*)surface;
271 static void gbm_kms_surface_destroy(struct gbm_surface *_surface)
273 struct gbm_kms_surface *surface = (struct gbm_kms_surface*)_surface;
278 gbm_kms_bo_destroy((struct gbm_bo*)surface->bo[0]);
279 gbm_kms_bo_destroy((struct gbm_bo*)surface->bo[1]);
284 static struct gbm_bo *gbm_kms_surface_lock_front_buffer(struct gbm_surface *_surface)
286 struct gbm_kms_surface *surface = (struct gbm_kms_surface*)_surface;
289 * Drm-compositor in the weston server relies on this API. After
290 * composing clients' surfaces with gl-renderer, drm-compositor locks
291 * the gbm_surface and queries BO attached to it with this API.
292 * Drm-compositor then sets it to DRM/KMS with drmModeAddFB() and
296 if (surface->front >= 0) {
297 struct gbm_kms_bo *front = surface->bo[surface->front];
299 return (struct gbm_bo*)front;
305 static void gbm_kms_surface_release_buffer(struct gbm_surface *_surface, struct gbm_bo *_bo)
307 struct gbm_kms_bo *bo = (struct gbm_kms_bo*)_bo;
312 static int gbm_kms_surface_has_free_buffers(struct gbm_surface *_surface)
314 struct gbm_kms_surface *surface = (struct gbm_kms_surface*)_surface;
315 return ((!surface->bo[0]->locked) || (!surface->bo[1]->locked));
318 struct gbm_device kms_gbm_device = {
321 .destroy = gbm_kms_destroy,
322 .is_format_supported = gbm_kms_is_format_supported,
324 .bo_create = gbm_kms_bo_create,
325 .bo_import = gbm_kms_bo_import,
326 .bo_write = gbm_kms_bo_write,
327 .bo_destroy = gbm_kms_bo_destroy,
329 .surface_create = gbm_kms_surface_create,
330 .surface_lock_front_buffer = gbm_kms_surface_lock_front_buffer,
331 .surface_release_buffer = gbm_kms_surface_release_buffer,
332 .surface_has_free_buffers = gbm_kms_surface_has_free_buffers,
333 .surface_destroy = gbm_kms_surface_destroy,
336 static struct gbm_device *kms_device_create(int fd)
338 struct gbm_kms_device *dev;
341 GBM_DEBUG("%s: %d\n", __func__, __LINE__);
343 if (!(dev = calloc(1, sizeof(struct gbm_kms_device))))
346 dev->base.type = GBM_DRM_DRIVER_TYPE_CUSTOM;
348 dev->base.base = kms_gbm_device;
349 dev->base.base.fd = fd;
351 if (kms_create(fd, &dev->kms)) {
356 return &dev->base.base;
359 /* backend loader looks for symbol "gbm_backend" */
360 struct gbm_backend gbm_backend = {
361 .backend_name = "kms",
362 .create_device = kms_device_create,