1 /*
2 * Cogl
3 *
4 * A Low Level GPU Graphics and Utilities API
5 *
6 * Copyright (C) 2020 Endless, Inc.
7 *
8 * Permission is hereby granted, free of charge, to any person
9 * obtaining a copy of this software and associated documentation
10 * files (the "Software"), to deal in the Software without
11 * restriction, including without limitation the rights to use, copy,
12 * modify, merge, publish, distribute, sublicense, and/or sell copies
13 * of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be
17 * included in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 *
28 * Authors:
29 * Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
30 */
31
32 #include "cogl-config.h"
33
34 #include "cogl-dma-buf-handle.h"
35 #include "cogl-object.h"
36
37 #include <errno.h>
38 #include <gio/gio.h>
39 #ifdef __linux__
40 #include <linux/dma-buf.h>
41 #include <sys/ioctl.h>
42 #endif
43 #include <sys/mman.h>
44 #include <unistd.h>
45
46 struct _CoglDmaBufHandle
47 {
48 CoglFramebuffer *framebuffer;
49 int dmabuf_fd;
50 int width;
51 int height;
52 int stride;
53 int offset;
54 int bpp;
55 gpointer user_data;
56 GDestroyNotify destroy_func;
57 };
58
59 CoglDmaBufHandle *
cogl_dma_buf_handle_new(CoglFramebuffer * framebuffer,int dmabuf_fd,int width,int height,int stride,int offset,int bpp,gpointer user_data,GDestroyNotify destroy_func)60 cogl_dma_buf_handle_new (CoglFramebuffer *framebuffer,
61 int dmabuf_fd,
62 int width,
63 int height,
64 int stride,
65 int offset,
66 int bpp,
67 gpointer user_data,
68 GDestroyNotify destroy_func)
69 {
70 CoglDmaBufHandle *dmabuf_handle;
71
72 g_assert (framebuffer);
73 g_assert (dmabuf_fd != -1);
74
75 dmabuf_handle = g_new0 (CoglDmaBufHandle, 1);
76 dmabuf_handle->framebuffer = g_object_ref (framebuffer);
77 dmabuf_handle->dmabuf_fd = dmabuf_fd;
78 dmabuf_handle->user_data = user_data;
79 dmabuf_handle->destroy_func = destroy_func;
80
81 dmabuf_handle->width = width;
82 dmabuf_handle->height = height;
83 dmabuf_handle->stride = stride;
84 dmabuf_handle->offset = offset;
85 dmabuf_handle->bpp = bpp;
86
87 return dmabuf_handle;
88 }
89
90 void
cogl_dma_buf_handle_free(CoglDmaBufHandle * dmabuf_handle)91 cogl_dma_buf_handle_free (CoglDmaBufHandle *dmabuf_handle)
92 {
93 g_return_if_fail (dmabuf_handle != NULL);
94
95 g_clear_object (&dmabuf_handle->framebuffer);
96
97 if (dmabuf_handle->destroy_func)
98 g_clear_pointer (&dmabuf_handle->user_data, dmabuf_handle->destroy_func);
99
100 if (dmabuf_handle->dmabuf_fd != -1)
101 close (dmabuf_handle->dmabuf_fd);
102
103 g_free (dmabuf_handle);
104 }
105
106 #ifdef __linux__
107 static gboolean
sync_read(CoglDmaBufHandle * dmabuf_handle,uint64_t start_or_end,GError ** error)108 sync_read (CoglDmaBufHandle *dmabuf_handle,
109 uint64_t start_or_end,
110 GError **error)
111 {
112 struct dma_buf_sync sync = { 0 };
113
114 sync.flags = start_or_end | DMA_BUF_SYNC_READ;
115
116 while (TRUE)
117 {
118 int ret;
119
120 ret = ioctl (dmabuf_handle->dmabuf_fd, DMA_BUF_IOCTL_SYNC, &sync);
121 if (ret == -1 && errno == EINTR)
122 {
123 continue;
124 }
125 else if (ret == -1)
126 {
127 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
128 "ioctl: %s", g_strerror (errno));
129 return FALSE;
130 }
131 else
132 {
133 break;
134 }
135 }
136
137 return TRUE;
138 }
139
140 gboolean
cogl_dma_buf_handle_sync_read_start(CoglDmaBufHandle * dmabuf_handle,GError ** error)141 cogl_dma_buf_handle_sync_read_start (CoglDmaBufHandle *dmabuf_handle,
142 GError **error)
143 {
144 return sync_read (dmabuf_handle, DMA_BUF_SYNC_START, error);
145 }
146
147 gboolean
cogl_dma_buf_handle_sync_read_end(CoglDmaBufHandle * dmabuf_handle,GError ** error)148 cogl_dma_buf_handle_sync_read_end (CoglDmaBufHandle *dmabuf_handle,
149 GError **error)
150 {
151 return sync_read (dmabuf_handle, DMA_BUF_SYNC_END, error);
152 }
153 #endif
154
155 gpointer
cogl_dma_buf_handle_mmap(CoglDmaBufHandle * dmabuf_handle,GError ** error)156 cogl_dma_buf_handle_mmap (CoglDmaBufHandle *dmabuf_handle,
157 GError **error)
158 {
159 size_t size;
160 gpointer data;
161
162 size = dmabuf_handle->height * dmabuf_handle->stride;
163
164 data = mmap (NULL, size, PROT_READ, MAP_PRIVATE,
165 dmabuf_handle->dmabuf_fd,
166 dmabuf_handle->offset);
167 if (data == MAP_FAILED)
168 {
169 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
170 "mmap failed: %s", g_strerror (errno));
171 return NULL;
172 }
173
174 return data;
175 }
176
177 gboolean
cogl_dma_buf_handle_munmap(CoglDmaBufHandle * dmabuf_handle,gpointer data,GError ** error)178 cogl_dma_buf_handle_munmap (CoglDmaBufHandle *dmabuf_handle,
179 gpointer data,
180 GError **error)
181 {
182 size_t size;
183
184 size = dmabuf_handle->height * dmabuf_handle->stride;
185 if (munmap (data, size) != 0)
186 {
187 g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
188 "munmap failed: %s", g_strerror (errno));
189 return FALSE;
190 }
191
192 return TRUE;
193 }
194
195 CoglFramebuffer *
cogl_dma_buf_handle_get_framebuffer(CoglDmaBufHandle * dmabuf_handle)196 cogl_dma_buf_handle_get_framebuffer (CoglDmaBufHandle *dmabuf_handle)
197 {
198 return dmabuf_handle->framebuffer;
199 }
200
201 int
cogl_dma_buf_handle_get_fd(CoglDmaBufHandle * dmabuf_handle)202 cogl_dma_buf_handle_get_fd (CoglDmaBufHandle *dmabuf_handle)
203 {
204 return dmabuf_handle->dmabuf_fd;
205 }
206
207 int
cogl_dma_buf_handle_get_width(CoglDmaBufHandle * dmabuf_handle)208 cogl_dma_buf_handle_get_width (CoglDmaBufHandle *dmabuf_handle)
209 {
210 return dmabuf_handle->width;
211 }
212
213 int
cogl_dma_buf_handle_get_height(CoglDmaBufHandle * dmabuf_handle)214 cogl_dma_buf_handle_get_height (CoglDmaBufHandle *dmabuf_handle)
215 {
216 return dmabuf_handle->height;
217 }
218
219 int
cogl_dma_buf_handle_get_stride(CoglDmaBufHandle * dmabuf_handle)220 cogl_dma_buf_handle_get_stride (CoglDmaBufHandle *dmabuf_handle)
221 {
222 return dmabuf_handle->stride;
223 }
224
225 int
cogl_dma_buf_handle_get_offset(CoglDmaBufHandle * dmabuf_handle)226 cogl_dma_buf_handle_get_offset (CoglDmaBufHandle *dmabuf_handle)
227 {
228 return dmabuf_handle->offset;
229 }
230
231 int
cogl_dma_buf_handle_get_bpp(CoglDmaBufHandle * dmabuf_handle)232 cogl_dma_buf_handle_get_bpp (CoglDmaBufHandle *dmabuf_handle)
233 {
234 return dmabuf_handle->bpp;
235 }
236