Switch from GEM to PRIME.
[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         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));
151                 goto error;
152         }
153
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))
157                         goto error;
158         }
159
160         return (struct gbm_bo*)bo;
161
162  error:
163         GBM_DEBUG("%s: %s: %d: ERROR!!!!\n", __FILE__, __func__, __LINE__);
164         gbm_kms_bo_destroy((struct gbm_bo*)bo);
165         return NULL;
166 }
167
168 static int gbm_kms_bo_write(struct gbm_bo *_bo, const void *buf, size_t count)
169 {
170         struct gbm_kms_bo *bo = (struct gbm_kms_bo*)_bo;
171
172         if (!bo->addr)
173                 return -1;
174
175         memcpy(bo->addr, buf, count);
176
177         return 0;
178 }
179
180 static struct gbm_bo *gbm_kms_bo_import(struct gbm_device *gbm,
181                                         uint32_t type, void *_buffer,
182                                         uint32_t usage)
183 {
184         struct gbm_kms_device *dev = (struct gbm_kms_device*)gbm;
185         struct gbm_kms_bo *bo;
186         struct wl_kms_buffer *buffer;
187
188         /*
189          * We need to  import only wl_buffer for Weston, i.e. client's
190          * rendering buffer.
191          *
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.
195          */
196         if (type != GBM_BO_IMPORT_WL_BUFFER)
197                 return NULL;
198
199         if (!(buffer = wayland_kms_buffer_get((struct wl_resource*)_buffer)))
200                 return NULL;
201
202         // XXX: BO handle is imported in wayland-kms.
203         if (!(bo = calloc(1, sizeof(struct gbm_kms_bo))))
204                 return NULL;
205
206         bo->base.gbm = gbm;
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;
212
213         return (struct gbm_bo*)bo;
214
215  error:
216         if (bo)
217                 free(bo);
218
219         return NULL;
220 }
221
222 static struct gbm_surface *gbm_kms_surface_create(struct gbm_device *gbm,
223                                                   uint32_t width,
224                                                   uint32_t height,
225                                                   uint32_t format,
226                                                   uint32_t flags)
227 {
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__);
231
232         if (!(surface = calloc(1, sizeof(struct gbm_kms_surface))))
233                 return NULL;
234
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;
240
241         /* need to map BO */
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);
245
246         GBM_DEBUG("%s: %s: %d: created surface %dx%d\n", __FILE__, __func__, __LINE__, width, height);
247         surface->front = -1;
248
249         return (struct gbm_surface*)surface;
250 }
251
252 static void gbm_kms_surface_destroy(struct gbm_surface *_surface)
253 {
254         struct gbm_kms_surface *surface = (struct gbm_kms_surface*)_surface;
255
256         if (!surface)
257                 return;
258
259         gbm_kms_bo_destroy((struct gbm_bo*)surface->bo[0]);
260         gbm_kms_bo_destroy((struct gbm_bo*)surface->bo[1]);
261
262         free(surface);
263 }
264
265 static struct gbm_bo *gbm_kms_surface_lock_front_buffer(struct gbm_surface *_surface)
266 {
267         struct gbm_kms_surface *surface = (struct gbm_kms_surface*)_surface;
268
269         /*
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
274          * drmModeAddFB2().
275          */
276
277         if (surface->front >= 0) {
278                 struct gbm_kms_bo *front = surface->bo[surface->front];
279                 front->locked = 1;
280                 return (struct gbm_bo*)front;
281         }
282
283         return NULL;
284 }
285
286 static void gbm_kms_surface_release_buffer(struct gbm_surface *_surface, struct gbm_bo *_bo)
287 {
288         struct gbm_kms_bo *bo = (struct gbm_kms_bo*)_bo;
289         bo->locked = 0;
290         return;
291 }
292
293 static int gbm_kms_surface_has_free_buffers(struct gbm_surface *_surface)
294 {
295         struct gbm_kms_surface *surface = (struct gbm_kms_surface*)_surface;
296         return ((!surface->bo[0]->locked) || (!surface->bo[1]->locked));
297 }
298
299 struct gbm_device kms_gbm_device = {
300         .name = "kms",
301
302         .destroy = gbm_kms_destroy,
303         .is_format_supported = gbm_kms_is_format_supported,
304
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,
309
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,
315 };
316
317 static struct gbm_device *kms_device_create(int fd)
318 {
319         struct gbm_kms_device *dev;
320         int ret;
321
322         GBM_DEBUG("%s: %d\n", __func__, __LINE__);
323
324         if (!(dev = calloc(1, sizeof(struct gbm_kms_device))))
325                 return NULL;
326
327         dev->base.type = GBM_DRM_DRIVER_TYPE_CUSTOM;
328
329         dev->base.base = kms_gbm_device;
330         dev->base.base.fd = fd;
331
332         if (kms_create(fd, &dev->kms)) {
333                 free(dev);
334                 return NULL;
335         }
336
337         return &dev->base.base;
338 }
339
340 /* backend loader looks for symbol "gbm_backend" */
341 struct gbm_backend gbm_backend = {
342         .backend_name = "kms",
343         .create_device = kms_device_create,
344 };