Merge branch 'master' into i915-unification
[mesa.git] / src / mesa / drivers / dri / common / dri_bufmgr_ttm.c
1 /**************************************************************************
2 *
3 * Copyright © 2007 Intel Corporation
4 * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
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 NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * The above copyright notice and this permission notice (including the
24 * next paragraph) shall be included in all copies or substantial portions
25 * of the Software.
26 *
27 *
28 **************************************************************************/
29 /*
30 * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
31 * Keith Whitwell <keithw-at-tungstengraphics-dot-com>
32 * Eric Anholt <eric@anholt.net>
33 */
34
35 #include <xf86drm.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include "glthread.h"
39 #include "errno.h"
40 #include "mtypes.h"
41 #include "dri_bufmgr.h"
42 #include "string.h"
43 #include "imports.h"
44
45 typedef struct _dri_bufmgr_ttm {
46 dri_bufmgr bufmgr;
47
48 int fd;
49 _glthread_Mutex mutex;
50 unsigned int fence_type;
51 unsigned int fence_type_flush;
52 } dri_bufmgr_ttm;
53
54 typedef struct _dri_bo_ttm {
55 dri_bo bo;
56
57 int refcount; /* Protected by bufmgr->mutex */
58 drmBO drm_bo;
59 } dri_bo_ttm;
60
61 typedef struct _dri_fence_ttm
62 {
63 dri_fence fence;
64
65 int refcount; /* Protected by bufmgr->mutex */
66 /** Fence type from when the fence was created, used for later waits */
67 unsigned int type;
68 const char *name;
69 drmFence drm_fence;
70 } dri_fence_ttm;
71
72 #if 0
73 int
74 driFenceSignaled(DriFenceObject * fence, unsigned type)
75 {
76 int signaled;
77 int ret;
78
79 if (fence == NULL)
80 return GL_TRUE;
81
82 _glthread_LOCK_MUTEX(fence->mutex);
83 ret = drmFenceSignaled(bufmgr_ttm->fd, &fence->fence, type, &signaled);
84 _glthread_UNLOCK_MUTEX(fence->mutex);
85 BM_CKFATAL(ret);
86 return signaled;
87 }
88 #endif
89
90 static dri_bo *
91 dri_ttm_alloc(dri_bufmgr *bufmgr, const char *name,
92 unsigned long size, unsigned int alignment, unsigned int flags,
93 unsigned int hint)
94 {
95 dri_bufmgr_ttm *ttm_bufmgr;
96 dri_bo_ttm *ttm_buf;
97 unsigned int pageSize = getpagesize();
98 int ret;
99
100 ttm_bufmgr = (dri_bufmgr_ttm *)bufmgr;
101
102 ttm_buf = malloc(sizeof(*ttm_buf));
103 if (!ttm_buf)
104 return NULL;
105
106 ret = drmBOCreate(ttm_bufmgr->fd, 0, size, alignment / pageSize,
107 NULL, drm_bo_type_dc,
108 flags, hint, &ttm_buf->drm_bo);
109 if (ret != 0) {
110 free(ttm_buf);
111 return NULL;
112 }
113 ttm_buf->bo.size = ttm_buf->drm_bo.size;
114 ttm_buf->bo.offset = ttm_buf->drm_bo.offset;
115 ttm_buf->bo.virtual = NULL;
116 ttm_buf->bo.bufmgr = bufmgr;
117 ttm_buf->refcount = 1;
118
119 return &ttm_buf->bo;
120 }
121
122 static dri_bo *
123 dri_ttm_alloc_static(dri_bufmgr *bufmgr, const char *name,
124 unsigned long offset, unsigned long size, void *virtual,
125 unsigned int flags, unsigned int hint)
126 {
127 dri_bufmgr_ttm *ttm_bufmgr;
128 dri_bo_ttm *ttm_buf;
129 int ret;
130
131 ttm_bufmgr = (dri_bufmgr_ttm *)bufmgr;
132
133 ttm_buf = malloc(sizeof(*ttm_buf));
134 if (!ttm_buf)
135 return NULL;
136
137 ret = drmBOCreate(ttm_bufmgr->fd, offset, size, 0,
138 NULL, drm_bo_type_fake,
139 flags, 0, &ttm_buf->drm_bo);
140 if (ret != 0) {
141 free(ttm_buf);
142 return NULL;
143 }
144 ttm_buf->bo.size = ttm_buf->drm_bo.size;
145 ttm_buf->bo.offset = ttm_buf->drm_bo.offset;
146 ttm_buf->bo.virtual = virtual;
147 ttm_buf->bo.bufmgr = bufmgr;
148 ttm_buf->refcount = 1;
149
150 return &ttm_buf->bo;
151 }
152
153 static void
154 dri_ttm_bo_reference(dri_bo *buf)
155 {
156 dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)buf->bufmgr;
157 dri_bo_ttm *ttm_buf = (dri_bo_ttm *)buf;
158
159 _glthread_LOCK_MUTEX(bufmgr_ttm->mutex);
160 ttm_buf->refcount++;
161 _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
162 }
163
164 static void
165 dri_ttm_bo_unreference(dri_bo *buf)
166 {
167 dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)buf->bufmgr;
168 dri_bo_ttm *ttm_buf = (dri_bo_ttm *)buf;
169
170 if (!buf)
171 return;
172
173 _glthread_LOCK_MUTEX(bufmgr_ttm->mutex);
174 if (--ttm_buf->refcount == 0) {
175 drmBOUnReference(bufmgr_ttm->fd, &ttm_buf->drm_bo);
176 _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
177 free(buf);
178 return;
179 }
180 _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
181 }
182
183 static int
184 dri_ttm_bo_map(dri_bo *buf, GLboolean write_enable)
185 {
186 dri_bufmgr_ttm *bufmgr_ttm;
187 dri_bo_ttm *ttm_buf = (dri_bo_ttm *)buf;
188 unsigned int flags;
189
190 bufmgr_ttm = (dri_bufmgr_ttm *)buf->bufmgr;
191
192 flags = DRM_BO_FLAG_READ;
193 if (write_enable)
194 flags |= DRM_BO_FLAG_WRITE;
195
196 return drmBOMap(bufmgr_ttm->fd, &ttm_buf->drm_bo, flags, 0, &buf->virtual);
197 }
198
199 static int
200 dri_ttm_bo_unmap(dri_bo *buf)
201 {
202 dri_bufmgr_ttm *bufmgr_ttm;
203 dri_bo_ttm *ttm_buf = (dri_bo_ttm *)buf;
204
205 if (buf == NULL)
206 return 0;
207
208 bufmgr_ttm = (dri_bufmgr_ttm *)buf->bufmgr;
209
210 buf->virtual = NULL;
211
212 return drmBOUnmap(bufmgr_ttm->fd, &ttm_buf->drm_bo);
213 }
214
215 static int
216 dri_ttm_validate(dri_bo *buf, unsigned int flags)
217 {
218 dri_bufmgr_ttm *bufmgr_ttm;
219 dri_bo_ttm *ttm_buf = (dri_bo_ttm *)buf;
220 unsigned int mask;
221 int err;
222
223 /* XXX: Sanity-check whether we've already validated this one under
224 * different flags. See drmAddValidateItem().
225 */
226
227 bufmgr_ttm = (dri_bufmgr_ttm *)buf->bufmgr;
228
229 /* Calculate the appropriate mask to pass to the DRM. There appears to be
230 * be a direct relationship to flags, so it's unnecessary to have it passed
231 * in as an argument.
232 */
233 mask = DRM_BO_MASK_MEM;
234 mask |= flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_EXE);
235
236 err = drmBOValidate(bufmgr_ttm->fd, &ttm_buf->drm_bo, flags, mask, 0);
237
238 if (err == 0) {
239 /* XXX: add to fence list for sanity checking */
240 }
241
242 return err;
243 }
244
245 static dri_fence *
246 dri_ttm_fence_validated(dri_bufmgr *bufmgr, const char *name,
247 GLboolean flushed)
248 {
249 dri_fence_ttm *fence_ttm = malloc(sizeof(*fence_ttm));
250 dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)bufmgr;
251 int ret;
252 unsigned int type;
253
254 if (!fence_ttm)
255 return NULL;
256
257 if (flushed)
258 type = bufmgr_ttm->fence_type_flush;
259 else
260 type = bufmgr_ttm->fence_type;
261
262 fence_ttm->refcount = 1;
263 fence_ttm->name = name;
264 fence_ttm->type = type;
265 fence_ttm->fence.bufmgr = bufmgr;
266 ret = drmFenceBuffers(bufmgr_ttm->fd, type, &fence_ttm->drm_fence);
267 if (ret) {
268 free(fence_ttm);
269 return NULL;
270 }
271 return &fence_ttm->fence;
272 }
273
274 static void
275 dri_ttm_fence_reference(dri_fence *fence)
276 {
277 dri_fence_ttm *fence_ttm = (dri_fence_ttm *)fence;
278 dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)fence->bufmgr;
279
280 _glthread_LOCK_MUTEX(bufmgr_ttm->mutex);
281 ++fence_ttm->refcount;
282 _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
283 }
284
285 static void
286 dri_ttm_fence_unreference(dri_fence *fence)
287 {
288 dri_fence_ttm *fence_ttm = (dri_fence_ttm *)fence;
289 dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)fence->bufmgr;
290
291 if (!fence)
292 return;
293
294 _glthread_LOCK_MUTEX(bufmgr_ttm->mutex);
295 if (--fence_ttm->refcount == 0) {
296 drmFenceDestroy(bufmgr_ttm->fd, &fence_ttm->drm_fence);
297 _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
298 free(fence);
299 return;
300 }
301 _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
302 }
303
304 static void
305 dri_ttm_fence_wait(dri_fence *fence)
306 {
307 dri_fence_ttm *fence_ttm = (dri_fence_ttm *)fence;
308 dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)fence->bufmgr;
309 int ret;
310
311 _glthread_LOCK_MUTEX(bufmgr_ttm->mutex);
312 ret = drmFenceWait(bufmgr_ttm->fd, 0, &fence_ttm->drm_fence,
313 fence_ttm->type);
314 _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
315 if (ret != 0) {
316 _mesa_printf("%s:%d: Error %d waiting for fence %s.\n",
317 __FILE__, __LINE__, fence_ttm->name);
318 abort();
319 }
320 }
321
322 /**
323 * Initializes the TTM buffer manager, which uses the kernel to allocate, map,
324 * and manage map buffer objections.
325 *
326 * \param fd File descriptor of the opened DRM device.
327 * \param fence_type Driver-specific fence type used for fences with no flush.
328 * \param fence_type_flush Driver-specific fence type used for fences with a
329 * flush.
330 */
331 dri_bufmgr *
332 dri_bufmgr_ttm_init(int fd, unsigned int fence_type,
333 unsigned int fence_type_flush)
334 {
335 dri_bufmgr_ttm *bufmgr_ttm;
336
337 bufmgr_ttm = malloc(sizeof(*bufmgr_ttm));
338 bufmgr_ttm->fd = fd;
339 bufmgr_ttm->fence_type = fence_type;
340 bufmgr_ttm->fence_type_flush = fence_type_flush;
341 _glthread_INIT_MUTEX(bufmgr_ttm->mutex);
342
343 bufmgr_ttm->bufmgr.bo_alloc = dri_ttm_alloc;
344 bufmgr_ttm->bufmgr.bo_alloc_static = dri_ttm_alloc_static;
345 bufmgr_ttm->bufmgr.bo_reference = dri_ttm_bo_reference;
346 bufmgr_ttm->bufmgr.bo_unreference = dri_ttm_bo_unreference;
347 bufmgr_ttm->bufmgr.bo_map = dri_ttm_bo_map;
348 bufmgr_ttm->bufmgr.bo_unmap = dri_ttm_bo_unmap;
349 bufmgr_ttm->bufmgr.bo_validate = dri_ttm_validate;
350 bufmgr_ttm->bufmgr.fence_validated = dri_ttm_fence_validated;
351 bufmgr_ttm->bufmgr.fence_reference = dri_ttm_fence_reference;
352 bufmgr_ttm->bufmgr.fence_unreference = dri_ttm_fence_unreference;
353 bufmgr_ttm->bufmgr.fence_wait = dri_ttm_fence_wait;
354
355 return &bufmgr_ttm->bufmgr;
356 }