Merge commit 'origin/master' into gallium-0.2
[mesa.git] / src / mesa / drivers / dri / common / dri_bufmgr.c
1 /**************************************************************************
2 *
3 * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * The above copyright notice and this permission notice (including the
23 * next paragraph) shall be included in all copies or substantial portions
24 * of the Software.
25 *
26 *
27 **************************************************************************/
28 /*
29 * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
30 * Keith Whitwell <keithw-at-tungstengraphics-dot-com>
31 */
32
33 #include <xf86drm.h>
34 #include <stdlib.h>
35 #include "glthread.h"
36 #include "errno.h"
37 #include "dri_bufmgr.h"
38 #include "string.h"
39 #include "imports.h"
40 #include "dri_bufpool.h"
41
42 _glthread_DECLARE_STATIC_MUTEX(bmMutex);
43
44 /*
45 * TODO: Introduce fence pools in the same way as
46 * buffer object pools.
47 */
48
49
50
51 typedef struct _DriFenceObject
52 {
53 int fd;
54 _glthread_Mutex mutex;
55 int refCount;
56 const char *name;
57 drmFence fence;
58 } DriFenceObject;
59
60 typedef struct _DriBufferObject
61 {
62 DriBufferPool *pool;
63 _glthread_Mutex mutex;
64 int refCount;
65 const char *name;
66 unsigned flags;
67 unsigned hint;
68 unsigned alignment;
69 void *private;
70 /* user-space buffer: */
71 unsigned userBuffer;
72 void *userData;
73 unsigned userSize;
74 } DriBufferObject;
75
76
77 void
78 bmError(int val, const char *file, const char *function, int line)
79 {
80 _mesa_printf("Fatal video memory manager error \"%s\".\n"
81 "Check kernel logs or set the LIBGL_DEBUG\n"
82 "environment variable to \"verbose\" for more info.\n"
83 "Detected in file %s, line %d, function %s.\n",
84 strerror(-val), file, line, function);
85 #ifndef NDEBUG
86 abort();
87 #else
88 abort();
89 #endif
90 }
91
92 DriFenceObject *
93 driFenceBuffers(int fd, char *name, unsigned flags)
94 {
95 DriFenceObject *fence = (DriFenceObject *) malloc(sizeof(*fence));
96 int ret;
97
98 if (!fence)
99 BM_CKFATAL(-EINVAL);
100
101 _glthread_LOCK_MUTEX(bmMutex);
102 fence->refCount = 1;
103 fence->name = name;
104 fence->fd = fd;
105 _glthread_INIT_MUTEX(fence->mutex);
106 ret = drmFenceBuffers(fd, flags, &fence->fence);
107 _glthread_UNLOCK_MUTEX(bmMutex);
108 if (ret) {
109 free(fence);
110 BM_CKFATAL(ret);
111 }
112 return fence;
113 }
114
115
116 unsigned
117 driFenceType(DriFenceObject * fence)
118 {
119 unsigned ret;
120
121 _glthread_LOCK_MUTEX(bmMutex);
122 ret = fence->fence.flags;
123 _glthread_UNLOCK_MUTEX(bmMutex);
124
125 return ret;
126 }
127
128
129 DriFenceObject *
130 driFenceReference(DriFenceObject * fence)
131 {
132 _glthread_LOCK_MUTEX(bmMutex);
133 ++fence->refCount;
134 _glthread_UNLOCK_MUTEX(bmMutex);
135 return fence;
136 }
137
138 void
139 driFenceUnReference(DriFenceObject * fence)
140 {
141 if (!fence)
142 return;
143
144 _glthread_LOCK_MUTEX(bmMutex);
145 if (--fence->refCount == 0) {
146 drmFenceDestroy(fence->fd, &fence->fence);
147 free(fence);
148 }
149 _glthread_UNLOCK_MUTEX(bmMutex);
150 }
151
152 void
153 driFenceFinish(DriFenceObject * fence, unsigned type, int lazy)
154 {
155 int ret;
156 unsigned flags = (lazy) ? DRM_FENCE_FLAG_WAIT_LAZY : 0;
157
158 _glthread_LOCK_MUTEX(fence->mutex);
159 ret = drmFenceWait(fence->fd, flags, &fence->fence, type);
160 _glthread_UNLOCK_MUTEX(fence->mutex);
161 BM_CKFATAL(ret);
162 }
163
164 int
165 driFenceSignaled(DriFenceObject * fence, unsigned type)
166 {
167 int signaled;
168 int ret;
169
170 if (fence == NULL)
171 return GL_TRUE;
172
173 _glthread_LOCK_MUTEX(fence->mutex);
174 ret = drmFenceSignaled(fence->fd, &fence->fence, type, &signaled);
175 _glthread_UNLOCK_MUTEX(fence->mutex);
176 BM_CKFATAL(ret);
177 return signaled;
178 }
179
180
181 extern drmBO *
182 driBOKernel(struct _DriBufferObject *buf)
183 {
184 drmBO *ret;
185
186 assert(buf->private != NULL);
187 ret = buf->pool->kernel(buf->pool, buf->private);
188 if (!ret)
189 BM_CKFATAL(-EINVAL);
190
191 return ret;
192 }
193
194 void
195 driBOWaitIdle(struct _DriBufferObject *buf, int lazy)
196 {
197 struct _DriBufferPool *pool;
198 void *priv;
199
200 _glthread_LOCK_MUTEX(buf->mutex);
201 pool = buf->pool;
202 priv = buf->private;
203 _glthread_UNLOCK_MUTEX(buf->mutex);
204
205 assert(priv != NULL);
206 BM_CKFATAL(buf->pool->waitIdle(pool, priv, lazy));
207 }
208
209 void *
210 driBOMap(struct _DriBufferObject *buf, unsigned flags, unsigned hint)
211 {
212 if (buf->userBuffer) {
213 return buf->userData;
214 }
215 else {
216 void *virtual;
217
218 assert(buf->private != NULL);
219
220 _glthread_LOCK_MUTEX(buf->mutex);
221 BM_CKFATAL(buf->pool->map(buf->pool, buf->private, flags, hint, &virtual));
222 _glthread_UNLOCK_MUTEX(buf->mutex);
223 return virtual;
224 }
225 }
226
227 void
228 driBOUnmap(struct _DriBufferObject *buf)
229 {
230 if (!buf->userBuffer) {
231 assert(buf->private != NULL);
232
233 buf->pool->unmap(buf->pool, buf->private);
234 }
235 }
236
237 unsigned long
238 driBOOffset(struct _DriBufferObject *buf)
239 {
240 unsigned long ret;
241
242 assert(buf->private != NULL);
243
244 _glthread_LOCK_MUTEX(buf->mutex);
245 ret = buf->pool->offset(buf->pool, buf->private);
246 _glthread_UNLOCK_MUTEX(buf->mutex);
247 return ret;
248 }
249
250 unsigned
251 driBOFlags(struct _DriBufferObject *buf)
252 {
253 unsigned ret;
254
255 assert(buf->private != NULL);
256
257 _glthread_LOCK_MUTEX(buf->mutex);
258 ret = buf->pool->flags(buf->pool, buf->private);
259 _glthread_UNLOCK_MUTEX(buf->mutex);
260 return ret;
261 }
262
263 struct _DriBufferObject *
264 driBOReference(struct _DriBufferObject *buf)
265 {
266 _glthread_LOCK_MUTEX(bmMutex);
267 if (++buf->refCount == 1) {
268 BM_CKFATAL(-EINVAL);
269 }
270 _glthread_UNLOCK_MUTEX(bmMutex);
271 return buf;
272 }
273
274 void
275 driBOUnReference(struct _DriBufferObject *buf)
276 {
277 int tmp;
278
279 if (!buf)
280 return;
281
282 _glthread_LOCK_MUTEX(bmMutex);
283 tmp = --buf->refCount;
284 _glthread_UNLOCK_MUTEX(bmMutex);
285 if (!tmp) {
286 if (buf->private)
287 buf->pool->destroy(buf->pool, buf->private);
288 free(buf);
289 }
290 }
291
292 void
293 driBOData(struct _DriBufferObject *buf,
294 unsigned size, const void *data, unsigned flags)
295 {
296 void *virtual;
297 int newBuffer;
298 struct _DriBufferPool *pool;
299
300 assert(!buf->userBuffer); /* XXX just do a memcpy? */
301
302 _glthread_LOCK_MUTEX(buf->mutex);
303 pool = buf->pool;
304 if (!pool->create) {
305 _mesa_error(NULL, GL_INVALID_OPERATION,
306 "driBOData called on invalid buffer\n");
307 BM_CKFATAL(-EINVAL);
308 }
309 newBuffer = !buf->private || (pool->size(pool, buf->private) < size) ||
310 pool->map(pool, buf->private, DRM_BO_FLAG_WRITE,
311 DRM_BO_HINT_DONT_BLOCK, &virtual);
312
313 if (newBuffer) {
314 if (buf->private)
315 pool->destroy(pool, buf->private);
316 if (!flags)
317 flags = buf->flags;
318 buf->private = pool->create(pool, size, flags, DRM_BO_HINT_DONT_FENCE,
319 buf->alignment);
320 if (!buf->private)
321 BM_CKFATAL(-ENOMEM);
322 BM_CKFATAL(pool->map(pool, buf->private,
323 DRM_BO_FLAG_WRITE,
324 DRM_BO_HINT_DONT_BLOCK, &virtual));
325 }
326
327 if (data != NULL)
328 memcpy(virtual, data, size);
329
330 BM_CKFATAL(pool->unmap(pool, buf->private));
331 _glthread_UNLOCK_MUTEX(buf->mutex);
332 }
333
334 void
335 driBOSubData(struct _DriBufferObject *buf,
336 unsigned long offset, unsigned long size, const void *data)
337 {
338 void *virtual;
339
340 assert(!buf->userBuffer); /* XXX just do a memcpy? */
341
342 _glthread_LOCK_MUTEX(buf->mutex);
343 if (size && data) {
344 BM_CKFATAL(buf->pool->map(buf->pool, buf->private,
345 DRM_BO_FLAG_WRITE, 0, &virtual));
346 memcpy((unsigned char *) virtual + offset, data, size);
347 BM_CKFATAL(buf->pool->unmap(buf->pool, buf->private));
348 }
349 _glthread_UNLOCK_MUTEX(buf->mutex);
350 }
351
352 void
353 driBOGetSubData(struct _DriBufferObject *buf,
354 unsigned long offset, unsigned long size, void *data)
355 {
356 void *virtual;
357
358 assert(!buf->userBuffer); /* XXX just do a memcpy? */
359
360 _glthread_LOCK_MUTEX(buf->mutex);
361 if (size && data) {
362 BM_CKFATAL(buf->pool->map(buf->pool, buf->private,
363 DRM_BO_FLAG_READ, 0, &virtual));
364 memcpy(data, (unsigned char *) virtual + offset, size);
365 BM_CKFATAL(buf->pool->unmap(buf->pool, buf->private));
366 }
367 _glthread_UNLOCK_MUTEX(buf->mutex);
368 }
369
370 void
371 driBOSetStatic(struct _DriBufferObject *buf,
372 unsigned long offset,
373 unsigned long size, void *virtual, unsigned flags)
374 {
375 assert(!buf->userBuffer); /* XXX what to do? */
376
377 _glthread_LOCK_MUTEX(buf->mutex);
378 if (buf->private != NULL) {
379 _mesa_error(NULL, GL_INVALID_OPERATION,
380 "Invalid buffer for setStatic\n");
381 BM_CKFATAL(-EINVAL);
382 }
383 if (buf->pool->setstatic == NULL) {
384 _mesa_error(NULL, GL_INVALID_OPERATION,
385 "Invalid buffer pool for setStatic\n");
386 BM_CKFATAL(-EINVAL);
387 }
388
389 if (!flags)
390 flags = buf->flags;
391
392 buf->private = buf->pool->setstatic(buf->pool, offset, size,
393 virtual, flags);
394 if (!buf->private) {
395 _mesa_error(NULL, GL_OUT_OF_MEMORY,
396 "Invalid buffer pool for setStatic\n");
397 BM_CKFATAL(-ENOMEM);
398 }
399 _glthread_UNLOCK_MUTEX(buf->mutex);
400 }
401
402
403
404 void
405 driGenBuffers(struct _DriBufferPool *pool,
406 const char *name,
407 unsigned n,
408 struct _DriBufferObject *buffers[],
409 unsigned alignment, unsigned flags, unsigned hint)
410 {
411 struct _DriBufferObject *buf;
412 int i;
413
414 flags = (flags) ? flags : DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM |
415 DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE;
416
417
418 for (i = 0; i < n; ++i) {
419 buf = (struct _DriBufferObject *) calloc(1, sizeof(*buf));
420 if (!buf)
421 BM_CKFATAL(-ENOMEM);
422
423 _glthread_INIT_MUTEX(buf->mutex);
424 _glthread_LOCK_MUTEX(buf->mutex);
425 _glthread_LOCK_MUTEX(bmMutex);
426 buf->refCount = 1;
427 _glthread_UNLOCK_MUTEX(bmMutex);
428 buf->flags = flags;
429 buf->hint = hint;
430 buf->name = name;
431 buf->alignment = alignment;
432 buf->pool = pool;
433 _glthread_UNLOCK_MUTEX(buf->mutex);
434 buffers[i] = buf;
435 }
436 }
437
438 void
439 driGenUserBuffer(struct _DriBufferPool *pool,
440 const char *name,
441 struct _DriBufferObject **buffers,
442 void *ptr, unsigned bytes)
443 {
444 const unsigned alignment = 1, flags = 0, hint = 0;
445
446 driGenBuffers(pool, name, 1, buffers, alignment, flags, hint);
447
448 (*buffers)->userBuffer = 1;
449 (*buffers)->userData = ptr;
450 (*buffers)->userSize = bytes;
451 }
452
453
454 void
455 driDeleteBuffers(unsigned n, struct _DriBufferObject *buffers[])
456 {
457 int i;
458
459 for (i = 0; i < n; ++i) {
460 driBOUnReference(buffers[i]);
461 }
462 }
463
464
465 void
466 driInitBufMgr(int fd)
467 {
468 ;
469 }
470
471
472 void
473 driBOCreateList(int target, drmBOList * list)
474 {
475 _glthread_LOCK_MUTEX(bmMutex);
476 BM_CKFATAL(drmBOCreateList(target, list));
477 _glthread_UNLOCK_MUTEX(bmMutex);
478 }
479
480 void
481 driBOResetList(drmBOList * list)
482 {
483 _glthread_LOCK_MUTEX(bmMutex);
484 BM_CKFATAL(drmBOResetList(list));
485 _glthread_UNLOCK_MUTEX(bmMutex);
486 }
487
488 void
489 driBOAddListItem(drmBOList * list, struct _DriBufferObject *buf,
490 unsigned flags, unsigned mask)
491 {
492 int newItem;
493
494 _glthread_LOCK_MUTEX(buf->mutex);
495 _glthread_LOCK_MUTEX(bmMutex);
496 BM_CKFATAL(drmAddValidateItem(list, driBOKernel(buf),
497 flags, mask, &newItem));
498 _glthread_UNLOCK_MUTEX(bmMutex);
499
500 /*
501 * Tell userspace pools to validate the buffer. This should be a
502 * noop if the pool is already validated.
503 * FIXME: We should have a list for this as well.
504 */
505
506 if (buf->pool->validate) {
507 BM_CKFATAL(buf->pool->validate(buf->pool, buf->private));
508 }
509
510 _glthread_UNLOCK_MUTEX(buf->mutex);
511 }
512
513 void
514 driBOFence(struct _DriBufferObject *buf, struct _DriFenceObject *fence)
515 {
516 _glthread_LOCK_MUTEX(buf->mutex);
517 BM_CKFATAL(buf->pool->fence(buf->pool, buf->private, fence));
518 _glthread_UNLOCK_MUTEX(buf->mutex);
519
520 }
521
522 void
523 driBOValidateList(int fd, drmBOList * list)
524 {
525 _glthread_LOCK_MUTEX(bmMutex);
526 BM_CKFATAL(drmBOValidateList(fd, list));
527 _glthread_UNLOCK_MUTEX(bmMutex);
528 }
529
530 void
531 driPoolTakeDown(struct _DriBufferPool *pool)
532 {
533 pool->takeDown(pool);
534
535 }