5530d48eaf164ed1ad9f33f3f6029cc375546a81
[platform/upstream/libdrm.git] / vigs / vigs.c
1 /* vigs.c
2  *
3  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
4  * Authors:
5  * Stanislav Vorobiov <s.vorobiov@samsung.com>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the next
15  * paragraph) shall be included in all copies or substantial portions of the
16  * Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  * OTHER DEALINGS IN THE SOFTWARE.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <assert.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <errno.h>
36
37 #include <sys/mman.h>
38 #include <linux/stddef.h>
39
40 #include <xf86drm.h>
41 #include <xf86atomic.h>
42
43 #include "vigs.h"
44 #include "vigs_drm.h"
45
46 #define vigs_offsetof(type, member) ((size_t)&((type*)0)->member)
47
48 #define vigs_containerof(ptr, type, member) ((type*)((char*)(ptr) - vigs_offsetof(type, member)))
49
50 struct vigs_drm_gem_info
51 {
52     atomic_t ref_count;
53 };
54
55 struct vigs_drm_gem_impl
56 {
57     struct vigs_drm_gem_info info;
58
59     struct vigs_drm_gem gem;
60 };
61
62 struct vigs_drm_surface_impl
63 {
64     struct vigs_drm_gem_info gem_info;
65
66     struct vigs_drm_surface base;
67 };
68
69 struct vigs_drm_execbuffer_impl
70 {
71     struct vigs_drm_gem_info gem_info;
72
73     struct vigs_drm_execbuffer base;
74 };
75
76 static void vigs_drm_gem_close(struct vigs_drm_device *dev, uint32_t handle)
77 {
78     struct drm_gem_close req =
79     {
80         .handle = handle,
81     };
82
83     if (handle) {
84         drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
85     }
86 }
87
88 static void vigs_drm_gem_impl_init(struct vigs_drm_gem_impl *gem_impl,
89                                    struct vigs_drm_device *dev,
90                                    uint32_t handle,
91                                    uint32_t size,
92                                    uint32_t name)
93 {
94     atomic_set(&gem_impl->info.ref_count, 1);
95     gem_impl->gem.dev = dev;
96     gem_impl->gem.size = size;
97     gem_impl->gem.handle = handle;
98     gem_impl->gem.name = name;
99 }
100
101 int vigs_drm_device_create(int fd, struct vigs_drm_device **dev)
102 {
103     drmVersionPtr version;
104     uint32_t major;
105     int ret;
106
107     *dev = calloc(sizeof(**dev), 1);
108
109     if (!*dev) {
110         ret = -ENOMEM;
111         goto fail1;
112     }
113
114     version = drmGetVersion(fd);
115
116     if (!version) {
117         ret = -EINVAL;
118         goto fail2;
119     }
120
121     major = version->version_major;
122
123     drmFreeVersion(version);
124
125     if (major != DRM_VIGS_DRIVER_VERSION) {
126         ret = -EINVAL;
127         goto fail2;
128     }
129
130     (*dev)->fd = fd;
131
132     return 0;
133
134 fail2:
135     free(*dev);
136 fail1:
137     *dev = NULL;
138
139     return ret;
140 }
141
142 void vigs_drm_device_destroy(struct vigs_drm_device *dev)
143 {
144     free(dev);
145 }
146
147 int vigs_drm_device_get_protocol_version(struct vigs_drm_device *dev,
148                                          uint32_t *protocol_version)
149 {
150     struct drm_vigs_get_protocol_version req;
151     int ret;
152
153     ret = drmIoctl(dev->fd, DRM_IOCTL_VIGS_GET_PROTOCOL_VERSION, &req);
154
155     if (ret != 0) {
156         return -errno;
157     }
158
159     if (protocol_version) {
160         *protocol_version = req.version;
161     }
162
163     return 0;
164 }
165
166 void vigs_drm_gem_ref(struct vigs_drm_gem *gem)
167 {
168     struct vigs_drm_gem_impl *gem_impl;
169
170     if (!gem) {
171         return;
172     }
173
174     gem_impl = vigs_containerof(gem, struct vigs_drm_gem_impl, gem);
175
176     atomic_inc(&gem_impl->info.ref_count);
177 }
178
179 void vigs_drm_gem_unref(struct vigs_drm_gem *gem)
180 {
181     struct vigs_drm_gem_impl *gem_impl;
182
183     if (!gem) {
184         return;
185     }
186
187     gem_impl = vigs_containerof(gem, struct vigs_drm_gem_impl, gem);
188
189     assert(atomic_read(&gem_impl->info.ref_count) > 0);
190     if (!atomic_dec_and_test(&gem_impl->info.ref_count)) {
191         return;
192     }
193
194     if (gem->vaddr) {
195         munmap(gem->vaddr, gem->size);
196     }
197
198     vigs_drm_gem_close(gem->dev, gem->handle);
199
200     free(gem_impl);
201 }
202
203 int vigs_drm_gem_get_name(struct vigs_drm_gem *gem)
204 {
205     struct drm_gem_flink req =
206     {
207         .handle = gem->handle,
208     };
209     int ret;
210
211     if (gem->name) {
212         return 0;
213     }
214
215     ret = drmIoctl(gem->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
216
217     if (ret != 0) {
218         return -errno;
219     }
220
221     gem->name = req.name;
222
223     return 0;
224 }
225
226 int vigs_drm_gem_map(struct vigs_drm_gem *gem, int track_access)
227 {
228     struct drm_vigs_gem_map req =
229     {
230         .handle = gem->handle,
231         .track_access = track_access
232     };
233     int ret;
234
235     if (gem->vaddr) {
236         return 0;
237     }
238
239     ret = drmIoctl(gem->dev->fd, DRM_IOCTL_VIGS_GEM_MAP, &req);
240
241     if (ret != 0) {
242         return -errno;
243     }
244
245     gem->vaddr = (void*)req.address;
246
247     return 0;
248 }
249
250 void vigs_drm_gem_unmap(struct vigs_drm_gem *gem)
251 {
252     if (!gem->vaddr) {
253         return;
254     }
255
256     munmap(gem->vaddr, gem->size);
257     gem->vaddr = NULL;
258 }
259
260 int vigs_drm_surface_create(struct vigs_drm_device *dev,
261                             uint32_t width,
262                             uint32_t height,
263                             uint32_t stride,
264                             uint32_t format,
265                             struct vigs_drm_surface **sfc)
266 {
267     struct vigs_drm_surface_impl *sfc_impl;
268     struct drm_vigs_create_surface req =
269     {
270         .width = width,
271         .height = height,
272         .stride = stride,
273         .format = format,
274     };
275     int ret;
276
277     sfc_impl = calloc(sizeof(*sfc_impl), 1);
278
279     if (!sfc_impl) {
280         ret = -ENOMEM;
281         goto fail1;
282     }
283
284     ret = drmIoctl(dev->fd, DRM_IOCTL_VIGS_CREATE_SURFACE, &req);
285
286     if (ret != 0) {
287         ret = -errno;
288         goto fail2;
289     }
290
291     vigs_drm_gem_impl_init((struct vigs_drm_gem_impl*)sfc_impl,
292                            dev,
293                            req.handle,
294                            req.size,
295                            0);
296
297     sfc_impl->base.width = width;
298     sfc_impl->base.height = height;
299     sfc_impl->base.stride = stride;
300     sfc_impl->base.format = format;
301     sfc_impl->base.id = req.id;
302
303     *sfc = &sfc_impl->base;
304
305     return 0;
306
307 fail2:
308     free(sfc_impl);
309 fail1:
310     *sfc = NULL;
311
312     return ret;
313 }
314
315 int vigs_drm_surface_open(struct vigs_drm_device *dev,
316                           uint32_t name,
317                           struct vigs_drm_surface **sfc)
318 {
319     struct vigs_drm_surface_impl *sfc_impl;
320     struct drm_gem_open req =
321     {
322         .name = name,
323     };
324     struct drm_vigs_surface_info info_req;
325     int ret;
326
327     sfc_impl = calloc(sizeof(*sfc_impl), 1);
328
329     if (!sfc_impl) {
330         ret = -ENOMEM;
331         goto fail1;
332     }
333
334     ret = drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req);
335
336     if (ret != 0) {
337         ret = -errno;
338         goto fail2;
339     }
340
341     info_req.handle = req.handle;
342
343     ret = drmIoctl(dev->fd, DRM_IOCTL_VIGS_SURFACE_INFO, &info_req);
344
345     if (ret != 0) {
346         ret = -errno;
347         goto fail3;
348     }
349
350     vigs_drm_gem_impl_init((struct vigs_drm_gem_impl*)sfc_impl,
351                            dev,
352                            req.handle,
353                            info_req.size,
354                            name);
355
356     sfc_impl->base.width = info_req.width;
357     sfc_impl->base.height = info_req.height;
358     sfc_impl->base.stride = info_req.stride;
359     sfc_impl->base.format = info_req.format;
360     sfc_impl->base.id = info_req.id;
361
362     *sfc = &sfc_impl->base;
363
364     return 0;
365
366 fail3:
367     vigs_drm_gem_close(dev, req.handle);
368 fail2:
369     free(sfc_impl);
370 fail1:
371     *sfc = NULL;
372
373     return ret;
374 }
375
376 int vigs_drm_surface_set_gpu_dirty(struct vigs_drm_surface *sfc)
377 {
378     struct drm_vigs_surface_set_gpu_dirty req =
379     {
380         .handle = sfc->gem.handle
381     };
382     int ret;
383
384     ret = drmIoctl(sfc->gem.dev->fd, DRM_IOCTL_VIGS_SURFACE_SET_GPU_DIRTY, &req);
385
386     return (ret != 0) ? -errno : 0;
387 }
388
389 int vigs_drm_surface_start_access(struct vigs_drm_surface *sfc,
390                                   uint32_t saf)
391 {
392     struct drm_vigs_surface_start_access req =
393     {
394         .address = (unsigned long)sfc->gem.vaddr,
395         .saf = saf
396     };
397     int ret;
398
399     ret = drmIoctl(sfc->gem.dev->fd, DRM_IOCTL_VIGS_SURFACE_START_ACCESS, &req);
400
401     return (ret != 0) ? -errno : 0;
402 }
403
404 int vigs_drm_surface_end_access(struct vigs_drm_surface *sfc,
405                                 int sync)
406 {
407     struct drm_vigs_surface_end_access req =
408     {
409         .address = (unsigned long)sfc->gem.vaddr,
410         .sync = sync
411     };
412     int ret;
413
414     ret = drmIoctl(sfc->gem.dev->fd, DRM_IOCTL_VIGS_SURFACE_END_ACCESS, &req);
415
416     return (ret != 0) ? -errno : 0;
417 }
418
419 int vigs_drm_execbuffer_create(struct vigs_drm_device *dev,
420                                uint32_t size,
421                                struct vigs_drm_execbuffer **execbuffer)
422 {
423     struct vigs_drm_execbuffer_impl *execbuffer_impl;
424     struct drm_vigs_create_execbuffer req =
425     {
426         .size = size
427     };
428     int ret;
429
430     execbuffer_impl = calloc(sizeof(*execbuffer_impl), 1);
431
432     if (!execbuffer_impl) {
433         ret = -ENOMEM;
434         goto fail1;
435     }
436
437     ret = drmIoctl(dev->fd, DRM_IOCTL_VIGS_CREATE_EXECBUFFER, &req);
438
439     if (ret != 0) {
440         ret = -errno;
441         goto fail2;
442     }
443
444     vigs_drm_gem_impl_init((struct vigs_drm_gem_impl*)execbuffer_impl,
445                            dev,
446                            req.handle,
447                            req.size,
448                            0);
449
450     *execbuffer = &execbuffer_impl->base;
451
452     return 0;
453
454 fail2:
455     free(execbuffer_impl);
456 fail1:
457     *execbuffer = NULL;
458
459     return ret;
460 }
461
462 int vigs_drm_execbuffer_open(struct vigs_drm_device *dev,
463                              uint32_t name,
464                              struct vigs_drm_execbuffer **execbuffer)
465 {
466     struct vigs_drm_execbuffer_impl *execbuffer_impl;
467     struct drm_gem_open req =
468     {
469         .name = name,
470     };
471     int ret;
472
473     execbuffer_impl = calloc(sizeof(*execbuffer_impl), 1);
474
475     if (!execbuffer_impl) {
476         ret = -ENOMEM;
477         goto fail1;
478     }
479
480     ret = drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req);
481
482     if (ret != 0) {
483         ret = -errno;
484         goto fail2;
485     }
486
487     vigs_drm_gem_impl_init((struct vigs_drm_gem_impl*)execbuffer_impl,
488                            dev,
489                            req.handle,
490                            req.size,
491                            name);
492
493     *execbuffer = &execbuffer_impl->base;
494
495     return 0;
496
497 fail2:
498     free(execbuffer_impl);
499 fail1:
500     *execbuffer = NULL;
501
502     return ret;
503 }
504
505 int vigs_drm_execbuffer_exec(struct vigs_drm_execbuffer *execbuffer)
506 {
507     struct drm_vigs_exec req =
508     {
509         .handle = execbuffer->gem.handle
510     };
511     int ret;
512
513     ret = drmIoctl(execbuffer->gem.dev->fd, DRM_IOCTL_VIGS_EXEC, &req);
514
515     return (ret != 0) ? -errno : 0;
516 }