3b73ac80bf6634ad3d08e44c7e81136bc6e9caf7
[mesa.git] / src / gallium / drivers / vc4 / vc4_bufmgr.c
1 /*
2 * Copyright © 2014 Broadcom
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, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include <errno.h>
25 #include <err.h>
26 #include <sys/mman.h>
27 #include <xf86drm.h>
28 #include <xf86drmMode.h>
29
30 #include "util/u_memory.h"
31
32 #include "vc4_context.h"
33 #include "vc4_screen.h"
34
35 struct vc4_bo *
36 vc4_bo_alloc(struct vc4_screen *screen, uint32_t size, const char *name)
37 {
38 struct vc4_bo *bo = CALLOC_STRUCT(vc4_bo);
39 if (!bo)
40 return NULL;
41
42 pipe_reference_init(&bo->reference, 1);
43 bo->screen = screen;
44 bo->size = size;
45 bo->name = name;
46
47 struct drm_mode_create_dumb create;
48 memset(&create, 0, sizeof(create));
49
50 create.width = 128;
51 create.bpp = 8;
52 create.height = (size + 127) / 128;
53
54 int ret = drmIoctl(screen->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);
55 if (ret != 0) {
56 fprintf(stderr, "create ioctl failure\n");
57 abort();
58 }
59
60 bo->handle = create.handle;
61 assert(create.size >= size);
62
63 return bo;
64 }
65
66 void
67 vc4_bo_free(struct vc4_bo *bo)
68 {
69 struct vc4_screen *screen = bo->screen;
70
71 if (bo->map) {
72 #ifdef USE_VC4_SIMULATOR
73 if (bo->simulator_winsys_map) {
74 free(bo->map);
75 bo->map = bo->simulator_winsys_map;
76 }
77 #endif
78 munmap(bo->map, bo->size);
79 }
80
81 struct drm_gem_close c;
82 memset(&c, 0, sizeof(c));
83 c.handle = bo->handle;
84 int ret = drmIoctl(screen->fd, DRM_IOCTL_GEM_CLOSE, &c);
85 if (ret != 0)
86 fprintf(stderr, "close object %d: %s\n", bo->handle, strerror(errno));
87
88 free(bo);
89 }
90
91 struct vc4_bo *
92 vc4_bo_open_name(struct vc4_screen *screen, uint32_t name,
93 uint32_t winsys_stride)
94 {
95 struct vc4_bo *bo = CALLOC_STRUCT(vc4_bo);
96
97 struct drm_gem_open o;
98 o.name = name;
99 int ret = drmIoctl(screen->fd, DRM_IOCTL_GEM_OPEN, &o);
100 if (ret) {
101 fprintf(stderr, "Failed to open bo %d: %s\n",
102 name, strerror(errno));
103 free(bo);
104 return NULL;
105 }
106
107 pipe_reference_init(&bo->reference, 1);
108 bo->screen = screen;
109 bo->handle = o.handle;
110 bo->size = o.size;
111 bo->name = "winsys";
112
113 #ifdef USE_VC4_SIMULATOR
114 vc4_bo_map(bo);
115 bo->simulator_winsys_map = bo->map;
116 bo->simulator_winsys_stride = winsys_stride;
117 bo->map = malloc(bo->size);
118 #endif
119
120 return bo;
121 }
122
123 struct vc4_bo *
124 vc4_bo_alloc_mem(struct vc4_screen *screen, const void *data, uint32_t size,
125 const char *name)
126 {
127 void *map;
128 struct vc4_bo *bo;
129
130 bo = vc4_bo_alloc(screen, size, name);
131 map = vc4_bo_map(bo);
132 memcpy(map, data, size);
133 return bo;
134 }
135
136 bool
137 vc4_bo_flink(struct vc4_bo *bo, uint32_t *name)
138 {
139 struct drm_gem_flink flink = {
140 .handle = bo->handle,
141 };
142 int ret = drmIoctl(bo->screen->fd, DRM_IOCTL_GEM_FLINK, &flink);
143 if (ret) {
144 fprintf(stderr, "Failed to flink bo %d: %s\n",
145 bo->handle, strerror(errno));
146 free(bo);
147 return false;
148 }
149
150 *name = flink.name;
151
152 return true;
153 }
154
155 bool
156 vc4_wait_seqno(struct vc4_screen *screen, uint64_t seqno, uint64_t timeout_ns)
157 {
158 #ifndef USE_VC4_SIMULATOR
159 struct drm_vc4_wait_seqno wait;
160 memset(&wait, 0, sizeof(wait));
161 wait.seqno = seqno;
162 wait.timeout_ns = timeout_ns;
163
164 int ret = drmIoctl(screen->fd, DRM_IOCTL_VC4_WAIT_SEQNO, &wait);
165 if (ret == -ETIME) {
166 return false;
167 } else if (ret != 0) {
168 fprintf(stderr, "wait failed\n");
169 abort();
170 } else {
171 screen->finished_seqno = wait.seqno;
172 return true;
173 }
174 #else
175 return true;
176 #endif
177 }
178
179 bool
180 vc4_bo_wait(struct vc4_bo *bo, uint64_t timeout_ns)
181 {
182 #ifndef USE_VC4_SIMULATOR
183 struct vc4_screen *screen = bo->screen;
184
185 struct drm_vc4_wait_bo wait;
186 memset(&wait, 0, sizeof(wait));
187 wait.handle = bo->handle;
188 wait.timeout_ns = timeout_ns;
189
190 int ret = drmIoctl(screen->fd, DRM_IOCTL_VC4_WAIT_BO, &wait);
191 if (ret == -ETIME) {
192 return false;
193 } else if (ret != 0) {
194 fprintf(stderr, "wait failed\n");
195 abort();
196 } else {
197 return true;
198 }
199 #else
200 return true;
201 #endif
202 }
203
204 void *
205 vc4_bo_map_unsynchronized(struct vc4_bo *bo)
206 {
207 int ret;
208
209 if (bo->map)
210 return bo->map;
211
212 struct drm_mode_map_dumb map;
213 memset(&map, 0, sizeof(map));
214 map.handle = bo->handle;
215 ret = drmIoctl(bo->screen->fd, DRM_IOCTL_MODE_MAP_DUMB, &map);
216 if (ret != 0) {
217 fprintf(stderr, "map ioctl failure\n");
218 abort();
219 }
220
221 bo->map = mmap(NULL, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
222 bo->screen->fd, map.offset);
223 if (bo->map == MAP_FAILED) {
224 fprintf(stderr, "mmap of bo %d (offset 0x%016llx, size %d) failed\n",
225 bo->handle, (long long)map.offset, bo->size);
226 abort();
227 }
228
229 return bo->map;
230 }
231
232 void *
233 vc4_bo_map(struct vc4_bo *bo)
234 {
235 void *map = vc4_bo_map_unsynchronized(bo);
236
237 bool ok = vc4_bo_wait(bo, PIPE_TIMEOUT_INFINITE);
238 if (!ok) {
239 fprintf(stderr, "BO wait for map failed\n");
240 abort();
241 }
242
243 return map;
244 }