a7662e4da7b4605b2ee14d8d8d35fae31761b48b
[platform/upstream/libgbm.git] / backend_kms.c
1 /*
2  * Copyright (c) 2013 Renesas Solutions Corp.
3  *
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:
10  *
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
13  * Software.
14  *
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.
23  *
24  * Authors:
25  *    Takanari Hayama <taki@igel.co.jp>
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stddef.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <limits.h>
34
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <dlfcn.h>
40
41 #include <xf86drm.h>
42 #include <libkms.h>
43 #include <errno.h>
44
45 #include <wayland-kms.h>
46
47 #include "gbmint.h"
48 #include "common_drm.h"
49 #include "gbm_kmsint.h"
50
51 #if defined(DEBUG)
52 #  define GBM_DEBUG(s, x...)    { printf(s, ## x); }
53 #else
54 #  define GBM_DEBUG(s, x...)    { }
55 #endif
56
57 /*
58  * Destroy gbm backend
59  */
60 static void gbm_kms_destroy(struct gbm_device *gbm)
61 {
62         free(gbm);
63 }
64
65 /*
66  * Check if the given format is supported
67  *
68  * Weston requires GBM_FORMAT_XRGB8888 only for now.
69  */
70 static int gbm_kms_is_format_supported(struct gbm_device *gbm,
71                                        uint32_t format, uint32_t usage)
72 {
73         int ret = 0;
74         switch (format) {
75                 // 32bpp
76         case GBM_FORMAT_ARGB8888:
77         case GBM_FORMAT_XRGB8888:
78                 ret = 1;
79         }
80
81         return ret;
82 }
83
84 static void gbm_kms_bo_destroy(struct gbm_bo *_bo)
85 {
86         struct gbm_kms_bo *bo = (struct gbm_kms_bo*)_bo;
87
88         if (!bo)
89                 return;
90
91         if (bo->addr)
92                 kms_bo_unmap(bo->addr);
93
94         if (bo->bo)
95                 kms_bo_destroy(&bo->bo);
96
97         free(bo);
98
99         return;
100 }
101
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)
105 {
106         struct gbm_kms_device *dev = (struct gbm_kms_device*)gbm;
107         struct gbm_kms_bo *bo;
108         unsigned attr[] = {
109                 KMS_BO_TYPE, KMS_BO_TYPE_SCANOUT_X8R8G8B8,
110                 KMS_WIDTH, 0,
111                 KMS_HEIGHT, 0,
112                 KMS_TERMINATE_PROP_LIST
113         };
114
115         GBM_DEBUG("%s: %s: %d\n", __FILE__, __func__, __LINE__);
116
117         if (!(bo = calloc(1, sizeof(struct gbm_kms_bo))))
118                 return NULL;
119
120         switch (format) {
121                 // 32bpp
122         case GBM_FORMAT_ARGB8888:
123         case GBM_FORMAT_XRGB8888:
124                 break;
125         default:
126                 // unsupported...
127                 goto error;
128         }
129
130         if (usage & GBM_BO_USE_CURSOR_64X64)
131                 attr[1] = KMS_BO_TYPE_CURSOR_64X64_A8R8G8B8;
132         attr[3] = width;
133         attr[5] = height;
134
135         // Create BO
136         if (kms_bo_create(dev->kms, attr, &bo->bo))
137                 goto error;
138
139         bo->base.gbm = gbm;
140         bo->base.width = width;
141         bo->base.height = height;
142         bo->base.format = format;
143
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);
146
147         bo->size = bo->base.stride * bo->base.height;
148
149         // TODO: We have to export the handle.
150         // drmPrimeHandleToFd() or DRM_IOCTL_GEM_FLINK
151         {
152 #if 0
153                 if (drmPrimeHandleToFD(dev->base.base.fd, bo->base.handle.u32, DRM_CLOEXEC, &bo->fd)) {
154                         // export failed...anything we can do?
155                         goto error;
156                 }
157 #else
158                 struct drm_gem_flink fl;
159                 int ret;
160
161                 fl.handle = bo->base.handle.u32;
162                 fl.name   = 0;
163
164                 ret = drmIoctl( dev->base.base.fd, DRM_IOCTL_GEM_FLINK, &fl );
165                 if (ret) {
166                         GBM_DEBUG("%s: %s: DRM_IOCTL_GEM_FLINK failed. %s\n", __FILE__, __func__, strerror(errno));
167                         goto error;
168                 }
169
170                 bo->fd = fl.name;
171 #endif
172         }
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))
176                         goto error;
177         }
178
179         return (struct gbm_bo*)bo;
180
181  error:
182         GBM_DEBUG("%s: %s: %d: ERROR!!!!\n", __FILE__, __func__, __LINE__);
183         gbm_kms_bo_destroy((struct gbm_bo*)bo);
184         return NULL;
185 }
186
187 static int gbm_kms_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
188 {
189         struct gbm_kms_bo *bo = (struct gbm_kms_bo*)_bo;
190
191         if (!bo->addr)
192                 return -1;
193
194         memcpy(bo->addr, buf, count);
195
196         return 0;
197 }
198
199 static struct gbm_bo *gbm_kms_bo_import(struct gbm_device *gbm,
200                                         uint32_t type, void *_buffer,
201                                         uint32_t usage)
202 {
203         struct gbm_kms_device *dev = (struct gbm_kms_device*)gbm;
204         struct gbm_kms_bo *bo;
205         struct wl_kms_buffer *buffer;
206
207         /*
208          * We need to  import only wl_buffer for Weston, i.e. client's
209          * rendering buffer.
210          *
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.
214          */
215         if (type != GBM_BO_IMPORT_WL_BUFFER)
216                 return NULL;
217
218         if (!(buffer = wayland_kms_buffer_get((struct wl_resource*)_buffer)))
219                 return NULL;
220
221         // XXX: BO handle is imported in wayland-kms.
222         if (!(bo = calloc(1, sizeof(struct gbm_kms_bo))))
223                 return NULL;
224
225         bo->base.gbm = gbm;
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;
231
232         return (struct gbm_bo*)bo;
233
234  error:
235         if (bo)
236                 free(bo);
237
238         return NULL;
239 }
240
241 static struct gbm_surface *gbm_kms_surface_create(struct gbm_device *gbm,
242                                                   uint32_t width,
243                                                   uint32_t height,
244                                                   uint32_t format,
245                                                   uint32_t flags)
246 {
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__);
250
251         if (!(surface = calloc(1, sizeof(struct gbm_kms_surface))))
252                 return NULL;
253
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;
259
260         /* need to map BO */
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);
264
265         GBM_DEBUG("%s: %s: %d: created surface %dx%d\n", __FILE__, __func__, __LINE__, width, height);
266         surface->front = -1;
267
268         return (struct gbm_surface*)surface;
269 }
270
271 static void gbm_kms_surface_destroy(struct gbm_surface *_surface)
272 {
273         struct gbm_kms_surface *surface = (struct gbm_kms_surface*)_surface;
274
275         if (!surface)
276                 return;
277
278         gbm_kms_bo_destroy((struct gbm_bo*)surface->bo[0]);
279         gbm_kms_bo_destroy((struct gbm_bo*)surface->bo[1]);
280
281         free(surface);
282 }
283
284 static struct gbm_bo *gbm_kms_surface_lock_front_buffer(struct gbm_surface *_surface)
285 {
286         struct gbm_kms_surface *surface = (struct gbm_kms_surface*)_surface;
287
288         /*
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
293          * drmModeAddFB2().
294          */
295
296         if (surface->front >= 0) {
297                 struct gbm_kms_bo *front = surface->bo[surface->front];
298                 front->locked = 1;
299                 return (struct gbm_bo*)front;
300         }
301
302         return NULL;
303 }
304
305 static void gbm_kms_surface_release_buffer(struct gbm_surface *_surface, struct gbm_bo *_bo)
306 {
307         struct gbm_kms_bo *bo = (struct gbm_kms_bo*)_bo;
308         bo->locked = 0;
309         return;
310 }
311
312 static int gbm_kms_surface_has_free_buffers(struct gbm_surface *_surface)
313 {
314         struct gbm_kms_surface *surface = (struct gbm_kms_surface*)_surface;
315         return ((!surface->bo[0]->locked) || (!surface->bo[1]->locked));
316 }
317
318 struct gbm_device kms_gbm_device = {
319         .name = "kms",
320
321         .destroy = gbm_kms_destroy,
322         .is_format_supported = gbm_kms_is_format_supported,
323
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,
328
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,
334 };
335
336 static struct gbm_device *kms_device_create(int fd)
337 {
338         struct gbm_kms_device *dev;
339         int ret;
340
341         GBM_DEBUG("%s: %d\n", __func__, __LINE__);
342
343         if (!(dev = calloc(1, sizeof(struct gbm_kms_device))))
344                 return NULL;
345
346         dev->base.type = GBM_DRM_DRIVER_TYPE_CUSTOM;
347
348         dev->base.base = kms_gbm_device;
349         dev->base.base.fd = fd;
350
351         if (kms_create(fd, &dev->kms)) {
352                 free(dev);
353                 return NULL;
354         }
355
356         return &dev->base.base;
357 }
358
359 /* backend loader looks for symbol "gbm_backend" */
360 struct gbm_backend gbm_backend = {
361         .backend_name = "kms",
362         .create_device = kms_device_create,
363 };