OSDN Git Service

[intel] Fix the type and naming of the flags/mask args to TTM functions.
[android-x86/external-mesa.git] / src / mesa / drivers / dri / intel / intel_bufmgr_ttm.c
1 /**************************************************************************
2  *
3  * Copyright © 2007 Red Hat Inc.
4  * Copyright © 2007 Intel Corporation
5  * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
6  * All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the
10  * "Software"), to deal in the Software without restriction, including
11  * without limitation the rights to use, copy, modify, merge, publish,
12  * distribute, sub license, and/or sell copies of the Software, and to
13  * permit persons to whom the Software is furnished to do so, subject to
14  * the following conditions:
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
20  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22  * USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * The above copyright notice and this permission notice (including the
25  * next paragraph) shall be included in all copies or substantial portions
26  * of the Software.
27  *
28  *
29  **************************************************************************/
30 /*
31  * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
32  *          Keith Whitwell <keithw-at-tungstengraphics-dot-com>
33  *          Eric Anholt <eric@anholt.net>
34  *          Dave Airlie <airlied@linux.ie>
35  */
36
37 #include <xf86drm.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include "glthread.h"
41 #include "errno.h"
42 #include "mtypes.h"
43 #include "dri_bufmgr.h"
44 #include "string.h"
45 #include "imports.h"
46
47 #include "i915_drm.h"
48
49 #include "intel_bufmgr_ttm.h"
50
51 #define BUFMGR_DEBUG 0
52
53 struct intel_reloc_info
54 {
55     GLuint type;
56     GLuint reloc;
57     GLuint delta;
58     GLuint index;
59     drm_handle_t handle;
60 };
61
62 struct intel_bo_node
63 {
64     drmMMListHead head;
65     drmBO *buf;
66     struct drm_i915_op_arg bo_arg;
67     uint64_t flags;
68     uint64_t mask;
69     void (*destroy)(void *);
70     void *priv;
71 };
72
73 struct intel_bo_reloc_list
74 {
75     drmMMListHead head;
76     drmBO buf;
77     uint32_t *relocs;
78 };
79
80 struct intel_bo_reloc_node
81 {
82     drmMMListHead head;
83     drm_handle_t handle;
84     uint32_t nr_reloc_types;
85     struct intel_bo_reloc_list type_list;
86 };
87
88 struct intel_bo_list {
89     unsigned numCurrent;
90     drmMMListHead list;
91     void (*destroy)(void *node);
92 };
93
94 typedef struct _dri_bufmgr_ttm {
95     dri_bufmgr bufmgr;
96
97     int fd;
98     _glthread_Mutex mutex;
99     unsigned int fence_type;
100     unsigned int fence_type_flush;
101
102     uint32_t max_relocs;
103     /** ttm relocation list */
104     struct intel_bo_list list;
105     struct intel_bo_list reloc_list;
106
107 } dri_bufmgr_ttm;
108
109 typedef struct _dri_bo_ttm {
110     dri_bo bo;
111
112     int refcount;               /* Protected by bufmgr->mutex */
113     drmBO drm_bo;
114     const char *name;
115 } dri_bo_ttm;
116
117 typedef struct _dri_fence_ttm
118 {
119     dri_fence fence;
120
121     int refcount;               /* Protected by bufmgr->mutex */
122     const char *name;
123     drmFence drm_fence;
124 } dri_fence_ttm;
125
126
127 static void
128 intel_bo_free_list(struct intel_bo_list *list)
129 {
130     struct intel_bo_node *node;
131     drmMMListHead *l;
132
133     l = list->list.next;
134     while(l != &list->list) {
135         DRMLISTDEL(l);
136         node = DRMLISTENTRY(struct intel_bo_node, l, head);
137         list->destroy(node);
138         l = list->list.next;
139         list->numCurrent--;
140     }
141 }
142
143 static void
144 generic_destroy(void *nodep)
145 {
146     free(nodep);
147 }
148
149 static int
150 intel_create_bo_list(int numTarget, struct intel_bo_list *list,
151                      void (*destroy)(void *))
152 {
153     DRMINITLISTHEAD(&list->list);
154     list->numCurrent = 0;
155     if (destroy)
156         list->destroy = destroy;
157     else
158         list->destroy = generic_destroy;
159     return 0;
160 }
161
162
163 static struct drm_i915_op_arg *
164 intel_setup_validate_list(int fd, struct intel_bo_list *list,
165                           struct intel_bo_list *reloc_list, GLuint *count_p)
166 {
167     struct intel_bo_node *node;
168     struct intel_bo_reloc_node *rl_node;
169     drmMMListHead *l, *rl;
170     struct drm_i915_op_arg *arg, *first;
171     struct drm_bo_op_req *req;
172     uint64_t *prevNext = NULL;
173     GLuint count = 0;
174
175     first = NULL;
176
177     for (l = list->list.next; l != &list->list; l = l->next) {
178         node = DRMLISTENTRY(struct intel_bo_node, l, head);
179
180         arg = &node->bo_arg;
181         req = &arg->d.req;
182
183         if (!first)
184             first = arg;
185
186         if (prevNext)
187             *prevNext = (unsigned long) arg;
188
189         memset(arg, 0, sizeof(*arg));
190         prevNext = &arg->next;
191         req->bo_req.handle = node->buf->handle;
192         req->op = drm_bo_validate;
193         req->bo_req.flags = node->flags;
194         req->bo_req.hint = 0;
195         req->bo_req.mask = node->mask;
196         req->bo_req.fence_class = 0; /* Backwards compat. */
197         arg->reloc_handle = 0;
198
199         for (rl = reloc_list->list.next; rl != &reloc_list->list;
200              rl = rl->next)
201         {
202             rl_node = DRMLISTENTRY(struct intel_bo_reloc_node, rl, head);
203
204             if (rl_node->handle == node->buf->handle) {
205                 arg->reloc_handle = rl_node->type_list.buf.handle;
206             }
207         }
208         count++;
209     }
210
211     if (!first)
212         return 0;
213
214     *count_p = count;
215     return first;
216 }
217
218 static void
219 intel_free_validate_list(int fd, struct intel_bo_list *list)
220 {
221     struct intel_bo_node *node;
222     drmMMListHead *l;
223
224     for (l = list->list.next; l != &list->list; l = l->next) {
225         node = DRMLISTENTRY(struct intel_bo_node, l, head);
226
227         if (node->destroy)
228             (*node->destroy)(node->priv);
229
230     }
231 }
232
233 static void
234 intel_free_reloc_list(int fd, struct intel_bo_list *reloc_list)
235 {
236     struct intel_bo_reloc_node *reloc_node;
237     drmMMListHead *rl, *tmp;
238
239     for (rl = reloc_list->list.next, tmp = rl->next; rl != &reloc_list->list;
240          rl = tmp, tmp = rl->next)
241     {
242         reloc_node = DRMLISTENTRY(struct intel_bo_reloc_node, rl, head);
243
244         DRMLISTDEL(rl);
245
246         if (reloc_node->nr_reloc_types > 1) {
247             /* TODO */
248         }
249
250         drmBOUnmap(fd, &reloc_node->type_list.buf);
251         drmBOUnreference(fd, &reloc_node->type_list.buf);
252         free(reloc_node);
253     }
254 }
255
256 static int
257 intel_add_validate_buffer(struct intel_bo_list *list, dri_bo *buf,
258                           uint64_t flags, uint64_t mask,
259                           int *itemLoc, void (*destroy_cb)(void *))
260 {
261     struct intel_bo_node *node, *cur;
262     drmMMListHead *l;
263     int count = 0;
264     int ret = 0;
265     drmBO *buf_bo = &((dri_bo_ttm *)buf)->drm_bo;
266     cur = NULL;
267
268     for (l = list->list.next; l != &list->list; l = l->next) {
269         node = DRMLISTENTRY(struct intel_bo_node, l, head);
270         if (node->buf->handle == buf_bo->handle) {
271             cur = node;
272             break;
273         }
274         count++;
275     }
276
277     if (!cur) {
278         cur = drmMalloc(sizeof(*cur));
279         if (!cur) {
280             return -ENOMEM;
281         }
282         cur->buf = buf_bo;
283         cur->priv = buf;
284         cur->flags = flags;
285         cur->mask = mask;
286         cur->destroy = destroy_cb;
287         ret = 1;
288
289         DRMLISTADDTAIL(&cur->head, &list->list);
290     } else {
291         uint64_t memMask = (cur->mask | mask) & DRM_BO_MASK_MEM;
292         uint64_t memFlags = cur->flags & flags & memMask;
293
294         if (!memFlags) {
295             return -EINVAL;
296         }
297         if (mask & cur->mask & ~DRM_BO_MASK_MEM  & (cur->flags ^ flags)) {
298             return -EINVAL;
299         }
300         cur->mask |= mask;
301         cur->flags = memFlags | ((cur->flags | flags) &
302                                 cur->mask & ~DRM_BO_MASK_MEM);
303     }
304     *itemLoc = count;
305     return ret;
306 }
307
308
309 #define RELOC_BUF_SIZE(x) ((I915_RELOC_HEADER + x * I915_RELOC0_STRIDE) * \
310         sizeof(uint32_t))
311
312 static int
313 intel_create_new_reloc_type_list(int fd, struct intel_bo_reloc_list *cur_type,
314                                  int max_relocs)
315 {
316     int ret;
317
318     /* should allocate a drmBO here */
319     ret = drmBOCreate(fd, RELOC_BUF_SIZE(max_relocs), 0,
320                       NULL,
321                       DRM_BO_FLAG_MEM_LOCAL |
322                       DRM_BO_FLAG_READ |
323                       DRM_BO_FLAG_WRITE |
324                       DRM_BO_FLAG_MAPPABLE |
325                       DRM_BO_FLAG_CACHED,
326                       0, &cur_type->buf);
327     if (ret)
328         return ret;
329
330     ret = drmBOMap(fd, &cur_type->buf,
331                    DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE,
332                    0, (void **)&cur_type->relocs);
333     if (ret)
334         return ret;
335     return 0;
336 }
337
338 static int
339 intel_add_validate_reloc(int fd, struct intel_bo_list *reloc_list,
340                          struct intel_reloc_info *reloc_info,
341                          uint32_t max_relocs)
342 {
343     struct intel_bo_reloc_node *rl_node, *cur;
344     drmMMListHead *rl, *l;
345     int ret = 0;
346     uint32_t *reloc_start;
347     int num_relocs;
348     struct intel_bo_reloc_list *cur_type;
349
350     cur = NULL;
351
352     for (rl = reloc_list->list.next; rl != &reloc_list->list; rl = rl->next) {
353         rl_node = DRMLISTENTRY(struct intel_bo_reloc_node, rl, head);
354         if (rl_node->handle == reloc_info->handle) {
355             cur = rl_node;
356             break;
357         }
358     }
359
360     if (!cur) {
361
362         cur = malloc(sizeof(*cur));
363         if (!cur)
364             return -ENOMEM;
365
366         cur->nr_reloc_types = 1;
367         cur->handle = reloc_info->handle;
368         cur_type = &cur->type_list;
369
370         DRMINITLISTHEAD(&cur->type_list.head);
371         ret = intel_create_new_reloc_type_list(fd, cur_type, max_relocs);
372         if (ret) {
373             return -1;
374         }
375         DRMLISTADDTAIL(&cur->head, &reloc_list->list);
376
377         cur_type->relocs[0] = 0 | (reloc_info->type << 16);
378         cur_type->relocs[1] = 0; // next reloc buffer handle is 0
379
380     } else {
381         int found = 0;
382         if ((cur->type_list.relocs[0] >> 16) == reloc_info->type) {
383                 cur_type = &cur->type_list;
384                 found = 1;
385         } else {
386             for (l = cur->type_list.head.next; l != &cur->type_list.head;
387                  l = l->next)
388             {
389                 cur_type = DRMLISTENTRY(struct intel_bo_reloc_list, l, head);
390                 if (((cur_type->relocs[0] >> 16) & 0xffff) == reloc_info->type)
391                     found = 1;
392                 break;
393             }
394         }
395
396         /* didn't find the relocation type */
397         if (!found) {
398             cur_type = malloc(sizeof(*cur_type));
399             if (!cur_type) {
400                 return -ENOMEM;
401             }
402
403             ret = intel_create_new_reloc_type_list(fd, cur_type, max_relocs);
404             DRMLISTADDTAIL(&cur_type->head, &cur->type_list.head);
405
406             cur_type->relocs[0] = (reloc_info->type << 16);
407             cur_type->relocs[1] = 0;
408
409             cur->nr_reloc_types++;
410         }
411     }
412
413     reloc_start = cur_type->relocs;
414
415     num_relocs = (reloc_start[0] & 0xffff);
416
417     reloc_start[num_relocs * I915_RELOC0_STRIDE + I915_RELOC_HEADER] =
418        reloc_info->reloc;
419     reloc_start[num_relocs * I915_RELOC0_STRIDE + I915_RELOC_HEADER + 1] =
420        reloc_info->delta;
421     reloc_start[num_relocs * I915_RELOC0_STRIDE + I915_RELOC_HEADER + 2] =
422        reloc_info->index;
423     reloc_start[0]++;
424     if (((reloc_start[0] & 0xffff)) > (max_relocs)) {
425         return -ENOMEM;
426     }
427     return 0;
428 }
429
430
431 #if 0
432 int
433 driFenceSignaled(DriFenceObject * fence, unsigned type)
434 {
435     int signaled;
436     int ret;
437
438     if (fence == NULL)
439         return GL_TRUE;
440
441     _glthread_LOCK_MUTEX(fence->mutex);
442     ret = drmFenceSignaled(bufmgr_ttm->fd, &fence->fence, type, &signaled);
443     _glthread_UNLOCK_MUTEX(fence->mutex);
444     BM_CKFATAL(ret);
445     return signaled;
446 }
447 #endif
448
449 static dri_bo *
450 dri_ttm_alloc(dri_bufmgr *bufmgr, const char *name,
451               unsigned long size, unsigned int alignment,
452               uint64_t location_mask)
453 {
454     dri_bufmgr_ttm *ttm_bufmgr;
455     dri_bo_ttm *ttm_buf;
456     unsigned int pageSize = getpagesize();
457     int ret;
458     unsigned int flags, hint;
459
460     ttm_bufmgr = (dri_bufmgr_ttm *)bufmgr;
461
462     ttm_buf = malloc(sizeof(*ttm_buf));
463     if (!ttm_buf)
464         return NULL;
465
466     /* The mask argument doesn't do anything for us that we want other than
467      * determine which pool (TTM or local) the buffer is allocated into, so
468      * just pass all of the allocation class flags.
469      */
470     flags = location_mask | DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE |
471         DRM_BO_FLAG_EXE;
472     /* No hints we want to use. */
473     hint = 0;
474
475     ret = drmBOCreate(ttm_bufmgr->fd, size, alignment / pageSize,
476                       NULL, flags, hint, &ttm_buf->drm_bo);
477     if (ret != 0) {
478         free(ttm_buf);
479         return NULL;
480     }
481     ttm_buf->bo.size = ttm_buf->drm_bo.size;
482     ttm_buf->bo.offset = ttm_buf->drm_bo.offset;
483     ttm_buf->bo.virtual = NULL;
484     ttm_buf->bo.bufmgr = bufmgr;
485     ttm_buf->name = name;
486     ttm_buf->refcount = 1;
487
488 #if BUFMGR_DEBUG
489     fprintf(stderr, "bo_create: %p (%s)\n", &ttm_buf->bo, ttm_buf->name);
490 #endif
491
492     return &ttm_buf->bo;
493 }
494
495 /* Our TTM backend doesn't allow creation of static buffers, as that requires
496  * privelege for the non-fake case, and the lock in the fake case where we were
497  * working around the X Server not creating buffers and passing handles to us.
498  */
499 static dri_bo *
500 dri_ttm_alloc_static(dri_bufmgr *bufmgr, const char *name,
501                      unsigned long offset, unsigned long size, void *virtual,
502                      uint64_t location_mask)
503 {
504     return NULL;
505 }
506
507 /**
508  * Returns a dri_bo wrapping the given buffer object handle.
509  *
510  * This can be used when one application needs to pass a buffer object
511  * to another.
512  */
513 dri_bo *
514 intel_ttm_bo_create_from_handle(dri_bufmgr *bufmgr, const char *name,
515                               unsigned int handle)
516 {
517     dri_bufmgr_ttm *ttm_bufmgr;
518     dri_bo_ttm *ttm_buf;
519     int ret;
520
521     ttm_bufmgr = (dri_bufmgr_ttm *)bufmgr;
522
523     ttm_buf = malloc(sizeof(*ttm_buf));
524     if (!ttm_buf)
525         return NULL;
526
527     ret = drmBOReference(ttm_bufmgr->fd, handle, &ttm_buf->drm_bo);
528     if (ret != 0) {
529         free(ttm_buf);
530         return NULL;
531     }
532     ttm_buf->bo.size = ttm_buf->drm_bo.size;
533     ttm_buf->bo.offset = ttm_buf->drm_bo.offset;
534     ttm_buf->bo.virtual = NULL;
535     ttm_buf->bo.bufmgr = bufmgr;
536     ttm_buf->name = name;
537     ttm_buf->refcount = 1;
538
539 #if BUFMGR_DEBUG
540     fprintf(stderr, "bo_create_from_handle: %p %08x (%s)\n",
541             &ttm_buf->bo, handle, ttm_buf->name);
542 #endif
543
544     return &ttm_buf->bo;
545 }
546
547 static void
548 dri_ttm_bo_reference(dri_bo *buf)
549 {
550     dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)buf->bufmgr;
551     dri_bo_ttm *ttm_buf = (dri_bo_ttm *)buf;
552
553     _glthread_LOCK_MUTEX(bufmgr_ttm->mutex);
554     ttm_buf->refcount++;
555     _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
556 }
557
558 static void
559 dri_ttm_bo_unreference(dri_bo *buf)
560 {
561     dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)buf->bufmgr;
562     dri_bo_ttm *ttm_buf = (dri_bo_ttm *)buf;
563
564     if (!buf)
565         return;
566
567     _glthread_LOCK_MUTEX(bufmgr_ttm->mutex);
568     if (--ttm_buf->refcount == 0) {
569         int ret;
570
571         ret = drmBOUnreference(bufmgr_ttm->fd, &ttm_buf->drm_bo);
572         if (ret != 0) {
573             fprintf(stderr, "drmBOUnreference failed (%s): %s\n",
574                     ttm_buf->name, strerror(-ret));
575         }
576 #if BUFMGR_DEBUG
577         fprintf(stderr, "bo_unreference final: %p (%s)\n",
578                 &ttm_buf->bo, ttm_buf->name);
579 #endif
580         _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
581         free(buf);
582         return;
583     }
584     _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
585 }
586
587 static int
588 dri_ttm_bo_map(dri_bo *buf, GLboolean write_enable)
589 {
590     dri_bufmgr_ttm *bufmgr_ttm;
591     dri_bo_ttm *ttm_buf = (dri_bo_ttm *)buf;
592     unsigned int flags;
593
594     bufmgr_ttm = (dri_bufmgr_ttm *)buf->bufmgr;
595
596     flags = DRM_BO_FLAG_READ;
597     if (write_enable)
598         flags |= DRM_BO_FLAG_WRITE;
599
600     assert(buf->virtual == NULL);
601
602 #if BUFMGR_DEBUG
603     fprintf(stderr, "bo_map: %p (%s)\n", &ttm_buf->bo, ttm_buf->name);
604 #endif
605
606     return drmBOMap(bufmgr_ttm->fd, &ttm_buf->drm_bo, flags, 0, &buf->virtual);
607 }
608
609 static int
610 dri_ttm_bo_unmap(dri_bo *buf)
611 {
612     dri_bufmgr_ttm *bufmgr_ttm;
613     dri_bo_ttm *ttm_buf = (dri_bo_ttm *)buf;
614
615     if (buf == NULL)
616         return 0;
617
618     bufmgr_ttm = (dri_bufmgr_ttm *)buf->bufmgr;
619
620     assert(buf->virtual != NULL);
621
622     buf->virtual = NULL;
623
624 #if BUFMGR_DEBUG
625     fprintf(stderr, "bo_unmap: %p (%s)\n", &ttm_buf->bo, ttm_buf->name);
626 #endif
627
628     return drmBOUnmap(bufmgr_ttm->fd, &ttm_buf->drm_bo);
629 }
630
631 /**
632  * Returns a dri_bo wrapping the given buffer object handle.
633  *
634  * This can be used when one application needs to pass a buffer object
635  * to another.
636  */
637 dri_fence *
638 intel_ttm_fence_create_from_arg(dri_bufmgr *bufmgr, const char *name,
639                                 drm_fence_arg_t *arg)
640 {
641     dri_bufmgr_ttm *ttm_bufmgr;
642     dri_fence_ttm *ttm_fence;
643
644     ttm_bufmgr = (dri_bufmgr_ttm *)bufmgr;
645
646     ttm_fence = malloc(sizeof(*ttm_fence));
647     if (!ttm_fence)
648         return NULL;
649
650     ttm_fence->drm_fence.handle = arg->handle;
651     ttm_fence->drm_fence.fence_class = arg->fence_class;
652     ttm_fence->drm_fence.type = arg->type;
653     ttm_fence->drm_fence.flags = arg->flags;
654     ttm_fence->drm_fence.signaled = 0;
655     ttm_fence->drm_fence.sequence = arg->sequence;
656
657     ttm_fence->fence.bufmgr = bufmgr;
658     ttm_fence->name = name;
659     ttm_fence->refcount = 1;
660
661 #if BUFMGR_DEBUG
662     fprintf(stderr, "fence_create_from_handle: %p (%s)\n", &ttm_fence->fence,
663             ttm_fence->name);
664 #endif
665
666     return &ttm_fence->fence;
667 }
668
669
670 static void
671 dri_ttm_fence_reference(dri_fence *fence)
672 {
673     dri_fence_ttm *fence_ttm = (dri_fence_ttm *)fence;
674     dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)fence->bufmgr;
675
676     _glthread_LOCK_MUTEX(bufmgr_ttm->mutex);
677     ++fence_ttm->refcount;
678     _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
679 #if BUFMGR_DEBUG
680     fprintf(stderr, "fence_reference: %p (%s)\n", &fence_ttm->fence,
681             fence_ttm->name);
682 #endif
683 }
684
685 static void
686 dri_ttm_fence_unreference(dri_fence *fence)
687 {
688     dri_fence_ttm *fence_ttm = (dri_fence_ttm *)fence;
689     dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)fence->bufmgr;
690
691     if (!fence)
692         return;
693
694 #if BUFMGR_DEBUG
695     fprintf(stderr, "fence_unreference: %p (%s)\n", &fence_ttm->fence,
696             fence_ttm->name);
697 #endif
698     _glthread_LOCK_MUTEX(bufmgr_ttm->mutex);
699     if (--fence_ttm->refcount == 0) {
700         int ret;
701
702         ret = drmFenceUnreference(bufmgr_ttm->fd, &fence_ttm->drm_fence);
703         if (ret != 0) {
704             fprintf(stderr, "drmFenceUnreference failed (%s): %s\n",
705                     fence_ttm->name, strerror(-ret));
706         }
707
708         _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
709         free(fence);
710         return;
711     }
712     _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
713 }
714
715 static void
716 dri_ttm_fence_wait(dri_fence *fence)
717 {
718     dri_fence_ttm *fence_ttm = (dri_fence_ttm *)fence;
719     dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)fence->bufmgr;
720     int ret;
721
722     _glthread_LOCK_MUTEX(bufmgr_ttm->mutex);
723     ret = drmFenceWait(bufmgr_ttm->fd, 0, &fence_ttm->drm_fence, 0);
724     _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
725     if (ret != 0) {
726         _mesa_printf("%s:%d: Error %d waiting for fence %s.\n",
727                      __FILE__, __LINE__, ret, fence_ttm->name);
728         abort();
729     }
730
731 #if BUFMGR_DEBUG
732     fprintf(stderr, "fence_wait: %p (%s)\n", &fence_ttm->fence,
733             fence_ttm->name);
734 #endif
735 }
736
737 static void
738 dri_bufmgr_ttm_destroy(dri_bufmgr *bufmgr)
739 {
740     dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)bufmgr;
741
742     intel_bo_free_list(&bufmgr_ttm->list);
743     intel_bo_free_list(&bufmgr_ttm->reloc_list);
744
745     _glthread_DESTROY_MUTEX(bufmgr_ttm->mutex);
746     free(bufmgr);
747 }
748
749
750 static void
751 intel_dribo_destroy_callback(void *priv)
752 {
753     dri_bo *dribo = priv;
754
755     if (dribo)
756         dri_bo_unreference(dribo);
757 }
758
759 static void
760 dri_ttm_emit_reloc(dri_bo *reloc_buf, uint64_t flags, GLuint delta,
761                    GLuint offset, dri_bo *target_buf)
762 {
763     dri_bo_ttm *ttm_buf = (dri_bo_ttm *)reloc_buf;
764     dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)reloc_buf->bufmgr;
765     int newItem;
766     struct intel_reloc_info reloc;
767     int mask;
768     int ret;
769
770     mask = DRM_BO_MASK_MEM;
771     mask |= flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_EXE);
772
773     ret = intel_add_validate_buffer(&bufmgr_ttm->list, target_buf, flags, mask,
774                                     &newItem, intel_dribo_destroy_callback);
775     if (ret < 0)
776         return;
777
778     if (ret == 1)
779         dri_bo_reference(target_buf);
780
781     reloc.type = I915_RELOC_TYPE_0;
782     reloc.reloc = offset;
783     reloc.delta = delta;
784     reloc.index = newItem;
785     reloc.handle = ttm_buf->drm_bo.handle;
786
787     intel_add_validate_reloc(bufmgr_ttm->fd, &bufmgr_ttm->reloc_list, &reloc,
788                              bufmgr_ttm->max_relocs);
789 }
790
791
792 static void *
793 dri_ttm_process_reloc(dri_bo *batch_buf, GLuint *count)
794 {
795     dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)batch_buf->bufmgr;
796     void *ptr;
797     int itemLoc;
798
799     dri_bo_unmap(batch_buf);
800
801     intel_add_validate_buffer(&bufmgr_ttm->list, batch_buf,
802                               DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_EXE,
803                               DRM_BO_MASK_MEM | DRM_BO_FLAG_EXE,
804                               &itemLoc, NULL);
805
806     ptr = intel_setup_validate_list(bufmgr_ttm->fd, &bufmgr_ttm->list,
807                                     &bufmgr_ttm->reloc_list, count);
808
809     return ptr;
810 }
811
812 static void
813 dri_ttm_post_submit(dri_bo *batch_buf, dri_fence **last_fence)
814 {
815     dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)batch_buf->bufmgr;
816
817     intel_free_validate_list(bufmgr_ttm->fd, &bufmgr_ttm->list);
818     intel_free_reloc_list(bufmgr_ttm->fd, &bufmgr_ttm->reloc_list);
819
820     intel_bo_free_list(&bufmgr_ttm->list);
821 }
822
823 /**
824  * Initializes the TTM buffer manager, which uses the kernel to allocate, map,
825  * and manage map buffer objections.
826  *
827  * \param fd File descriptor of the opened DRM device.
828  * \param fence_type Driver-specific fence type used for fences with no flush.
829  * \param fence_type_flush Driver-specific fence type used for fences with a
830  *        flush.
831  */
832 dri_bufmgr *
833 intel_bufmgr_ttm_init(int fd, unsigned int fence_type,
834                       unsigned int fence_type_flush, int batch_size)
835 {
836     dri_bufmgr_ttm *bufmgr_ttm;
837
838     bufmgr_ttm = malloc(sizeof(*bufmgr_ttm));
839     bufmgr_ttm->fd = fd;
840     bufmgr_ttm->fence_type = fence_type;
841     bufmgr_ttm->fence_type_flush = fence_type_flush;
842     _glthread_INIT_MUTEX(bufmgr_ttm->mutex);
843
844     /* lets go with one relocation per every four dwords - purely heuristic */
845     bufmgr_ttm->max_relocs = batch_size / sizeof(uint32_t) / 4;
846
847     intel_create_bo_list(10, &bufmgr_ttm->list, NULL);
848     intel_create_bo_list(1, &bufmgr_ttm->reloc_list, NULL);
849
850     bufmgr_ttm->bufmgr.bo_alloc = dri_ttm_alloc;
851     bufmgr_ttm->bufmgr.bo_alloc_static = dri_ttm_alloc_static;
852     bufmgr_ttm->bufmgr.bo_reference = dri_ttm_bo_reference;
853     bufmgr_ttm->bufmgr.bo_unreference = dri_ttm_bo_unreference;
854     bufmgr_ttm->bufmgr.bo_map = dri_ttm_bo_map;
855     bufmgr_ttm->bufmgr.bo_unmap = dri_ttm_bo_unmap;
856     bufmgr_ttm->bufmgr.fence_reference = dri_ttm_fence_reference;
857     bufmgr_ttm->bufmgr.fence_unreference = dri_ttm_fence_unreference;
858     bufmgr_ttm->bufmgr.fence_wait = dri_ttm_fence_wait;
859     bufmgr_ttm->bufmgr.destroy = dri_bufmgr_ttm_destroy;
860     bufmgr_ttm->bufmgr.emit_reloc = dri_ttm_emit_reloc;
861     bufmgr_ttm->bufmgr.process_relocs = dri_ttm_process_reloc;
862     bufmgr_ttm->bufmgr.post_submit = dri_ttm_post_submit;
863
864     return &bufmgr_ttm->bufmgr;
865 }
866