1 /**************************************************************************
3 * Copyright © 2007 Red Hat Inc.
4 * Copyright © 2007 Intel Corporation
5 * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
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:
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.
24 * The above copyright notice and this permission notice (including the
25 * next paragraph) shall be included in all copies or substantial portions
29 **************************************************************************/
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>
43 #include "dri_bufmgr.h"
49 #include "intel_bufmgr_ttm.h"
51 #define BUFMGR_DEBUG 0
53 struct intel_reloc_info
66 struct drm_i915_op_arg bo_arg;
69 void (*destroy)(void *);
73 struct intel_bo_reloc_list
80 struct intel_bo_reloc_node
84 uint32_t nr_reloc_types;
85 struct intel_bo_reloc_list type_list;
88 struct intel_bo_list {
91 void (*destroy)(void *node);
94 typedef struct _dri_bufmgr_ttm {
98 _glthread_Mutex mutex;
99 unsigned int fence_type;
100 unsigned int fence_type_flush;
103 /** ttm relocation list */
104 struct intel_bo_list list;
105 struct intel_bo_list reloc_list;
109 typedef struct _dri_bo_ttm {
112 int refcount; /* Protected by bufmgr->mutex */
117 typedef struct _dri_fence_ttm
121 int refcount; /* Protected by bufmgr->mutex */
128 intel_bo_free_list(struct intel_bo_list *list)
130 struct intel_bo_node *node;
134 while(l != &list->list) {
136 node = DRMLISTENTRY(struct intel_bo_node, l, head);
144 generic_destroy(void *nodep)
150 intel_create_bo_list(int numTarget, struct intel_bo_list *list,
151 void (*destroy)(void *))
153 DRMINITLISTHEAD(&list->list);
154 list->numCurrent = 0;
156 list->destroy = destroy;
158 list->destroy = generic_destroy;
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)
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;
177 for (l = list->list.next; l != &list->list; l = l->next) {
178 node = DRMLISTENTRY(struct intel_bo_node, l, head);
187 *prevNext = (unsigned long) arg;
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;
199 for (rl = reloc_list->list.next; rl != &reloc_list->list;
202 rl_node = DRMLISTENTRY(struct intel_bo_reloc_node, rl, head);
204 if (rl_node->handle == node->buf->handle) {
205 arg->reloc_handle = rl_node->type_list.buf.handle;
219 intel_free_validate_list(int fd, struct intel_bo_list *list)
221 struct intel_bo_node *node;
224 for (l = list->list.next; l != &list->list; l = l->next) {
225 node = DRMLISTENTRY(struct intel_bo_node, l, head);
228 (*node->destroy)(node->priv);
234 intel_free_reloc_list(int fd, struct intel_bo_list *reloc_list)
236 struct intel_bo_reloc_node *reloc_node;
237 drmMMListHead *rl, *tmp;
239 for (rl = reloc_list->list.next, tmp = rl->next; rl != &reloc_list->list;
240 rl = tmp, tmp = rl->next)
242 reloc_node = DRMLISTENTRY(struct intel_bo_reloc_node, rl, head);
246 if (reloc_node->nr_reloc_types > 1) {
250 drmBOUnmap(fd, &reloc_node->type_list.buf);
251 drmBOUnreference(fd, &reloc_node->type_list.buf);
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 *))
261 struct intel_bo_node *node, *cur;
265 drmBO *buf_bo = &((dri_bo_ttm *)buf)->drm_bo;
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) {
278 cur = drmMalloc(sizeof(*cur));
286 cur->destroy = destroy_cb;
289 DRMLISTADDTAIL(&cur->head, &list->list);
291 uint64_t memMask = (cur->mask | mask) & DRM_BO_MASK_MEM;
292 uint64_t memFlags = cur->flags & flags & memMask;
297 if (mask & cur->mask & ~DRM_BO_MASK_MEM & (cur->flags ^ flags)) {
301 cur->flags = memFlags | ((cur->flags | flags) &
302 cur->mask & ~DRM_BO_MASK_MEM);
309 #define RELOC_BUF_SIZE(x) ((I915_RELOC_HEADER + x * I915_RELOC0_STRIDE) * \
313 intel_create_new_reloc_type_list(int fd, struct intel_bo_reloc_list *cur_type,
318 /* should allocate a drmBO here */
319 ret = drmBOCreate(fd, RELOC_BUF_SIZE(max_relocs), 0,
321 DRM_BO_FLAG_MEM_LOCAL |
324 DRM_BO_FLAG_MAPPABLE |
330 ret = drmBOMap(fd, &cur_type->buf,
331 DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE,
332 0, (void **)&cur_type->relocs);
339 intel_add_validate_reloc(int fd, struct intel_bo_list *reloc_list,
340 struct intel_reloc_info *reloc_info,
343 struct intel_bo_reloc_node *rl_node, *cur;
344 drmMMListHead *rl, *l;
346 uint32_t *reloc_start;
348 struct intel_bo_reloc_list *cur_type;
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) {
362 cur = malloc(sizeof(*cur));
366 cur->nr_reloc_types = 1;
367 cur->handle = reloc_info->handle;
368 cur_type = &cur->type_list;
370 DRMINITLISTHEAD(&cur->type_list.head);
371 ret = intel_create_new_reloc_type_list(fd, cur_type, max_relocs);
375 DRMLISTADDTAIL(&cur->head, &reloc_list->list);
377 cur_type->relocs[0] = 0 | (reloc_info->type << 16);
378 cur_type->relocs[1] = 0; // next reloc buffer handle is 0
382 if ((cur->type_list.relocs[0] >> 16) == reloc_info->type) {
383 cur_type = &cur->type_list;
386 for (l = cur->type_list.head.next; l != &cur->type_list.head;
389 cur_type = DRMLISTENTRY(struct intel_bo_reloc_list, l, head);
390 if (((cur_type->relocs[0] >> 16) & 0xffff) == reloc_info->type)
396 /* didn't find the relocation type */
398 cur_type = malloc(sizeof(*cur_type));
403 ret = intel_create_new_reloc_type_list(fd, cur_type, max_relocs);
404 DRMLISTADDTAIL(&cur_type->head, &cur->type_list.head);
406 cur_type->relocs[0] = (reloc_info->type << 16);
407 cur_type->relocs[1] = 0;
409 cur->nr_reloc_types++;
413 reloc_start = cur_type->relocs;
415 num_relocs = (reloc_start[0] & 0xffff);
417 reloc_start[num_relocs * I915_RELOC0_STRIDE + I915_RELOC_HEADER] =
419 reloc_start[num_relocs * I915_RELOC0_STRIDE + I915_RELOC_HEADER + 1] =
421 reloc_start[num_relocs * I915_RELOC0_STRIDE + I915_RELOC_HEADER + 2] =
424 if (((reloc_start[0] & 0xffff)) > (max_relocs)) {
433 driFenceSignaled(DriFenceObject * fence, unsigned type)
441 _glthread_LOCK_MUTEX(fence->mutex);
442 ret = drmFenceSignaled(bufmgr_ttm->fd, &fence->fence, type, &signaled);
443 _glthread_UNLOCK_MUTEX(fence->mutex);
450 dri_ttm_alloc(dri_bufmgr *bufmgr, const char *name,
451 unsigned long size, unsigned int alignment,
452 uint64_t location_mask)
454 dri_bufmgr_ttm *ttm_bufmgr;
456 unsigned int pageSize = getpagesize();
458 unsigned int flags, hint;
460 ttm_bufmgr = (dri_bufmgr_ttm *)bufmgr;
462 ttm_buf = malloc(sizeof(*ttm_buf));
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.
470 flags = location_mask | DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE |
472 /* No hints we want to use. */
475 ret = drmBOCreate(ttm_bufmgr->fd, size, alignment / pageSize,
476 NULL, flags, hint, &ttm_buf->drm_bo);
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;
489 fprintf(stderr, "bo_create: %p (%s)\n", &ttm_buf->bo, ttm_buf->name);
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.
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)
508 * Returns a dri_bo wrapping the given buffer object handle.
510 * This can be used when one application needs to pass a buffer object
514 intel_ttm_bo_create_from_handle(dri_bufmgr *bufmgr, const char *name,
517 dri_bufmgr_ttm *ttm_bufmgr;
521 ttm_bufmgr = (dri_bufmgr_ttm *)bufmgr;
523 ttm_buf = malloc(sizeof(*ttm_buf));
527 ret = drmBOReference(ttm_bufmgr->fd, handle, &ttm_buf->drm_bo);
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;
540 fprintf(stderr, "bo_create_from_handle: %p %08x (%s)\n",
541 &ttm_buf->bo, handle, ttm_buf->name);
548 dri_ttm_bo_reference(dri_bo *buf)
550 dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)buf->bufmgr;
551 dri_bo_ttm *ttm_buf = (dri_bo_ttm *)buf;
553 _glthread_LOCK_MUTEX(bufmgr_ttm->mutex);
555 _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
559 dri_ttm_bo_unreference(dri_bo *buf)
561 dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)buf->bufmgr;
562 dri_bo_ttm *ttm_buf = (dri_bo_ttm *)buf;
567 _glthread_LOCK_MUTEX(bufmgr_ttm->mutex);
568 if (--ttm_buf->refcount == 0) {
571 ret = drmBOUnreference(bufmgr_ttm->fd, &ttm_buf->drm_bo);
573 fprintf(stderr, "drmBOUnreference failed (%s): %s\n",
574 ttm_buf->name, strerror(-ret));
577 fprintf(stderr, "bo_unreference final: %p (%s)\n",
578 &ttm_buf->bo, ttm_buf->name);
580 _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
584 _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
588 dri_ttm_bo_map(dri_bo *buf, GLboolean write_enable)
590 dri_bufmgr_ttm *bufmgr_ttm;
591 dri_bo_ttm *ttm_buf = (dri_bo_ttm *)buf;
594 bufmgr_ttm = (dri_bufmgr_ttm *)buf->bufmgr;
596 flags = DRM_BO_FLAG_READ;
598 flags |= DRM_BO_FLAG_WRITE;
600 assert(buf->virtual == NULL);
603 fprintf(stderr, "bo_map: %p (%s)\n", &ttm_buf->bo, ttm_buf->name);
606 return drmBOMap(bufmgr_ttm->fd, &ttm_buf->drm_bo, flags, 0, &buf->virtual);
610 dri_ttm_bo_unmap(dri_bo *buf)
612 dri_bufmgr_ttm *bufmgr_ttm;
613 dri_bo_ttm *ttm_buf = (dri_bo_ttm *)buf;
618 bufmgr_ttm = (dri_bufmgr_ttm *)buf->bufmgr;
620 assert(buf->virtual != NULL);
625 fprintf(stderr, "bo_unmap: %p (%s)\n", &ttm_buf->bo, ttm_buf->name);
628 return drmBOUnmap(bufmgr_ttm->fd, &ttm_buf->drm_bo);
632 * Returns a dri_bo wrapping the given buffer object handle.
634 * This can be used when one application needs to pass a buffer object
638 intel_ttm_fence_create_from_arg(dri_bufmgr *bufmgr, const char *name,
639 drm_fence_arg_t *arg)
641 dri_bufmgr_ttm *ttm_bufmgr;
642 dri_fence_ttm *ttm_fence;
644 ttm_bufmgr = (dri_bufmgr_ttm *)bufmgr;
646 ttm_fence = malloc(sizeof(*ttm_fence));
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;
657 ttm_fence->fence.bufmgr = bufmgr;
658 ttm_fence->name = name;
659 ttm_fence->refcount = 1;
662 fprintf(stderr, "fence_create_from_handle: %p (%s)\n", &ttm_fence->fence,
666 return &ttm_fence->fence;
671 dri_ttm_fence_reference(dri_fence *fence)
673 dri_fence_ttm *fence_ttm = (dri_fence_ttm *)fence;
674 dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)fence->bufmgr;
676 _glthread_LOCK_MUTEX(bufmgr_ttm->mutex);
677 ++fence_ttm->refcount;
678 _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
680 fprintf(stderr, "fence_reference: %p (%s)\n", &fence_ttm->fence,
686 dri_ttm_fence_unreference(dri_fence *fence)
688 dri_fence_ttm *fence_ttm = (dri_fence_ttm *)fence;
689 dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)fence->bufmgr;
695 fprintf(stderr, "fence_unreference: %p (%s)\n", &fence_ttm->fence,
698 _glthread_LOCK_MUTEX(bufmgr_ttm->mutex);
699 if (--fence_ttm->refcount == 0) {
702 ret = drmFenceUnreference(bufmgr_ttm->fd, &fence_ttm->drm_fence);
704 fprintf(stderr, "drmFenceUnreference failed (%s): %s\n",
705 fence_ttm->name, strerror(-ret));
708 _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
712 _glthread_UNLOCK_MUTEX(bufmgr_ttm->mutex);
716 dri_ttm_fence_wait(dri_fence *fence)
718 dri_fence_ttm *fence_ttm = (dri_fence_ttm *)fence;
719 dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)fence->bufmgr;
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);
726 _mesa_printf("%s:%d: Error %d waiting for fence %s.\n",
727 __FILE__, __LINE__, ret, fence_ttm->name);
732 fprintf(stderr, "fence_wait: %p (%s)\n", &fence_ttm->fence,
738 dri_bufmgr_ttm_destroy(dri_bufmgr *bufmgr)
740 dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)bufmgr;
742 intel_bo_free_list(&bufmgr_ttm->list);
743 intel_bo_free_list(&bufmgr_ttm->reloc_list);
745 _glthread_DESTROY_MUTEX(bufmgr_ttm->mutex);
751 intel_dribo_destroy_callback(void *priv)
753 dri_bo *dribo = priv;
756 dri_bo_unreference(dribo);
760 dri_ttm_emit_reloc(dri_bo *reloc_buf, uint64_t flags, GLuint delta,
761 GLuint offset, dri_bo *target_buf)
763 dri_bo_ttm *ttm_buf = (dri_bo_ttm *)reloc_buf;
764 dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)reloc_buf->bufmgr;
766 struct intel_reloc_info reloc;
770 mask = DRM_BO_MASK_MEM;
771 mask |= flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_EXE);
773 ret = intel_add_validate_buffer(&bufmgr_ttm->list, target_buf, flags, mask,
774 &newItem, intel_dribo_destroy_callback);
779 dri_bo_reference(target_buf);
781 reloc.type = I915_RELOC_TYPE_0;
782 reloc.reloc = offset;
784 reloc.index = newItem;
785 reloc.handle = ttm_buf->drm_bo.handle;
787 intel_add_validate_reloc(bufmgr_ttm->fd, &bufmgr_ttm->reloc_list, &reloc,
788 bufmgr_ttm->max_relocs);
793 dri_ttm_process_reloc(dri_bo *batch_buf, GLuint *count)
795 dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)batch_buf->bufmgr;
799 dri_bo_unmap(batch_buf);
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,
806 ptr = intel_setup_validate_list(bufmgr_ttm->fd, &bufmgr_ttm->list,
807 &bufmgr_ttm->reloc_list, count);
813 dri_ttm_post_submit(dri_bo *batch_buf, dri_fence **last_fence)
815 dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)batch_buf->bufmgr;
817 intel_free_validate_list(bufmgr_ttm->fd, &bufmgr_ttm->list);
818 intel_free_reloc_list(bufmgr_ttm->fd, &bufmgr_ttm->reloc_list);
820 intel_bo_free_list(&bufmgr_ttm->list);
824 * Initializes the TTM buffer manager, which uses the kernel to allocate, map,
825 * and manage map buffer objections.
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
833 intel_bufmgr_ttm_init(int fd, unsigned int fence_type,
834 unsigned int fence_type_flush, int batch_size)
836 dri_bufmgr_ttm *bufmgr_ttm;
838 bufmgr_ttm = malloc(sizeof(*bufmgr_ttm));
840 bufmgr_ttm->fence_type = fence_type;
841 bufmgr_ttm->fence_type_flush = fence_type_flush;
842 _glthread_INIT_MUTEX(bufmgr_ttm->mutex);
844 /* lets go with one relocation per every four dwords - purely heuristic */
845 bufmgr_ttm->max_relocs = batch_size / sizeof(uint32_t) / 4;
847 intel_create_bo_list(10, &bufmgr_ttm->list, NULL);
848 intel_create_bo_list(1, &bufmgr_ttm->reloc_list, NULL);
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;
864 return &bufmgr_ttm->bufmgr;