libdrm_vigs: Scanout flag added to surfaces
[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                             int scanout,
290                             struct vigs_drm_surface **sfc)
291 {
292     struct vigs_drm_surface_impl *sfc_impl;
293     struct drm_vigs_create_surface req =
294     {
295         .width = width,
296         .height = height,
297         .stride = stride,
298         .format = format,
299         .scanout = scanout,
300     };
301     int ret;
302
303     sfc_impl = calloc(sizeof(*sfc_impl), 1);
304
305     if (!sfc_impl) {
306         ret = -ENOMEM;
307         goto fail1;
308     }
309
310     ret = drmIoctl(dev->fd, DRM_IOCTL_VIGS_CREATE_SURFACE, &req);
311
312     if (ret != 0) {
313         ret = -errno;
314         goto fail2;
315     }
316
317     vigs_drm_gem_impl_init((struct vigs_drm_gem_impl*)sfc_impl,
318                            dev,
319                            req.handle,
320                            req.size,
321                            0);
322
323     sfc_impl->base.width = width;
324     sfc_impl->base.height = height;
325     sfc_impl->base.stride = stride;
326     sfc_impl->base.format = format;
327     sfc_impl->base.scanout = scanout;
328     sfc_impl->base.id = req.id;
329
330     *sfc = &sfc_impl->base;
331
332     return 0;
333
334 fail2:
335     free(sfc_impl);
336 fail1:
337     *sfc = NULL;
338
339     return ret;
340 }
341
342 int vigs_drm_surface_open(struct vigs_drm_device *dev,
343                           uint32_t name,
344                           struct vigs_drm_surface **sfc)
345 {
346     struct vigs_drm_surface_impl *sfc_impl;
347     struct drm_gem_open req =
348     {
349         .name = name,
350     };
351     struct drm_vigs_surface_info info_req;
352     int ret;
353
354     sfc_impl = calloc(sizeof(*sfc_impl), 1);
355
356     if (!sfc_impl) {
357         ret = -ENOMEM;
358         goto fail1;
359     }
360
361     ret = drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req);
362
363     if (ret != 0) {
364         ret = -errno;
365         goto fail2;
366     }
367
368     info_req.handle = req.handle;
369
370     ret = drmIoctl(dev->fd, DRM_IOCTL_VIGS_SURFACE_INFO, &info_req);
371
372     if (ret != 0) {
373         ret = -errno;
374         goto fail3;
375     }
376
377     vigs_drm_gem_impl_init((struct vigs_drm_gem_impl*)sfc_impl,
378                            dev,
379                            req.handle,
380                            info_req.size,
381                            name);
382
383     sfc_impl->base.width = info_req.width;
384     sfc_impl->base.height = info_req.height;
385     sfc_impl->base.stride = info_req.stride;
386     sfc_impl->base.format = info_req.format;
387     sfc_impl->base.scanout = info_req.scanout;
388     sfc_impl->base.id = info_req.id;
389
390     *sfc = &sfc_impl->base;
391
392     return 0;
393
394 fail3:
395     vigs_drm_gem_close(dev, req.handle);
396 fail2:
397     free(sfc_impl);
398 fail1:
399     *sfc = NULL;
400
401     return ret;
402 }
403
404 int vigs_drm_surface_set_gpu_dirty(struct vigs_drm_surface *sfc)
405 {
406     struct drm_vigs_surface_set_gpu_dirty req =
407     {
408         .handle = sfc->gem.handle
409     };
410     int ret;
411
412     ret = drmIoctl(sfc->gem.dev->fd, DRM_IOCTL_VIGS_SURFACE_SET_GPU_DIRTY, &req);
413
414     return (ret != 0) ? -errno : 0;
415 }
416
417 int vigs_drm_surface_start_access(struct vigs_drm_surface *sfc,
418                                   uint32_t saf)
419 {
420     struct drm_vigs_surface_start_access req =
421     {
422         .address = (unsigned long)sfc->gem.vaddr,
423         .saf = saf
424     };
425     int ret;
426
427     ret = drmIoctl(sfc->gem.dev->fd, DRM_IOCTL_VIGS_SURFACE_START_ACCESS, &req);
428
429     return (ret != 0) ? -errno : 0;
430 }
431
432 int vigs_drm_surface_end_access(struct vigs_drm_surface *sfc,
433                                 int sync)
434 {
435     struct drm_vigs_surface_end_access req =
436     {
437         .address = (unsigned long)sfc->gem.vaddr,
438         .sync = sync
439     };
440     int ret;
441
442     ret = drmIoctl(sfc->gem.dev->fd, DRM_IOCTL_VIGS_SURFACE_END_ACCESS, &req);
443
444     return (ret != 0) ? -errno : 0;
445 }
446
447 int vigs_drm_execbuffer_create(struct vigs_drm_device *dev,
448                                uint32_t size,
449                                struct vigs_drm_execbuffer **execbuffer)
450 {
451     struct vigs_drm_execbuffer_impl *execbuffer_impl;
452     struct drm_vigs_create_execbuffer req =
453     {
454         .size = size
455     };
456     int ret;
457
458     execbuffer_impl = calloc(sizeof(*execbuffer_impl), 1);
459
460     if (!execbuffer_impl) {
461         ret = -ENOMEM;
462         goto fail1;
463     }
464
465     ret = drmIoctl(dev->fd, DRM_IOCTL_VIGS_CREATE_EXECBUFFER, &req);
466
467     if (ret != 0) {
468         ret = -errno;
469         goto fail2;
470     }
471
472     vigs_drm_gem_impl_init((struct vigs_drm_gem_impl*)execbuffer_impl,
473                            dev,
474                            req.handle,
475                            req.size,
476                            0);
477
478     *execbuffer = &execbuffer_impl->base;
479
480     return 0;
481
482 fail2:
483     free(execbuffer_impl);
484 fail1:
485     *execbuffer = NULL;
486
487     return ret;
488 }
489
490 int vigs_drm_execbuffer_open(struct vigs_drm_device *dev,
491                              uint32_t name,
492                              struct vigs_drm_execbuffer **execbuffer)
493 {
494     struct vigs_drm_execbuffer_impl *execbuffer_impl;
495     struct drm_gem_open req =
496     {
497         .name = name,
498     };
499     int ret;
500
501     execbuffer_impl = calloc(sizeof(*execbuffer_impl), 1);
502
503     if (!execbuffer_impl) {
504         ret = -ENOMEM;
505         goto fail1;
506     }
507
508     ret = drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req);
509
510     if (ret != 0) {
511         ret = -errno;
512         goto fail2;
513     }
514
515     vigs_drm_gem_impl_init((struct vigs_drm_gem_impl*)execbuffer_impl,
516                            dev,
517                            req.handle,
518                            req.size,
519                            name);
520
521     *execbuffer = &execbuffer_impl->base;
522
523     return 0;
524
525 fail2:
526     free(execbuffer_impl);
527 fail1:
528     *execbuffer = NULL;
529
530     return ret;
531 }
532
533 int vigs_drm_execbuffer_exec(struct vigs_drm_execbuffer *execbuffer)
534 {
535     struct drm_vigs_exec req =
536     {
537         .handle = execbuffer->gem.handle
538     };
539     int ret;
540
541     ret = drmIoctl(execbuffer->gem.dev->fd, DRM_IOCTL_VIGS_EXEC, &req);
542
543     return (ret != 0) ? -errno : 0;
544 }
545
546 int vigs_drm_fence_create(struct vigs_drm_device *dev,
547                           int send,
548                           struct vigs_drm_fence **fence)
549 {
550     struct vigs_drm_fence_impl *fence_impl;
551     struct drm_vigs_create_fence req =
552     {
553         .send = send
554     };
555     int ret;
556
557     fence_impl = calloc(sizeof(*fence_impl), 1);
558
559     if (!fence_impl) {
560         ret = -ENOMEM;
561         goto fail1;
562     }
563
564     ret = drmIoctl(dev->fd, DRM_IOCTL_VIGS_CREATE_FENCE, &req);
565
566     if (ret != 0) {
567         ret = -errno;
568         goto fail2;
569     }
570
571     atomic_set(&fence_impl->ref_count, 1);
572     fence_impl->base.dev = dev;
573     fence_impl->base.handle = req.handle;
574     fence_impl->base.seq = req.seq;
575     fence_impl->base.signaled = 0;
576
577     *fence = &fence_impl->base;
578
579     return 0;
580
581 fail2:
582     free(fence_impl);
583 fail1:
584     *fence = NULL;
585
586     return ret;
587 }
588
589 void vigs_drm_fence_ref(struct vigs_drm_fence *fence)
590 {
591     struct vigs_drm_fence_impl *fence_impl;
592
593     if (!fence) {
594         return;
595     }
596
597     fence_impl = vigs_containerof(fence, struct vigs_drm_fence_impl, base);
598
599     atomic_inc(&fence_impl->ref_count);
600 }
601
602 void vigs_drm_fence_unref(struct vigs_drm_fence *fence)
603 {
604     struct vigs_drm_fence_impl *fence_impl;
605     struct drm_vigs_fence_unref req;
606
607     if (!fence) {
608         return;
609     }
610
611     fence_impl = vigs_containerof(fence, struct vigs_drm_fence_impl, base);
612
613     assert(atomic_read(&fence_impl->ref_count) > 0);
614     if (!atomic_dec_and_test(&fence_impl->ref_count)) {
615         return;
616     }
617
618     req.handle = fence->handle;
619
620     drmIoctl(fence->dev->fd, DRM_IOCTL_VIGS_FENCE_UNREF, &req);
621
622     free(fence_impl);
623 }
624
625 int vigs_drm_fence_wait(struct vigs_drm_fence *fence)
626 {
627     struct drm_vigs_fence_wait req =
628     {
629         .handle = fence->handle
630     };
631     int ret;
632
633     ret = drmIoctl(fence->dev->fd, DRM_IOCTL_VIGS_FENCE_WAIT, &req);
634
635     return (ret != 0) ? -errno : 0;
636 }
637
638 int vigs_drm_fence_check(struct vigs_drm_fence *fence)
639 {
640     struct drm_vigs_fence_signaled req =
641     {
642         .handle = fence->handle
643     };
644     int ret;
645
646     if (fence->signaled) {
647         return 0;
648     }
649
650     ret = drmIoctl(fence->dev->fd, DRM_IOCTL_VIGS_FENCE_SIGNALED, &req);
651
652     if (ret != 0) {
653         return -errno;
654     }
655
656     fence->signaled = req.signaled;
657
658     return 0;
659 }