dc95a7c54738267a6aa2785739ae7f365bc57fd3
[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 struct vigs_drm_fence_impl
77 {
78     struct vigs_drm_fence base;
79
80     atomic_t ref_count;
81 };
82
83 static void vigs_drm_gem_close(struct vigs_drm_device *dev, uint32_t handle)
84 {
85     struct drm_gem_close req =
86     {
87         .handle = handle,
88     };
89
90     if (handle) {
91         drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
92     }
93 }
94
95 static void vigs_drm_gem_impl_init(struct vigs_drm_gem_impl *gem_impl,
96                                    struct vigs_drm_device *dev,
97                                    uint32_t handle,
98                                    uint32_t size,
99                                    uint32_t name)
100 {
101     atomic_set(&gem_impl->info.ref_count, 1);
102     gem_impl->gem.dev = dev;
103     gem_impl->gem.size = size;
104     gem_impl->gem.handle = handle;
105     gem_impl->gem.name = name;
106 }
107
108 int vigs_drm_device_create(int fd, struct vigs_drm_device **dev)
109 {
110     drmVersionPtr version;
111     uint32_t major;
112     int ret;
113
114     *dev = calloc(sizeof(**dev), 1);
115
116     if (!*dev) {
117         ret = -ENOMEM;
118         goto fail1;
119     }
120
121     version = drmGetVersion(fd);
122
123     if (!version) {
124         ret = -EINVAL;
125         goto fail2;
126     }
127
128     major = version->version_major;
129
130     drmFreeVersion(version);
131
132     if (major != DRM_VIGS_DRIVER_VERSION) {
133         ret = -EINVAL;
134         goto fail2;
135     }
136
137     (*dev)->fd = fd;
138
139     return 0;
140
141 fail2:
142     free(*dev);
143 fail1:
144     *dev = NULL;
145
146     return ret;
147 }
148
149 void vigs_drm_device_destroy(struct vigs_drm_device *dev)
150 {
151     free(dev);
152 }
153
154 int vigs_drm_device_get_protocol_version(struct vigs_drm_device *dev,
155                                          uint32_t *protocol_version)
156 {
157     struct drm_vigs_get_protocol_version req;
158     int ret;
159
160     ret = drmIoctl(dev->fd, DRM_IOCTL_VIGS_GET_PROTOCOL_VERSION, &req);
161
162     if (ret != 0) {
163         return -errno;
164     }
165
166     if (protocol_version) {
167         *protocol_version = req.version;
168     }
169
170     return 0;
171 }
172
173 void vigs_drm_gem_ref(struct vigs_drm_gem *gem)
174 {
175     struct vigs_drm_gem_impl *gem_impl;
176
177     if (!gem) {
178         return;
179     }
180
181     gem_impl = vigs_containerof(gem, struct vigs_drm_gem_impl, gem);
182
183     atomic_inc(&gem_impl->info.ref_count);
184 }
185
186 void vigs_drm_gem_unref(struct vigs_drm_gem *gem)
187 {
188     struct vigs_drm_gem_impl *gem_impl;
189
190     if (!gem) {
191         return;
192     }
193
194     gem_impl = vigs_containerof(gem, struct vigs_drm_gem_impl, gem);
195
196     assert(atomic_read(&gem_impl->info.ref_count) > 0);
197     if (!atomic_dec_and_test(&gem_impl->info.ref_count)) {
198         return;
199     }
200
201     if (gem->vaddr) {
202         munmap(gem->vaddr, gem->size);
203     }
204
205     vigs_drm_gem_close(gem->dev, gem->handle);
206
207     free(gem_impl);
208 }
209
210 int vigs_drm_gem_get_name(struct vigs_drm_gem *gem)
211 {
212     struct drm_gem_flink req =
213     {
214         .handle = gem->handle,
215     };
216     int ret;
217
218     if (gem->name) {
219         return 0;
220     }
221
222     ret = drmIoctl(gem->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
223
224     if (ret != 0) {
225         return -errno;
226     }
227
228     gem->name = req.name;
229
230     return 0;
231 }
232
233 int vigs_drm_gem_map(struct vigs_drm_gem *gem, int track_access)
234 {
235     struct drm_vigs_gem_map req =
236     {
237         .handle = gem->handle,
238         .track_access = track_access
239     };
240     int ret;
241
242     if (gem->vaddr) {
243         return 0;
244     }
245
246     ret = drmIoctl(gem->dev->fd, DRM_IOCTL_VIGS_GEM_MAP, &req);
247
248     if (ret != 0) {
249         return -errno;
250     }
251
252     gem->vaddr = (void*)req.address;
253
254     return 0;
255 }
256
257 void vigs_drm_gem_unmap(struct vigs_drm_gem *gem)
258 {
259     if (!gem->vaddr) {
260         return;
261     }
262
263     munmap(gem->vaddr, gem->size);
264     gem->vaddr = NULL;
265 }
266
267 int vigs_drm_gem_wait(struct vigs_drm_gem *gem)
268 {
269     struct drm_vigs_gem_wait req =
270     {
271         .handle = gem->handle,
272     };
273     int ret;
274
275     ret = drmIoctl(gem->dev->fd, DRM_IOCTL_VIGS_GEM_WAIT, &req);
276
277     if (ret != 0) {
278         return -errno;
279     }
280
281     return 0;
282 }
283
284 int vigs_drm_surface_create(struct vigs_drm_device *dev,
285                             uint32_t width,
286                             uint32_t height,
287                             uint32_t stride,
288                             uint32_t format,
289                             struct vigs_drm_surface **sfc)
290 {
291     struct vigs_drm_surface_impl *sfc_impl;
292     struct drm_vigs_create_surface req =
293     {
294         .width = width,
295         .height = height,
296         .stride = stride,
297         .format = format,
298     };
299     int ret;
300
301     sfc_impl = calloc(sizeof(*sfc_impl), 1);
302
303     if (!sfc_impl) {
304         ret = -ENOMEM;
305         goto fail1;
306     }
307
308     ret = drmIoctl(dev->fd, DRM_IOCTL_VIGS_CREATE_SURFACE, &req);
309
310     if (ret != 0) {
311         ret = -errno;
312         goto fail2;
313     }
314
315     vigs_drm_gem_impl_init((struct vigs_drm_gem_impl*)sfc_impl,
316                            dev,
317                            req.handle,
318                            req.size,
319                            0);
320
321     sfc_impl->base.width = width;
322     sfc_impl->base.height = height;
323     sfc_impl->base.stride = stride;
324     sfc_impl->base.format = format;
325     sfc_impl->base.id = req.id;
326
327     *sfc = &sfc_impl->base;
328
329     return 0;
330
331 fail2:
332     free(sfc_impl);
333 fail1:
334     *sfc = NULL;
335
336     return ret;
337 }
338
339 int vigs_drm_surface_open(struct vigs_drm_device *dev,
340                           uint32_t name,
341                           struct vigs_drm_surface **sfc)
342 {
343     struct vigs_drm_surface_impl *sfc_impl;
344     struct drm_gem_open req =
345     {
346         .name = name,
347     };
348     struct drm_vigs_surface_info info_req;
349     int ret;
350
351     sfc_impl = calloc(sizeof(*sfc_impl), 1);
352
353     if (!sfc_impl) {
354         ret = -ENOMEM;
355         goto fail1;
356     }
357
358     ret = drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req);
359
360     if (ret != 0) {
361         ret = -errno;
362         goto fail2;
363     }
364
365     info_req.handle = req.handle;
366
367     ret = drmIoctl(dev->fd, DRM_IOCTL_VIGS_SURFACE_INFO, &info_req);
368
369     if (ret != 0) {
370         ret = -errno;
371         goto fail3;
372     }
373
374     vigs_drm_gem_impl_init((struct vigs_drm_gem_impl*)sfc_impl,
375                            dev,
376                            req.handle,
377                            info_req.size,
378                            name);
379
380     sfc_impl->base.width = info_req.width;
381     sfc_impl->base.height = info_req.height;
382     sfc_impl->base.stride = info_req.stride;
383     sfc_impl->base.format = info_req.format;
384     sfc_impl->base.id = info_req.id;
385
386     *sfc = &sfc_impl->base;
387
388     return 0;
389
390 fail3:
391     vigs_drm_gem_close(dev, req.handle);
392 fail2:
393     free(sfc_impl);
394 fail1:
395     *sfc = NULL;
396
397     return ret;
398 }
399
400 int vigs_drm_surface_set_gpu_dirty(struct vigs_drm_surface *sfc)
401 {
402     struct drm_vigs_surface_set_gpu_dirty req =
403     {
404         .handle = sfc->gem.handle
405     };
406     int ret;
407
408     ret = drmIoctl(sfc->gem.dev->fd, DRM_IOCTL_VIGS_SURFACE_SET_GPU_DIRTY, &req);
409
410     return (ret != 0) ? -errno : 0;
411 }
412
413 int vigs_drm_surface_start_access(struct vigs_drm_surface *sfc,
414                                   uint32_t saf)
415 {
416     struct drm_vigs_surface_start_access req =
417     {
418         .address = (unsigned long)sfc->gem.vaddr,
419         .saf = saf
420     };
421     int ret;
422
423     ret = drmIoctl(sfc->gem.dev->fd, DRM_IOCTL_VIGS_SURFACE_START_ACCESS, &req);
424
425     return (ret != 0) ? -errno : 0;
426 }
427
428 int vigs_drm_surface_end_access(struct vigs_drm_surface *sfc,
429                                 int sync)
430 {
431     struct drm_vigs_surface_end_access req =
432     {
433         .address = (unsigned long)sfc->gem.vaddr,
434         .sync = sync
435     };
436     int ret;
437
438     ret = drmIoctl(sfc->gem.dev->fd, DRM_IOCTL_VIGS_SURFACE_END_ACCESS, &req);
439
440     return (ret != 0) ? -errno : 0;
441 }
442
443 int vigs_drm_execbuffer_create(struct vigs_drm_device *dev,
444                                uint32_t size,
445                                struct vigs_drm_execbuffer **execbuffer)
446 {
447     struct vigs_drm_execbuffer_impl *execbuffer_impl;
448     struct drm_vigs_create_execbuffer req =
449     {
450         .size = size
451     };
452     int ret;
453
454     execbuffer_impl = calloc(sizeof(*execbuffer_impl), 1);
455
456     if (!execbuffer_impl) {
457         ret = -ENOMEM;
458         goto fail1;
459     }
460
461     ret = drmIoctl(dev->fd, DRM_IOCTL_VIGS_CREATE_EXECBUFFER, &req);
462
463     if (ret != 0) {
464         ret = -errno;
465         goto fail2;
466     }
467
468     vigs_drm_gem_impl_init((struct vigs_drm_gem_impl*)execbuffer_impl,
469                            dev,
470                            req.handle,
471                            req.size,
472                            0);
473
474     *execbuffer = &execbuffer_impl->base;
475
476     return 0;
477
478 fail2:
479     free(execbuffer_impl);
480 fail1:
481     *execbuffer = NULL;
482
483     return ret;
484 }
485
486 int vigs_drm_execbuffer_open(struct vigs_drm_device *dev,
487                              uint32_t name,
488                              struct vigs_drm_execbuffer **execbuffer)
489 {
490     struct vigs_drm_execbuffer_impl *execbuffer_impl;
491     struct drm_gem_open req =
492     {
493         .name = name,
494     };
495     int ret;
496
497     execbuffer_impl = calloc(sizeof(*execbuffer_impl), 1);
498
499     if (!execbuffer_impl) {
500         ret = -ENOMEM;
501         goto fail1;
502     }
503
504     ret = drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req);
505
506     if (ret != 0) {
507         ret = -errno;
508         goto fail2;
509     }
510
511     vigs_drm_gem_impl_init((struct vigs_drm_gem_impl*)execbuffer_impl,
512                            dev,
513                            req.handle,
514                            req.size,
515                            name);
516
517     *execbuffer = &execbuffer_impl->base;
518
519     return 0;
520
521 fail2:
522     free(execbuffer_impl);
523 fail1:
524     *execbuffer = NULL;
525
526     return ret;
527 }
528
529 int vigs_drm_execbuffer_exec(struct vigs_drm_execbuffer *execbuffer)
530 {
531     struct drm_vigs_exec req =
532     {
533         .handle = execbuffer->gem.handle
534     };
535     int ret;
536
537     ret = drmIoctl(execbuffer->gem.dev->fd, DRM_IOCTL_VIGS_EXEC, &req);
538
539     return (ret != 0) ? -errno : 0;
540 }
541
542 int vigs_drm_fence_create(struct vigs_drm_device *dev,
543                           int send,
544                           struct vigs_drm_fence **fence)
545 {
546     struct vigs_drm_fence_impl *fence_impl;
547     struct drm_vigs_create_fence req =
548     {
549         .send = send
550     };
551     int ret;
552
553     fence_impl = calloc(sizeof(*fence_impl), 1);
554
555     if (!fence_impl) {
556         ret = -ENOMEM;
557         goto fail1;
558     }
559
560     ret = drmIoctl(dev->fd, DRM_IOCTL_VIGS_CREATE_FENCE, &req);
561
562     if (ret != 0) {
563         ret = -errno;
564         goto fail2;
565     }
566
567     atomic_set(&fence_impl->ref_count, 1);
568     fence_impl->base.dev = dev;
569     fence_impl->base.handle = req.handle;
570     fence_impl->base.seq = req.seq;
571     fence_impl->base.signaled = 0;
572
573     *fence = &fence_impl->base;
574
575     return 0;
576
577 fail2:
578     free(fence_impl);
579 fail1:
580     *fence = NULL;
581
582     return ret;
583 }
584
585 void vigs_drm_fence_ref(struct vigs_drm_fence *fence)
586 {
587     struct vigs_drm_fence_impl *fence_impl;
588
589     if (!fence) {
590         return;
591     }
592
593     fence_impl = vigs_containerof(fence, struct vigs_drm_fence_impl, base);
594
595     atomic_inc(&fence_impl->ref_count);
596 }
597
598 void vigs_drm_fence_unref(struct vigs_drm_fence *fence)
599 {
600     struct vigs_drm_fence_impl *fence_impl;
601     struct drm_vigs_fence_unref req;
602
603     if (!fence) {
604         return;
605     }
606
607     fence_impl = vigs_containerof(fence, struct vigs_drm_fence_impl, base);
608
609     assert(atomic_read(&fence_impl->ref_count) > 0);
610     if (!atomic_dec_and_test(&fence_impl->ref_count)) {
611         return;
612     }
613
614     req.handle = fence->handle;
615
616     drmIoctl(fence->dev->fd, DRM_IOCTL_VIGS_FENCE_UNREF, &req);
617
618     free(fence_impl);
619 }
620
621 int vigs_drm_fence_wait(struct vigs_drm_fence *fence)
622 {
623     struct drm_vigs_fence_wait req =
624     {
625         .handle = fence->handle
626     };
627     int ret;
628
629     ret = drmIoctl(fence->dev->fd, DRM_IOCTL_VIGS_FENCE_WAIT, &req);
630
631     return (ret != 0) ? -errno : 0;
632 }
633
634 int vigs_drm_fence_check(struct vigs_drm_fence *fence)
635 {
636     struct drm_vigs_fence_signaled req =
637     {
638         .handle = fence->handle
639     };
640     int ret;
641
642     if (fence->signaled) {
643         return 0;
644     }
645
646     ret = drmIoctl(fence->dev->fd, DRM_IOCTL_VIGS_FENCE_SIGNALED, &req);
647
648     if (ret != 0) {
649         return -errno;
650     }
651
652     fence->signaled = req.signaled;
653
654     return 0;
655 }