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 if (drmPrimeHandleToFD(dev->base.base.fd, bo->base.handle.u32, DRM_CLOEXEC, &bo->fd)) {
150 GBM_DEBUG("%s: %s: drmPrimeHandleToFD() failed. %s\n", __FILE__, __func__, strerror(errno));
154 // Map to the user space for bo_write
155 if (usage & GBM_BO_USE_WRITE) {
156 if (kms_bo_map(bo->bo, &bo->addr))
160 return (struct gbm_bo*)bo;
163 GBM_DEBUG("%s: %s: %d: ERROR!!!!\n", __FILE__, __func__, __LINE__);
164 gbm_kms_bo_destroy((struct gbm_bo*)bo);
168 static int gbm_kms_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
170 struct gbm_kms_bo *bo = (struct gbm_kms_bo*)_bo;
175 memcpy(bo->addr, buf, count);
180 static struct gbm_bo *gbm_kms_bo_import(struct gbm_device *gbm,
181 uint32_t type, void *_buffer,
184 struct gbm_kms_device *dev = (struct gbm_kms_device*)gbm;
185 struct gbm_kms_bo *bo;
186 struct wl_kms_buffer *buffer;
189 * We need to import only wl_buffer for Weston, i.e. client's
192 * To make gbm_kms backend to be agnostic to none-DRM/KMS as much as
193 * possible, wl_buffer that we receive must be DRM BO, nothing else.
194 * We are already kind of wayland dependent which is enough.
196 if (type != GBM_BO_IMPORT_WL_BUFFER)
199 if (!(buffer = wayland_kms_buffer_get((struct wl_resource*)_buffer)))
202 // XXX: BO handle is imported in wayland-kms.
203 if (!(bo = calloc(1, sizeof(struct gbm_kms_bo))))
207 bo->base.width = buffer->width;
208 bo->base.height = buffer->height;
209 bo->base.format = buffer->format;
210 bo->base.stride = buffer->stride;
211 bo->base.handle.u32 = buffer->handle;
213 return (struct gbm_bo*)bo;
222 static struct gbm_surface *gbm_kms_surface_create(struct gbm_device *gbm,
228 struct gbm_kms_device *dev = (struct gbm_kms_device*)gbm;
229 struct gbm_kms_surface *surface;
230 GBM_DEBUG("%s: %s: %d\n", __FILE__, __func__, __LINE__);
232 if (!(surface = calloc(1, sizeof(struct gbm_kms_surface))))
235 surface->base.gbm = gbm;
236 surface->base.width = width;
237 surface->base.height = height;
238 surface->base.format = format;
239 surface->base.flags = flags;
242 flags |= GBM_BO_USE_WRITE;
243 surface->bo[0] = (struct gbm_kms_bo*)gbm_kms_bo_create(gbm, width, height, format, flags);
244 surface->bo[1] = (struct gbm_kms_bo*)gbm_kms_bo_create(gbm, width, height, format, flags);
246 GBM_DEBUG("%s: %s: %d: created surface %dx%d\n", __FILE__, __func__, __LINE__, width, height);
249 return (struct gbm_surface*)surface;
252 static void gbm_kms_surface_destroy(struct gbm_surface *_surface)
254 struct gbm_kms_surface *surface = (struct gbm_kms_surface*)_surface;
259 gbm_kms_bo_destroy((struct gbm_bo*)surface->bo[0]);
260 gbm_kms_bo_destroy((struct gbm_bo*)surface->bo[1]);
265 static struct gbm_bo *gbm_kms_surface_lock_front_buffer(struct gbm_surface *_surface)
267 struct gbm_kms_surface *surface = (struct gbm_kms_surface*)_surface;
270 * Drm-compositor in the weston server relies on this API. After
271 * composing clients' surfaces with gl-renderer, drm-compositor locks
272 * the gbm_surface and queries BO attached to it with this API.
273 * Drm-compositor then sets it to DRM/KMS with drmModeAddFB() and
277 if (surface->front >= 0) {
278 struct gbm_kms_bo *front = surface->bo[surface->front];
280 return (struct gbm_bo*)front;
286 static void gbm_kms_surface_release_buffer(struct gbm_surface *_surface, struct gbm_bo *_bo)
288 struct gbm_kms_bo *bo = (struct gbm_kms_bo*)_bo;
293 static int gbm_kms_surface_has_free_buffers(struct gbm_surface *_surface)
295 struct gbm_kms_surface *surface = (struct gbm_kms_surface*)_surface;
296 return ((!surface->bo[0]->locked) || (!surface->bo[1]->locked));
299 struct gbm_device kms_gbm_device = {
302 .destroy = gbm_kms_destroy,
303 .is_format_supported = gbm_kms_is_format_supported,
305 .bo_create = gbm_kms_bo_create,
306 .bo_import = gbm_kms_bo_import,
307 .bo_write = gbm_kms_bo_write,
308 .bo_destroy = gbm_kms_bo_destroy,
310 .surface_create = gbm_kms_surface_create,
311 .surface_lock_front_buffer = gbm_kms_surface_lock_front_buffer,
312 .surface_release_buffer = gbm_kms_surface_release_buffer,
313 .surface_has_free_buffers = gbm_kms_surface_has_free_buffers,
314 .surface_destroy = gbm_kms_surface_destroy,
317 static struct gbm_device *kms_device_create(int fd)
319 struct gbm_kms_device *dev;
322 GBM_DEBUG("%s: %d\n", __func__, __LINE__);
324 if (!(dev = calloc(1, sizeof(struct gbm_kms_device))))
327 dev->base.type = GBM_DRM_DRIVER_TYPE_CUSTOM;
329 dev->base.base = kms_gbm_device;
330 dev->base.base.fd = fd;
332 if (kms_create(fd, &dev->kms)) {
337 return &dev->base.base;
340 /* backend loader looks for symbol "gbm_backend" */
341 struct gbm_backend gbm_backend = {
342 .backend_name = "kms",
343 .create_device = kms_device_create,