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>
46 #include "dri_bufmgr.h"
52 #include "intel_bufmgr_ttm.h"
54 #define DBG(...) do { \
55 if (bufmgr_ttm->bufmgr.debug) \
56 fprintf(stderr, __VA_ARGS__); \
60 * These bits are always specified in each validation
61 * request. Other bits are not supported at this point
62 * as it would require a bit of investigation to figure
63 * out what mask value should be used.
65 #define INTEL_BO_MASK (DRM_BO_MASK_MEM | \
70 struct intel_validate_entry
{
72 struct drm_i915_op_arg bo_arg
;
75 typedef struct _dri_bufmgr_ttm
{
79 unsigned int fence_type
;
80 unsigned int fence_type_flush
;
84 struct intel_validate_entry
*validate_array
;
85 int validate_array_size
;
88 uint32_t *cached_reloc_buf_data
;
92 * Private information associated with a relocation that isn't already stored
93 * in the relocation buffer to be passed to the kernel.
95 struct dri_ttm_reloc
{
97 uint64_t validate_flags
;
98 /** Offset of target_buf after last execution of this relocation entry. */
99 unsigned int last_target_offset
;
102 typedef struct _dri_bo_ttm
{
112 * Index of the buffer within the validation list while preparing a
113 * batchbuffer execution.
117 /** DRM buffer object containing relocation list */
118 uint32_t *reloc_buf_data
;
119 struct dri_ttm_reloc
*relocs
;
122 * Indicates that the buffer may be shared with other processes, so we
123 * can't hold maps beyond when the user does.
127 GLboolean delayed_unmap
;
128 /* Virtual address from the dri_bo_map whose unmap was delayed. */
132 typedef struct _dri_fence_ttm
141 static void dri_ttm_dump_validation_list(dri_bufmgr_ttm
*bufmgr_ttm
)
145 for (i
= 0; i
< bufmgr_ttm
->validate_count
; i
++) {
146 dri_bo
*bo
= bufmgr_ttm
->validate_array
[i
].bo
;
147 dri_bo_ttm
*bo_ttm
= (dri_bo_ttm
*)bo
;
149 if (bo_ttm
->reloc_buf_data
!= NULL
) {
150 for (j
= 0; j
< (bo_ttm
->reloc_buf_data
[0] & 0xffff); j
++) {
151 uint32_t *reloc_entry
= bo_ttm
->reloc_buf_data
+
153 j
* I915_RELOC0_STRIDE
;
154 dri_bo
*target_bo
= bo_ttm
->relocs
[j
].target_buf
;
155 dri_bo_ttm
*target_ttm
= (dri_bo_ttm
*)target_bo
;
157 DBG("%2d: %s@0x%08x -> %s@0x%08lx + 0x%08x\n",
159 bo_ttm
->name
, reloc_entry
[0],
160 target_ttm
->name
, target_bo
->offset
,
164 DBG("%2d: %s\n", i
, bo_ttm
->name
);
170 * Adds the given buffer to the list of buffers to be validated (moved into the
171 * appropriate memory type) with the next batch submission.
173 * If a buffer is validated multiple times in a batch submission, it ends up
174 * with the intersection of the memory type flags and the union of the
178 intel_add_validate_buffer(dri_bo
*buf
,
181 dri_bufmgr_ttm
*bufmgr_ttm
= (dri_bufmgr_ttm
*)buf
->bufmgr
;
182 dri_bo_ttm
*ttm_buf
= (dri_bo_ttm
*)buf
;
184 /* If we delayed doing an unmap to mitigate map/unmap syscall thrashing,
187 if (ttm_buf
->delayed_unmap
) {
188 drmBOUnmap(bufmgr_ttm
->fd
, &ttm_buf
->drm_bo
);
189 ttm_buf
->delayed_unmap
= GL_FALSE
;
192 if (ttm_buf
->validate_index
== -1) {
193 struct intel_validate_entry
*entry
;
194 struct drm_i915_op_arg
*arg
;
195 struct drm_bo_op_req
*req
;
198 /* Extend the array of validation entries as necessary. */
199 if (bufmgr_ttm
->validate_count
== bufmgr_ttm
->validate_array_size
) {
200 int i
, new_size
= bufmgr_ttm
->validate_array_size
* 2;
205 bufmgr_ttm
->validate_array
=
206 realloc(bufmgr_ttm
->validate_array
,
207 sizeof(struct intel_validate_entry
) * new_size
);
208 bufmgr_ttm
->validate_array_size
= new_size
;
210 /* Update pointers for realloced mem. */
211 for (i
= 0; i
< bufmgr_ttm
->validate_count
- 1; i
++) {
212 bufmgr_ttm
->validate_array
[i
].bo_arg
.next
= (unsigned long)
213 &bufmgr_ttm
->validate_array
[i
+ 1].bo_arg
;
217 /* Pick out the new array entry for ourselves */
218 index
= bufmgr_ttm
->validate_count
;
219 ttm_buf
->validate_index
= index
;
220 entry
= &bufmgr_ttm
->validate_array
[index
];
221 bufmgr_ttm
->validate_count
++;
223 /* Fill in array entry */
225 dri_bo_reference(buf
);
227 /* Fill in kernel arg */
228 arg
= &entry
->bo_arg
;
231 memset(arg
, 0, sizeof(*arg
));
232 req
->bo_req
.handle
= ttm_buf
->drm_bo
.handle
;
233 req
->op
= drm_bo_validate
;
234 req
->bo_req
.flags
= flags
;
235 req
->bo_req
.hint
= 0;
236 #ifdef DRM_BO_HINT_PRESUMED_OFFSET
237 /* PRESUMED_OFFSET indicates that all relocations pointing at this
238 * buffer have the correct offset. If any of our relocations don't,
239 * this flag will be cleared off the buffer later in the relocation
242 req
->bo_req
.hint
|= DRM_BO_HINT_PRESUMED_OFFSET
;
243 req
->bo_req
.presumed_offset
= buf
->offset
;
245 req
->bo_req
.mask
= INTEL_BO_MASK
;
246 req
->bo_req
.fence_class
= 0; /* Backwards compat. */
248 if (ttm_buf
->reloc_buf_data
!= NULL
)
249 arg
->reloc_ptr
= (unsigned long)(void *)ttm_buf
->reloc_buf_data
;
253 /* Hook up the linked list of args for the kernel */
256 bufmgr_ttm
->validate_array
[index
- 1].bo_arg
.next
=
260 struct intel_validate_entry
*entry
=
261 &bufmgr_ttm
->validate_array
[ttm_buf
->validate_index
];
262 struct drm_i915_op_arg
*arg
= &entry
->bo_arg
;
263 struct drm_bo_op_req
*req
= &arg
->d
.req
;
264 uint64_t memFlags
= req
->bo_req
.flags
& flags
& DRM_BO_MASK_MEM
;
265 uint64_t modeFlags
= (req
->bo_req
.flags
| flags
) & ~DRM_BO_MASK_MEM
;
267 /* Buffer was already in the validate list. Extend its flags as
273 "%s: No shared memory types between "
274 "0x%16llx and 0x%16llx\n",
275 __FUNCTION__
, req
->bo_req
.flags
, flags
);
278 if (flags
& ~INTEL_BO_MASK
) {
280 "%s: Flags bits 0x%16llx are not supposed to be used in a relocation\n",
281 __FUNCTION__
, flags
& ~INTEL_BO_MASK
);
284 req
->bo_req
.flags
= memFlags
| modeFlags
;
289 #define RELOC_BUF_SIZE(x) ((I915_RELOC_HEADER + x * I915_RELOC0_STRIDE) * \
293 intel_setup_reloc_list(dri_bo
*bo
)
295 dri_bo_ttm
*bo_ttm
= (dri_bo_ttm
*)bo
;
296 dri_bufmgr_ttm
*bufmgr_ttm
= (dri_bufmgr_ttm
*)bo
->bufmgr
;
298 bo_ttm
->relocs
= malloc(sizeof(struct dri_ttm_reloc
) *
299 bufmgr_ttm
->max_relocs
);
301 if (bufmgr_ttm
->cached_reloc_buf_data
!= NULL
) {
302 bo_ttm
->reloc_buf_data
= bufmgr_ttm
->cached_reloc_buf_data
;
304 bufmgr_ttm
->cached_reloc_buf_data
= NULL
;
306 bo_ttm
->reloc_buf_data
= calloc(1, RELOC_BUF_SIZE(bufmgr_ttm
->max_relocs
));
309 /* Initialize the relocation list with the header:
310 * DWORD 0: relocation count
311 * DWORD 1: relocation type
312 * DWORD 2+3: handle to next relocation list (currently none) 64-bits
314 bo_ttm
->reloc_buf_data
[0] = 0;
315 bo_ttm
->reloc_buf_data
[1] = I915_RELOC_TYPE_0
;
316 bo_ttm
->reloc_buf_data
[2] = 0;
317 bo_ttm
->reloc_buf_data
[3] = 0;
324 driFenceSignaled(DriFenceObject
* fence
, unsigned type
)
332 ret
= drmFenceSignaled(bufmgr_ttm
->fd
, &fence
->fence
, type
, &signaled
);
339 dri_ttm_alloc(dri_bufmgr
*bufmgr
, const char *name
,
340 unsigned long size
, unsigned int alignment
,
341 uint64_t location_mask
)
343 dri_bufmgr_ttm
*bufmgr_ttm
= (dri_bufmgr_ttm
*)bufmgr
;
345 unsigned int pageSize
= getpagesize();
350 ttm_buf
= malloc(sizeof(*ttm_buf
));
354 /* The mask argument doesn't do anything for us that we want other than
355 * determine which pool (TTM or local) the buffer is allocated into, so
356 * just pass all of the allocation class flags.
358 flags
= location_mask
| DRM_BO_FLAG_READ
| DRM_BO_FLAG_WRITE
|
360 /* No hints we want to use. */
363 ret
= drmBOCreate(bufmgr_ttm
->fd
, size
, alignment
/ pageSize
,
364 NULL
, flags
, hint
, &ttm_buf
->drm_bo
);
369 ttm_buf
->bo
.size
= ttm_buf
->drm_bo
.size
;
370 ttm_buf
->bo
.offset
= ttm_buf
->drm_bo
.offset
;
371 ttm_buf
->bo
.virtual = NULL
;
372 ttm_buf
->bo
.bufmgr
= bufmgr
;
373 ttm_buf
->name
= name
;
374 ttm_buf
->refcount
= 1;
375 ttm_buf
->reloc_buf_data
= NULL
;
376 ttm_buf
->relocs
= NULL
;
377 ttm_buf
->last_flags
= ttm_buf
->drm_bo
.flags
;
378 ttm_buf
->shared
= GL_FALSE
;
379 ttm_buf
->delayed_unmap
= GL_FALSE
;
380 ttm_buf
->validate_index
= -1;
382 DBG("bo_create: %p (%s) %ldb\n", &ttm_buf
->bo
, ttm_buf
->name
, size
);
387 /* Our TTM backend doesn't allow creation of static buffers, as that requires
388 * privelege for the non-fake case, and the lock in the fake case where we were
389 * working around the X Server not creating buffers and passing handles to us.
392 dri_ttm_alloc_static(dri_bufmgr
*bufmgr
, const char *name
,
393 unsigned long offset
, unsigned long size
, void *virtual,
394 uint64_t location_mask
)
400 * Returns a dri_bo wrapping the given buffer object handle.
402 * This can be used when one application needs to pass a buffer object
406 intel_ttm_bo_create_from_handle(dri_bufmgr
*bufmgr
, const char *name
,
409 dri_bufmgr_ttm
*bufmgr_ttm
= (dri_bufmgr_ttm
*)bufmgr
;
413 ttm_buf
= malloc(sizeof(*ttm_buf
));
417 ret
= drmBOReference(bufmgr_ttm
->fd
, handle
, &ttm_buf
->drm_bo
);
419 fprintf(stderr
, "Couldn't reference %s handle 0x%08x: %s\n",
420 name
, handle
, strerror(-ret
));
424 ttm_buf
->bo
.size
= ttm_buf
->drm_bo
.size
;
425 ttm_buf
->bo
.offset
= ttm_buf
->drm_bo
.offset
;
426 ttm_buf
->bo
.virtual = NULL
;
427 ttm_buf
->bo
.bufmgr
= bufmgr
;
428 ttm_buf
->name
= name
;
429 ttm_buf
->refcount
= 1;
430 ttm_buf
->reloc_buf_data
= NULL
;
431 ttm_buf
->relocs
= NULL
;
432 ttm_buf
->last_flags
= ttm_buf
->drm_bo
.flags
;
433 ttm_buf
->shared
= GL_TRUE
;
434 ttm_buf
->delayed_unmap
= GL_FALSE
;
435 ttm_buf
->validate_index
= -1;
437 DBG("bo_create_from_handle: %p %08x (%s)\n",
438 &ttm_buf
->bo
, handle
, ttm_buf
->name
);
444 dri_ttm_bo_reference(dri_bo
*buf
)
446 dri_bo_ttm
*ttm_buf
= (dri_bo_ttm
*)buf
;
452 dri_ttm_bo_unreference(dri_bo
*buf
)
454 dri_bufmgr_ttm
*bufmgr_ttm
= (dri_bufmgr_ttm
*)buf
->bufmgr
;
455 dri_bo_ttm
*ttm_buf
= (dri_bo_ttm
*)buf
;
460 if (--ttm_buf
->refcount
== 0) {
463 if (ttm_buf
->reloc_buf_data
) {
466 /* Unreference all the target buffers */
467 for (i
= 0; i
< (ttm_buf
->reloc_buf_data
[0] & 0xffff); i
++)
468 dri_bo_unreference(ttm_buf
->relocs
[i
].target_buf
);
469 free(ttm_buf
->relocs
);
471 if (bufmgr_ttm
->cached_reloc_buf_data
== NULL
) {
472 /* Cache a single relocation buffer allocation to avoid
473 * repeated create/map/unmap/destroy for batchbuffer
476 bufmgr_ttm
->cached_reloc_buf_data
= ttm_buf
->reloc_buf_data
;
478 /* Free the kernel BO containing relocation entries */
479 free(ttm_buf
->reloc_buf_data
);
480 ttm_buf
->reloc_buf_data
= NULL
;
484 if (ttm_buf
->delayed_unmap
) {
485 int ret
= drmBOUnmap(bufmgr_ttm
->fd
, &ttm_buf
->drm_bo
);
488 fprintf(stderr
, "%s:%d: Error unmapping buffer %s: %s.\n",
489 __FILE__
, __LINE__
, ttm_buf
->name
, strerror(-ret
));
493 ret
= drmBOUnreference(bufmgr_ttm
->fd
, &ttm_buf
->drm_bo
);
495 fprintf(stderr
, "drmBOUnreference failed (%s): %s\n",
496 ttm_buf
->name
, strerror(-ret
));
498 DBG("bo_unreference final: %p (%s)\n", &ttm_buf
->bo
, ttm_buf
->name
);
506 dri_ttm_bo_map(dri_bo
*buf
, GLboolean write_enable
)
508 dri_bufmgr_ttm
*bufmgr_ttm
;
509 dri_bo_ttm
*ttm_buf
= (dri_bo_ttm
*)buf
;
513 bufmgr_ttm
= (dri_bufmgr_ttm
*)buf
->bufmgr
;
515 flags
= DRM_BO_FLAG_READ
;
517 flags
|= DRM_BO_FLAG_WRITE
;
519 assert(buf
->virtual == NULL
);
521 DBG("bo_map: %p (%s)\n", &ttm_buf
->bo
, ttm_buf
->name
);
523 /* XXX: What about if we're upgrading from READ to WRITE? */
524 if (ttm_buf
->delayed_unmap
) {
525 buf
->virtual = ttm_buf
->saved_virtual
;
529 ret
= drmBOMap(bufmgr_ttm
->fd
, &ttm_buf
->drm_bo
, flags
, 0, &buf
->virtual);
531 fprintf(stderr
, "%s:%d: Error mapping buffer %s: %s .\n",
532 __FILE__
, __LINE__
, ttm_buf
->name
, strerror(-ret
));
539 dri_ttm_bo_unmap(dri_bo
*buf
)
541 dri_bufmgr_ttm
*bufmgr_ttm
;
542 dri_bo_ttm
*ttm_buf
= (dri_bo_ttm
*)buf
;
548 bufmgr_ttm
= (dri_bufmgr_ttm
*)buf
->bufmgr
;
550 assert(buf
->virtual != NULL
);
552 DBG("bo_unmap: %p (%s)\n", &ttm_buf
->bo
, ttm_buf
->name
);
554 if (!ttm_buf
->shared
) {
555 ttm_buf
->saved_virtual
= buf
->virtual;
556 ttm_buf
->delayed_unmap
= GL_TRUE
;
564 ret
= drmBOUnmap(bufmgr_ttm
->fd
, &ttm_buf
->drm_bo
);
566 fprintf(stderr
, "%s:%d: Error unmapping buffer %s: %s.\n",
567 __FILE__
, __LINE__
, ttm_buf
->name
, strerror(-ret
));
574 * Returns a dri_bo wrapping the given buffer object handle.
576 * This can be used when one application needs to pass a buffer object
580 intel_ttm_fence_create_from_arg(dri_bufmgr
*bufmgr
, const char *name
,
581 drm_fence_arg_t
*arg
)
583 dri_bufmgr_ttm
*bufmgr_ttm
= (dri_bufmgr_ttm
*)bufmgr
;
584 dri_fence_ttm
*ttm_fence
;
586 ttm_fence
= malloc(sizeof(*ttm_fence
));
590 ttm_fence
->drm_fence
.handle
= arg
->handle
;
591 ttm_fence
->drm_fence
.fence_class
= arg
->fence_class
;
592 ttm_fence
->drm_fence
.type
= arg
->type
;
593 ttm_fence
->drm_fence
.flags
= arg
->flags
;
594 ttm_fence
->drm_fence
.signaled
= 0;
595 ttm_fence
->drm_fence
.sequence
= arg
->sequence
;
597 ttm_fence
->fence
.bufmgr
= bufmgr
;
598 ttm_fence
->name
= name
;
599 ttm_fence
->refcount
= 1;
601 DBG("fence_create_from_handle: %p (%s)\n",
602 &ttm_fence
->fence
, ttm_fence
->name
);
604 return &ttm_fence
->fence
;
609 dri_ttm_fence_reference(dri_fence
*fence
)
611 dri_fence_ttm
*fence_ttm
= (dri_fence_ttm
*)fence
;
612 dri_bufmgr_ttm
*bufmgr_ttm
= (dri_bufmgr_ttm
*)fence
->bufmgr
;
614 ++fence_ttm
->refcount
;
615 DBG("fence_reference: %p (%s)\n", &fence_ttm
->fence
, fence_ttm
->name
);
619 dri_ttm_fence_unreference(dri_fence
*fence
)
621 dri_fence_ttm
*fence_ttm
= (dri_fence_ttm
*)fence
;
622 dri_bufmgr_ttm
*bufmgr_ttm
= (dri_bufmgr_ttm
*)fence
->bufmgr
;
627 DBG("fence_unreference: %p (%s)\n", &fence_ttm
->fence
, fence_ttm
->name
);
629 if (--fence_ttm
->refcount
== 0) {
632 ret
= drmFenceUnreference(bufmgr_ttm
->fd
, &fence_ttm
->drm_fence
);
634 fprintf(stderr
, "drmFenceUnreference failed (%s): %s\n",
635 fence_ttm
->name
, strerror(-ret
));
644 dri_ttm_fence_wait(dri_fence
*fence
)
646 dri_fence_ttm
*fence_ttm
= (dri_fence_ttm
*)fence
;
647 dri_bufmgr_ttm
*bufmgr_ttm
= (dri_bufmgr_ttm
*)fence
->bufmgr
;
650 ret
= drmFenceWait(bufmgr_ttm
->fd
, DRM_FENCE_FLAG_WAIT_LAZY
, &fence_ttm
->drm_fence
, 0);
652 fprintf(stderr
, "%s:%d: Error waiting for fence %s: %s.\n",
653 __FILE__
, __LINE__
, fence_ttm
->name
, strerror(-ret
));
657 DBG("fence_wait: %p (%s)\n", &fence_ttm
->fence
, fence_ttm
->name
);
661 dri_bufmgr_ttm_destroy(dri_bufmgr
*bufmgr
)
663 dri_bufmgr_ttm
*bufmgr_ttm
= (dri_bufmgr_ttm
*)bufmgr
;
665 if (bufmgr_ttm
->cached_reloc_buf_data
) {
666 free(bufmgr_ttm
->cached_reloc_buf_data
);
669 free(bufmgr_ttm
->validate_array
);
675 * Adds the target buffer to the validation list and adds the relocation
676 * to the reloc_buffer's relocation list.
678 * The relocation entry at the given offset must already contain the
679 * precomputed relocation value, because the kernel will optimize out
680 * the relocation entry write when the buffer hasn't moved from the
681 * last known offset in target_buf.
684 dri_ttm_emit_reloc(dri_bo
*reloc_buf
, uint64_t flags
, GLuint delta
,
685 GLuint offset
, dri_bo
*target_buf
)
687 dri_bufmgr_ttm
*bufmgr_ttm
= (dri_bufmgr_ttm
*)reloc_buf
->bufmgr
;
688 dri_bo_ttm
*reloc_buf_ttm
= (dri_bo_ttm
*)reloc_buf
;
689 dri_bo_ttm
*target_buf_ttm
= (dri_bo_ttm
*)target_buf
;
691 uint32_t *this_reloc
;
693 /* Create a new relocation list if needed */
694 if (reloc_buf_ttm
->reloc_buf_data
== NULL
)
695 intel_setup_reloc_list(reloc_buf
);
697 num_relocs
= reloc_buf_ttm
->reloc_buf_data
[0];
700 assert(num_relocs
< bufmgr_ttm
->max_relocs
);
702 this_reloc
= reloc_buf_ttm
->reloc_buf_data
+ I915_RELOC_HEADER
+
703 num_relocs
* I915_RELOC0_STRIDE
;
705 this_reloc
[0] = offset
;
706 this_reloc
[1] = delta
;
707 this_reloc
[2] = target_buf_ttm
->drm_bo
.handle
; /* To be filled in at exec time */
710 reloc_buf_ttm
->relocs
[num_relocs
].validate_flags
= flags
;
711 reloc_buf_ttm
->relocs
[num_relocs
].target_buf
= target_buf
;
712 dri_bo_reference(target_buf
);
714 reloc_buf_ttm
->reloc_buf_data
[0]++; /* Increment relocation count */
715 /* Check wraparound */
716 assert(reloc_buf_ttm
->reloc_buf_data
[0] != 0);
720 * Walk the tree of relocations rooted at BO and accumulate the list of
721 * validations to be performed and update the relocation buffers with
722 * index values into the validation list.
725 dri_ttm_bo_process_reloc(dri_bo
*bo
)
727 dri_bufmgr_ttm
*bufmgr_ttm
= (dri_bufmgr_ttm
*)bo
->bufmgr
;
728 dri_bo_ttm
*bo_ttm
= (dri_bo_ttm
*)bo
;
729 unsigned int nr_relocs
;
732 if (bo_ttm
->reloc_buf_data
== NULL
)
735 nr_relocs
= bo_ttm
->reloc_buf_data
[0] & 0xffff;
737 for (i
= 0; i
< nr_relocs
; i
++) {
738 struct dri_ttm_reloc
*r
= &bo_ttm
->relocs
[i
];
740 /* Continue walking the tree depth-first. */
741 dri_ttm_bo_process_reloc(r
->target_buf
);
743 /* Add the target to the validate list */
744 intel_add_validate_buffer(r
->target_buf
, r
->validate_flags
);
746 /* Clear the PRESUMED_OFFSET flag from the validate list entry of the
747 * target if this buffer has a stale relocated pointer at it.
749 if (r
->last_target_offset
!= r
->target_buf
->offset
) {
750 dri_bo_ttm
*target_buf_ttm
= (dri_bo_ttm
*)r
->target_buf
;
751 struct intel_validate_entry
*entry
=
752 &bufmgr_ttm
->validate_array
[target_buf_ttm
->validate_index
];
754 entry
->bo_arg
.d
.req
.bo_req
.flags
&= ~DRM_BO_HINT_PRESUMED_OFFSET
;
760 dri_ttm_process_reloc(dri_bo
*batch_buf
, GLuint
*count
)
762 dri_bufmgr_ttm
*bufmgr_ttm
= (dri_bufmgr_ttm
*)batch_buf
->bufmgr
;
764 /* Update indices and set up the validate list. */
765 dri_ttm_bo_process_reloc(batch_buf
);
767 /* Add the batch buffer to the validation list. There are no relocations
770 intel_add_validate_buffer(batch_buf
,
771 DRM_BO_FLAG_MEM_TT
| DRM_BO_FLAG_EXE
);
773 *count
= bufmgr_ttm
->validate_count
;
774 return &bufmgr_ttm
->validate_array
[0].bo_arg
;
778 intel_get_flags_mem_type_string(uint64_t flags
)
780 switch (flags
& DRM_BO_MASK_MEM
) {
781 case DRM_BO_FLAG_MEM_LOCAL
: return "local";
782 case DRM_BO_FLAG_MEM_TT
: return "ttm";
783 case DRM_BO_FLAG_MEM_VRAM
: return "vram";
784 case DRM_BO_FLAG_MEM_PRIV0
: return "priv0";
785 case DRM_BO_FLAG_MEM_PRIV1
: return "priv1";
786 case DRM_BO_FLAG_MEM_PRIV2
: return "priv2";
787 case DRM_BO_FLAG_MEM_PRIV3
: return "priv3";
788 case DRM_BO_FLAG_MEM_PRIV4
: return "priv4";
789 default: return NULL
;
794 intel_get_flags_caching_string(uint64_t flags
)
796 switch (flags
& (DRM_BO_FLAG_CACHED
| DRM_BO_FLAG_CACHED_MAPPED
)) {
798 case DRM_BO_FLAG_CACHED
: return "CU";
799 case DRM_BO_FLAG_CACHED_MAPPED
: return "UC";
800 case DRM_BO_FLAG_CACHED
| DRM_BO_FLAG_CACHED_MAPPED
: return "CC";
801 default: return NULL
;
806 intel_update_buffer_offsets (dri_bufmgr_ttm
*bufmgr_ttm
)
810 for (i
= 0; i
< bufmgr_ttm
->validate_count
; i
++) {
811 dri_bo
*bo
= bufmgr_ttm
->validate_array
[i
].bo
;
812 dri_bo_ttm
*bo_ttm
= (dri_bo_ttm
*)bo
;
813 struct drm_i915_op_arg
*arg
= &bufmgr_ttm
->validate_array
[i
].bo_arg
;
814 struct drm_bo_arg_rep
*rep
= &arg
->d
.rep
;
816 /* Update the flags */
817 if (rep
->bo_info
.flags
!= bo_ttm
->last_flags
) {
818 DBG("BO %s migrated: %s/%s -> %s/%s\n",
820 intel_get_flags_mem_type_string(bo_ttm
->last_flags
),
821 intel_get_flags_caching_string(bo_ttm
->last_flags
),
822 intel_get_flags_mem_type_string(rep
->bo_info
.flags
),
823 intel_get_flags_caching_string(rep
->bo_info
.flags
));
825 bo_ttm
->last_flags
= rep
->bo_info
.flags
;
827 /* Update the buffer offset */
828 if (rep
->bo_info
.offset
!= bo
->offset
) {
829 DBG("BO %s migrated: 0x%08lx -> 0x%08lx\n",
830 bo_ttm
->name
, bo
->offset
, (unsigned long)rep
->bo_info
.offset
);
831 bo
->offset
= rep
->bo_info
.offset
;
837 * Update the last target offset field of relocation entries for PRESUMED_OFFSET
841 dri_ttm_bo_post_submit(dri_bo
*bo
)
843 dri_bo_ttm
*bo_ttm
= (dri_bo_ttm
*)bo
;
844 unsigned int nr_relocs
;
847 if (bo_ttm
->reloc_buf_data
== NULL
)
850 nr_relocs
= bo_ttm
->reloc_buf_data
[0] & 0xffff;
852 for (i
= 0; i
< nr_relocs
; i
++) {
853 struct dri_ttm_reloc
*r
= &bo_ttm
->relocs
[i
];
855 /* Continue walking the tree depth-first. */
856 dri_ttm_bo_post_submit(r
->target_buf
);
858 r
->last_target_offset
= bo
->offset
;
863 dri_ttm_post_submit(dri_bo
*batch_buf
, dri_fence
**last_fence
)
865 dri_bufmgr_ttm
*bufmgr_ttm
= (dri_bufmgr_ttm
*)batch_buf
->bufmgr
;
868 intel_update_buffer_offsets (bufmgr_ttm
);
870 dri_ttm_bo_post_submit(batch_buf
);
872 if (bufmgr_ttm
->bufmgr
.debug
)
873 dri_ttm_dump_validation_list(bufmgr_ttm
);
875 for (i
= 0; i
< bufmgr_ttm
->validate_count
; i
++) {
876 dri_bo
*bo
= bufmgr_ttm
->validate_array
[i
].bo
;
877 dri_bo_ttm
*bo_ttm
= (dri_bo_ttm
*)bo
;
879 /* Disconnect the buffer from the validate list */
880 bo_ttm
->validate_index
= -1;
881 dri_bo_unreference(bo
);
882 bufmgr_ttm
->validate_array
[i
].bo
= NULL
;
884 bufmgr_ttm
->validate_count
= 0;
888 * Initializes the TTM buffer manager, which uses the kernel to allocate, map,
889 * and manage map buffer objections.
891 * \param fd File descriptor of the opened DRM device.
892 * \param fence_type Driver-specific fence type used for fences with no flush.
893 * \param fence_type_flush Driver-specific fence type used for fences with a
897 intel_bufmgr_ttm_init(int fd
, unsigned int fence_type
,
898 unsigned int fence_type_flush
, int batch_size
)
900 dri_bufmgr_ttm
*bufmgr_ttm
;
902 bufmgr_ttm
= calloc(1, sizeof(*bufmgr_ttm
));
904 bufmgr_ttm
->fence_type
= fence_type
;
905 bufmgr_ttm
->fence_type_flush
= fence_type_flush
;
906 bufmgr_ttm
->cached_reloc_buf_data
= NULL
;
908 /* Let's go with one relocation per every 2 dwords (but round down a bit
909 * since a power of two will mean an extra page allocation for the reloc
912 * Every 4 was too few for the blender benchmark.
914 bufmgr_ttm
->max_relocs
= batch_size
/ sizeof(uint32_t) / 2 - 2;
916 bufmgr_ttm
->bufmgr
.bo_alloc
= dri_ttm_alloc
;
917 bufmgr_ttm
->bufmgr
.bo_alloc_static
= dri_ttm_alloc_static
;
918 bufmgr_ttm
->bufmgr
.bo_reference
= dri_ttm_bo_reference
;
919 bufmgr_ttm
->bufmgr
.bo_unreference
= dri_ttm_bo_unreference
;
920 bufmgr_ttm
->bufmgr
.bo_map
= dri_ttm_bo_map
;
921 bufmgr_ttm
->bufmgr
.bo_unmap
= dri_ttm_bo_unmap
;
922 bufmgr_ttm
->bufmgr
.fence_reference
= dri_ttm_fence_reference
;
923 bufmgr_ttm
->bufmgr
.fence_unreference
= dri_ttm_fence_unreference
;
924 bufmgr_ttm
->bufmgr
.fence_wait
= dri_ttm_fence_wait
;
925 bufmgr_ttm
->bufmgr
.destroy
= dri_bufmgr_ttm_destroy
;
926 bufmgr_ttm
->bufmgr
.emit_reloc
= dri_ttm_emit_reloc
;
927 bufmgr_ttm
->bufmgr
.process_relocs
= dri_ttm_process_reloc
;
928 bufmgr_ttm
->bufmgr
.post_submit
= dri_ttm_post_submit
;
929 bufmgr_ttm
->bufmgr
.debug
= GL_FALSE
;
931 return &bufmgr_ttm
->bufmgr
;