1 /**************************************************************************
3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
28 /* Originally a fake version of the buffer manager so that we can
29 * prototype the changes in a driver fairly quickly, has been fleshed
30 * out to a fully functional interim solution.
32 * Basically wraps the old style memory management in the new
33 * programming interface, but is more expressive and avoids many of
34 * the bugs in the old texture manager.
46 #include "intel_bufmgr.h"
47 #include "intel_bufmgr_priv.h"
51 #include "libdrm_lists.h"
53 #define ALIGN(value, alignment) ((value + alignment - 1) & ~(alignment - 1))
55 #define DBG(...) do { \
56 if (bufmgr_fake->bufmgr.debug) \
57 drmMsg(__VA_ARGS__); \
62 #define BM_NO_BACKING_STORE 0x00000001
63 #define BM_NO_FENCE_SUBDATA 0x00000002
64 #define BM_PINNED 0x00000004
66 /* Wrapper around mm.c's mem_block, which understands that you must
67 * wait for fences to expire before memory can be freed. This is
68 * specific to our use of memcpy for uploads - an upload that was
69 * processed through the command queue wouldn't need to care about
72 #define MAX_RELOCS 4096
74 struct fake_buffer_reloc
76 /** Buffer object that the relocation points at. */
78 /** Offset of the relocation entry within reloc_buf. */
80 /** Cached value of the offset when we last performed this relocation. */
81 uint32_t last_target_offset;
82 /** Value added to target_buf's offset to get the relocation entry. */
84 /** Cache domains the target buffer is read into. */
85 uint32_t read_domains;
86 /** Cache domain the target buffer will have dirty cachelines in. */
87 uint32_t write_domain;
91 struct block *next, *prev;
92 struct mem_block *mem; /* BM_MEM_AGP */
95 * Marks that the block is currently in the aperture and has yet to be
98 unsigned on_hardware:1;
100 * Marks that the block is currently fenced (being used by rendering) and
101 * can't be freed until @fence is passed.
105 /** Fence cookie for the block. */
106 unsigned fence; /* Split to read_fence, write_fence */
112 typedef struct _bufmgr_fake {
115 unsigned long low_offset;
119 struct mem_block *heap;
121 unsigned buf_nr; /* for generating ids */
124 * List of blocks which are currently in the GART but haven't been
127 struct block on_hardware;
129 * List of blocks which are in the GART and have an active fence on them.
133 * List of blocks which have an expired fence and are ready to be evicted.
137 unsigned int last_fence;
140 unsigned need_fence:1;
144 * Driver callback to emit a fence, returning the cookie.
146 * This allows the driver to hook in a replacement for the DRM usage in
149 * Currently, this also requires that a write flush be emitted before
150 * emitting the fence, but this should change.
152 unsigned int (*fence_emit)(void *private);
153 /** Driver callback to wait for a fence cookie to have passed. */
154 void (*fence_wait)(unsigned int fence, void *private);
158 * Driver callback to execute a buffer.
160 * This allows the driver to hook in a replacement for the DRM usage in
163 int (*exec)(dri_bo *bo, unsigned int used, void *priv);
166 /** Driver-supplied argument to driver callbacks */
168 /* Pointer to kernel-updated sarea data for the last completed user irq */
169 volatile int *last_dispatch;
175 int performed_rendering;
178 typedef struct _dri_bo_fake {
181 unsigned id; /* debug only */
185 /** has the card written to this buffer - we make need to copy it back */
186 unsigned card_dirty:1;
187 unsigned int refcount;
188 /* Flags may consist of any of the DRM_BO flags, plus
189 * DRM_BO_NO_BACKING_STORE and BM_NO_FENCE_SUBDATA, which are the first two
190 * driver private flags.
193 /** Cache domains the target buffer is read into. */
194 uint32_t read_domains;
195 /** Cache domain the target buffer will have dirty cachelines in. */
196 uint32_t write_domain;
198 unsigned int alignment;
199 int is_static, validated;
200 unsigned int map_count;
202 /** relocation list */
203 struct fake_buffer_reloc *relocs;
206 * Total size of the target_bos of this buffer.
208 * Used for estimation in check_aperture.
210 unsigned int child_size;
214 void (*invalidate_cb)(dri_bo *bo, void *ptr);
215 void *invalidate_ptr;
218 static int clear_fenced(dri_bufmgr_fake *bufmgr_fake,
219 unsigned int fence_cookie);
221 #define MAXFENCE 0x7fffffff
223 static int FENCE_LTE( unsigned a, unsigned b )
228 if (a < b && b - a < (1<<24))
231 if (a > b && MAXFENCE - a + b < (1<<24))
237 void intel_bufmgr_fake_set_fence_callback(dri_bufmgr *bufmgr,
238 unsigned int (*emit)(void *priv),
239 void (*wait)(unsigned int fence,
243 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr;
245 bufmgr_fake->fence_emit = emit;
246 bufmgr_fake->fence_wait = wait;
247 bufmgr_fake->fence_priv = priv;
251 _fence_emit_internal(dri_bufmgr_fake *bufmgr_fake)
253 struct drm_i915_irq_emit ie;
256 if (bufmgr_fake->fence_emit != NULL)
257 return bufmgr_fake->fence_emit(bufmgr_fake->fence_priv);
260 ret = drmCommandWriteRead(bufmgr_fake->fd, DRM_I915_IRQ_EMIT,
263 drmMsg("%s: drm_i915_irq_emit: %d\n", __FUNCTION__, ret);
267 DBG("emit 0x%08x\n", seq);
268 bufmgr_fake->last_fence = seq;
269 return bufmgr_fake->last_fence;
273 _fence_wait_internal(dri_bufmgr_fake *bufmgr_fake, int seq)
275 struct drm_i915_irq_wait iw;
280 if (bufmgr_fake->fence_wait != NULL) {
281 bufmgr_fake->fence_wait(seq, bufmgr_fake->fence_priv);
285 DBG("wait 0x%08x\n", iw.irq_seq);
289 /* The kernel IRQ_WAIT implementation is all sorts of broken.
290 * 1) It returns 1 to 0x7fffffff instead of using the full 32-bit unsigned
292 * 2) It returns 0 if hw_seq >= seq, not seq - hw_seq < 0 on the 32-bit
294 * 3) It waits if seq < hw_seq, not seq - hw_seq > 0 on the 32-bit
296 * 4) It returns -EBUSY in 3 seconds even if the hardware is still
297 * successfully chewing through buffers.
299 * Assume that in userland we treat sequence numbers as ints, which makes
300 * some of the comparisons convenient, since the sequence numbers are
301 * all postive signed integers.
303 * From this we get several cases we need to handle. Here's a timeline.
304 * 0x2 0x7 0x7ffffff8 0x7ffffffd
306 * -------------------------------------------------------------------
308 * A) Normal wait for hw to catch up
311 * -------------------------------------------------------------------
312 * seq - hw_seq = 5. If we call IRQ_WAIT, it will wait for hw to catch up.
314 * B) Normal wait for a sequence number that's already passed.
317 * -------------------------------------------------------------------
318 * seq - hw_seq = -5. If we call IRQ_WAIT, it returns 0 quickly.
320 * C) Hardware has already wrapped around ahead of us
323 * -------------------------------------------------------------------
324 * seq - hw_seq = 0x80000000 - 5. If we called IRQ_WAIT, it would wait
325 * for hw_seq >= seq, which may never occur. Thus, we want to catch this
326 * in userland and return 0.
328 * D) We've wrapped around ahead of the hardware.
331 * -------------------------------------------------------------------
332 * seq - hw_seq = -(0x80000000 - 5). If we called IRQ_WAIT, it would return
333 * 0 quickly because hw_seq >= seq, even though the hardware isn't caught up.
334 * Thus, we need to catch this early return in userland and bother the
335 * kernel until the hardware really does catch up.
337 * E) Hardware might wrap after we test in userland.
340 * -------------------------------------------------------------------
341 * seq - hw_seq = 5. If we call IRQ_WAIT, it will likely see seq >= hw_seq
342 * and wait. However, suppose hw_seq wraps before we make it into the
343 * kernel. The kernel sees hw_seq >= seq and waits for 3 seconds then
344 * returns -EBUSY. This is case C). We should catch this and then return
348 /* Keep a copy of last_dispatch so that if the wait -EBUSYs because the
349 * hardware didn't catch up in 3 seconds, we can see if it at least made
350 * progress and retry.
352 hw_seq = *bufmgr_fake->last_dispatch;
355 if (seq - hw_seq > 0x40000000)
358 ret = drmCommandWrite(bufmgr_fake->fd, DRM_I915_IRQ_WAIT,
361 kernel_lied = (ret == 0) && (seq - *bufmgr_fake->last_dispatch <
365 if (ret == -EBUSY && (seq - *bufmgr_fake->last_dispatch > 0x40000000))
367 } while (kernel_lied || ret == -EAGAIN || ret == -EINTR ||
368 (ret == -EBUSY && hw_seq != *bufmgr_fake->last_dispatch));
371 drmMsg("%s:%d: Error %d waiting for fence.\n", __FILE__, __LINE__, ret);
374 clear_fenced(bufmgr_fake, seq);
378 _fence_test(dri_bufmgr_fake *bufmgr_fake, unsigned fence)
380 /* Slight problem with wrap-around:
382 return fence == 0 || FENCE_LTE(fence, bufmgr_fake->last_fence);
386 * Allocate a memory manager block for the buffer.
389 alloc_block(dri_bo *bo)
391 dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
392 dri_bufmgr_fake *bufmgr_fake= (dri_bufmgr_fake *)bo->bufmgr;
393 struct block *block = (struct block *)calloc(sizeof *block, 1);
394 unsigned int align_log2 = ffs(bo_fake->alignment) - 1;
400 sz = (bo->size + bo_fake->alignment - 1) & ~(bo_fake->alignment - 1);
402 block->mem = mmAllocMem(bufmgr_fake->heap, sz, align_log2, 0);
408 DRMINITLISTHEAD(block);
410 /* Insert at head or at tail???
412 DRMLISTADDTAIL(block, &bufmgr_fake->lru);
414 block->virtual = (uint8_t *)bufmgr_fake->virtual +
415 block->mem->ofs - bufmgr_fake->low_offset;
418 bo_fake->block = block;
423 /* Release the card storage associated with buf:
425 static void free_block(dri_bufmgr_fake *bufmgr_fake, struct block *block)
427 dri_bo_fake *bo_fake;
428 DBG("free block %p %08x %d %d\n", block, block->mem->ofs, block->on_hardware, block->fenced);
433 bo_fake = (dri_bo_fake *)block->bo;
434 if (!(bo_fake->flags & BM_NO_BACKING_STORE) && (bo_fake->card_dirty == 1)) {
435 memcpy(bo_fake->backing_store, block->virtual, block->bo->size);
436 bo_fake->card_dirty = 1;
440 if (block->on_hardware) {
443 else if (block->fenced) {
447 DBG(" - free immediately\n");
450 mmFreeMem(block->mem);
456 alloc_backing_store(dri_bo *bo)
458 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
459 dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
460 assert(!bo_fake->backing_store);
461 assert(!(bo_fake->flags & (BM_PINNED|BM_NO_BACKING_STORE)));
463 bo_fake->backing_store = malloc(bo->size);
465 DBG("alloc_backing - buf %d %p %d\n", bo_fake->id, bo_fake->backing_store, bo->size);
466 assert(bo_fake->backing_store);
470 free_backing_store(dri_bo *bo)
472 dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
474 if (bo_fake->backing_store) {
475 assert(!(bo_fake->flags & (BM_PINNED|BM_NO_BACKING_STORE)));
476 free(bo_fake->backing_store);
477 bo_fake->backing_store = NULL;
482 set_dirty(dri_bo *bo)
484 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
485 dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
487 if (bo_fake->flags & BM_NO_BACKING_STORE && bo_fake->invalidate_cb != NULL)
488 bo_fake->invalidate_cb(bo, bo_fake->invalidate_ptr);
490 assert(!(bo_fake->flags & BM_PINNED));
492 DBG("set_dirty - buf %d\n", bo_fake->id);
497 evict_lru(dri_bufmgr_fake *bufmgr_fake, unsigned int max_fence)
499 struct block *block, *tmp;
501 DBG("%s\n", __FUNCTION__);
503 DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) {
504 dri_bo_fake *bo_fake = (dri_bo_fake *)block->bo;
506 if (bo_fake != NULL && (bo_fake->flags & BM_NO_FENCE_SUBDATA))
509 if (block->fence && max_fence && !FENCE_LTE(block->fence, max_fence))
512 set_dirty(&bo_fake->bo);
513 bo_fake->block = NULL;
515 free_block(bufmgr_fake, block);
523 evict_mru(dri_bufmgr_fake *bufmgr_fake)
525 struct block *block, *tmp;
527 DBG("%s\n", __FUNCTION__);
529 DRMLISTFOREACHSAFEREVERSE(block, tmp, &bufmgr_fake->lru) {
530 dri_bo_fake *bo_fake = (dri_bo_fake *)block->bo;
532 if (bo_fake && (bo_fake->flags & BM_NO_FENCE_SUBDATA))
535 set_dirty(&bo_fake->bo);
536 bo_fake->block = NULL;
538 free_block(bufmgr_fake, block);
546 * Removes all objects from the fenced list older than the given fence.
548 static int clear_fenced(dri_bufmgr_fake *bufmgr_fake,
549 unsigned int fence_cookie)
551 struct block *block, *tmp;
554 DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->fenced) {
555 assert(block->fenced);
557 if (_fence_test(bufmgr_fake, block->fence)) {
562 DBG("delayed free: offset %x sz %x\n",
563 block->mem->ofs, block->mem->size);
565 mmFreeMem(block->mem);
569 DBG("return to lru: offset %x sz %x\n",
570 block->mem->ofs, block->mem->size);
572 DRMLISTADDTAIL(block, &bufmgr_fake->lru);
578 /* Blocks are ordered by fence, so if one fails, all from
579 * here will fail also:
581 DBG("fence not passed: offset %x sz %x %d %d \n",
582 block->mem->ofs, block->mem->size, block->fence, bufmgr_fake->last_fence);
587 DBG("%s: %d\n", __FUNCTION__, ret);
591 static void fence_blocks(dri_bufmgr_fake *bufmgr_fake, unsigned fence)
593 struct block *block, *tmp;
595 DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->on_hardware) {
596 DBG("Fence block %p (sz 0x%x ofs %x buf %p) with fence %d\n", block,
597 block->mem->size, block->mem->ofs, block->bo, fence);
598 block->fence = fence;
600 block->on_hardware = 0;
603 /* Move to tail of pending list here
606 DRMLISTADDTAIL(block, &bufmgr_fake->fenced);
609 assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware));
612 static int evict_and_alloc_block(dri_bo *bo)
614 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
615 dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
617 assert(bo_fake->block == NULL);
619 /* Search for already free memory:
624 /* If we're not thrashing, allow lru eviction to dig deeper into
625 * recently used textures. We'll probably be thrashing soon:
627 if (!bufmgr_fake->thrashing) {
628 while (evict_lru(bufmgr_fake, 0))
633 /* Keep thrashing counter alive?
635 if (bufmgr_fake->thrashing)
636 bufmgr_fake->thrashing = 20;
638 /* Wait on any already pending fences - here we are waiting for any
639 * freed memory that has been submitted to hardware and fenced to
642 while (!DRMLISTEMPTY(&bufmgr_fake->fenced)) {
643 uint32_t fence = bufmgr_fake->fenced.next->fence;
644 _fence_wait_internal(bufmgr_fake, fence);
650 if (!DRMLISTEMPTY(&bufmgr_fake->on_hardware)) {
651 while (!DRMLISTEMPTY(&bufmgr_fake->fenced)) {
652 uint32_t fence = bufmgr_fake->fenced.next->fence;
653 _fence_wait_internal(bufmgr_fake, fence);
656 if (!bufmgr_fake->thrashing) {
659 bufmgr_fake->thrashing = 20;
665 while (evict_mru(bufmgr_fake))
669 DBG("%s 0x%x bytes failed\n", __FUNCTION__, bo->size);
674 /***********************************************************************
679 * Wait for hardware idle by emitting a fence and waiting for it.
682 dri_bufmgr_fake_wait_idle(dri_bufmgr_fake *bufmgr_fake)
686 cookie = _fence_emit_internal(bufmgr_fake);
687 _fence_wait_internal(bufmgr_fake, cookie);
691 * Wait for rendering to a buffer to complete.
693 * It is assumed that the bathcbuffer which performed the rendering included
694 * the necessary flushing.
697 dri_fake_bo_wait_rendering(dri_bo *bo)
699 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
700 dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
702 if (bo_fake->block == NULL || !bo_fake->block->fenced)
705 _fence_wait_internal(bufmgr_fake, bo_fake->block->fence);
708 /* Specifically ignore texture memory sharing.
709 * -- just evict everything
710 * -- and wait for idle
713 intel_bufmgr_fake_contended_lock_take(dri_bufmgr *bufmgr)
715 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr;
716 struct block *block, *tmp;
718 bufmgr_fake->need_fence = 1;
719 bufmgr_fake->fail = 0;
721 /* Wait for hardware idle. We don't know where acceleration has been
722 * happening, so we'll need to wait anyway before letting anything get
723 * put on the card again.
725 dri_bufmgr_fake_wait_idle(bufmgr_fake);
727 /* Check that we hadn't released the lock without having fenced the last
730 assert(DRMLISTEMPTY(&bufmgr_fake->fenced));
731 assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware));
733 DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) {
734 assert(_fence_test(bufmgr_fake, block->fence));
735 set_dirty(block->bo);
740 dri_fake_bo_alloc(dri_bufmgr *bufmgr, const char *name,
741 unsigned long size, unsigned int alignment)
743 dri_bufmgr_fake *bufmgr_fake;
744 dri_bo_fake *bo_fake;
746 bufmgr_fake = (dri_bufmgr_fake *)bufmgr;
750 bo_fake = calloc(1, sizeof(*bo_fake));
754 bo_fake->bo.size = size;
755 bo_fake->bo.offset = -1;
756 bo_fake->bo.virtual = NULL;
757 bo_fake->bo.bufmgr = bufmgr;
758 bo_fake->refcount = 1;
760 /* Alignment must be a power of two */
761 assert((alignment & (alignment - 1)) == 0);
764 bo_fake->alignment = alignment;
765 bo_fake->id = ++bufmgr_fake->buf_nr;
766 bo_fake->name = name;
768 bo_fake->is_static = 0;
770 DBG("drm_bo_alloc: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name,
771 bo_fake->bo.size / 1024);
777 intel_bo_fake_alloc_static(dri_bufmgr *bufmgr, const char *name,
778 unsigned long offset, unsigned long size,
781 dri_bufmgr_fake *bufmgr_fake;
782 dri_bo_fake *bo_fake;
784 bufmgr_fake = (dri_bufmgr_fake *)bufmgr;
788 bo_fake = calloc(1, sizeof(*bo_fake));
792 bo_fake->bo.size = size;
793 bo_fake->bo.offset = offset;
794 bo_fake->bo.virtual = virtual;
795 bo_fake->bo.bufmgr = bufmgr;
796 bo_fake->refcount = 1;
797 bo_fake->id = ++bufmgr_fake->buf_nr;
798 bo_fake->name = name;
799 bo_fake->flags = BM_PINNED | DRM_BO_FLAG_NO_MOVE;
800 bo_fake->is_static = 1;
802 DBG("drm_bo_alloc_static: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name,
803 bo_fake->bo.size / 1024);
809 dri_fake_bo_reference(dri_bo *bo)
811 dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
817 dri_fake_bo_unreference(dri_bo *bo)
819 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
820 dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
826 if (--bo_fake->refcount == 0) {
827 assert(bo_fake->map_count == 0);
828 /* No remaining references, so free it */
830 free_block(bufmgr_fake, bo_fake->block);
831 free_backing_store(bo);
833 for (i = 0; i < bo_fake->nr_relocs; i++)
834 dri_bo_unreference(bo_fake->relocs[i].target_buf);
836 DBG("drm_bo_unreference: free buf %d %s\n", bo_fake->id, bo_fake->name);
838 free(bo_fake->relocs);
846 * Set the buffer as not requiring backing store, and instead get the callback
847 * invoked whenever it would be set dirty.
849 void intel_bo_fake_disable_backing_store(dri_bo *bo,
850 void (*invalidate_cb)(dri_bo *bo,
854 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
855 dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
857 if (bo_fake->backing_store)
858 free_backing_store(bo);
860 bo_fake->flags |= BM_NO_BACKING_STORE;
862 DBG("disable_backing_store set buf %d dirty\n", bo_fake->id);
864 bo_fake->invalidate_cb = invalidate_cb;
865 bo_fake->invalidate_ptr = ptr;
867 /* Note that it is invalid right from the start. Also note
868 * invalidate_cb is called with the bufmgr locked, so cannot
869 * itself make bufmgr calls.
871 if (invalidate_cb != NULL)
872 invalidate_cb(bo, ptr);
876 * Map a buffer into bo->virtual, allocating either card memory space (If
877 * BM_NO_BACKING_STORE or BM_PINNED) or backing store, as necessary.
880 dri_fake_bo_map(dri_bo *bo, int write_enable)
882 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
883 dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
885 /* Static buffers are always mapped. */
886 if (bo_fake->is_static)
889 /* Allow recursive mapping. Mesa may recursively map buffers with
890 * nested display loops, and it is used internally in bufmgr_fake
893 if (bo_fake->map_count++ != 0)
897 DBG("drm_bo_map: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name,
898 bo_fake->bo.size / 1024);
900 if (bo->virtual != NULL) {
901 drmMsg("%s: already mapped\n", __FUNCTION__);
904 else if (bo_fake->flags & (BM_NO_BACKING_STORE|BM_PINNED)) {
906 if (!bo_fake->block && !evict_and_alloc_block(bo)) {
907 DBG("%s: alloc failed\n", __FUNCTION__);
908 bufmgr_fake->fail = 1;
912 assert(bo_fake->block);
915 if (!(bo_fake->flags & BM_NO_FENCE_SUBDATA) &&
916 bo_fake->block->fenced) {
917 dri_fake_bo_wait_rendering(bo);
920 bo->virtual = bo_fake->block->virtual;
927 if (bo_fake->backing_store == 0)
928 alloc_backing_store(bo);
930 bo->virtual = bo_fake->backing_store;
938 dri_fake_bo_unmap(dri_bo *bo)
940 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
941 dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
943 /* Static buffers are always mapped. */
944 if (bo_fake->is_static)
947 assert(bo_fake->map_count != 0);
948 if (--bo_fake->map_count != 0)
951 DBG("drm_bo_unmap: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name,
952 bo_fake->bo.size / 1024);
960 dri_fake_kick_all(dri_bufmgr_fake *bufmgr_fake)
962 struct block *block, *tmp;
964 bufmgr_fake->performed_rendering = 0;
965 /* okay for ever BO that is on the HW kick it off.
966 seriously not afraid of the POLICE right now */
967 DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->on_hardware) {
968 dri_bo_fake *bo_fake = (dri_bo_fake *)block->bo;
970 block->on_hardware = 0;
971 free_block(bufmgr_fake, block);
972 bo_fake->block = NULL;
973 bo_fake->validated = 0;
974 if (!(bo_fake->flags & BM_NO_BACKING_STORE))
980 dri_fake_bo_validate(dri_bo *bo)
982 dri_bufmgr_fake *bufmgr_fake;
983 dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
985 /* XXX: Sanity-check whether we've already validated this one under
986 * different flags. See drmAddValidateItem().
988 bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
990 DBG("drm_bo_validate: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name,
991 bo_fake->bo.size / 1024);
993 /* Sanity check: Buffers should be unmapped before being validated.
994 * This is not so much of a problem for bufmgr_fake, but TTM refuses,
995 * and the problem is harder to debug there.
997 assert(bo_fake->map_count == 0);
999 if (bo_fake->is_static) {
1000 /* Add it to the needs-fence list */
1001 bufmgr_fake->need_fence = 1;
1005 /* Allocate the card memory */
1006 if (!bo_fake->block && !evict_and_alloc_block(bo)) {
1007 bufmgr_fake->fail = 1;
1008 DBG("Failed to validate buf %d:%s\n", bo_fake->id, bo_fake->name);
1012 assert(bo_fake->block);
1013 assert(bo_fake->block->bo == &bo_fake->bo);
1015 bo->offset = bo_fake->block->mem->ofs;
1017 /* Upload the buffer contents if necessary */
1018 if (bo_fake->dirty) {
1019 DBG("Upload dirty buf %d:%s, sz %d offset 0x%x\n", bo_fake->id,
1020 bo_fake->name, bo->size, bo_fake->block->mem->ofs);
1022 assert(!(bo_fake->flags &
1023 (BM_NO_BACKING_STORE|BM_PINNED)));
1025 /* Actually, should be able to just wait for a fence on the memory,
1026 * which we would be tracking when we free it. Waiting for idle is
1027 * a sufficiently large hammer for now.
1029 dri_bufmgr_fake_wait_idle(bufmgr_fake);
1031 /* we may never have mapped this BO so it might not have any backing
1032 * store if this happens it should be rare, but 0 the card memory
1034 if (bo_fake->backing_store)
1035 memcpy(bo_fake->block->virtual, bo_fake->backing_store, bo->size);
1037 memset(bo_fake->block->virtual, 0, bo->size);
1042 bo_fake->block->fenced = 0;
1043 bo_fake->block->on_hardware = 1;
1044 DRMLISTDEL(bo_fake->block);
1045 DRMLISTADDTAIL(bo_fake->block, &bufmgr_fake->on_hardware);
1047 bo_fake->validated = 1;
1048 bufmgr_fake->need_fence = 1;
1054 dri_fake_fence_validated(dri_bufmgr *bufmgr)
1056 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr;
1057 unsigned int cookie;
1059 cookie = _fence_emit_internal(bufmgr_fake);
1060 fence_blocks(bufmgr_fake, cookie);
1062 DBG("drm_fence_validated: 0x%08x cookie\n", cookie);
1066 dri_fake_destroy(dri_bufmgr *bufmgr)
1068 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr;
1070 mmDestroy(bufmgr_fake->heap);
1075 dri_fake_emit_reloc(dri_bo *reloc_buf,
1076 uint32_t read_domains, uint32_t write_domain,
1077 uint32_t delta, uint32_t offset, dri_bo *target_buf)
1079 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)reloc_buf->bufmgr;
1080 struct fake_buffer_reloc *r;
1081 dri_bo_fake *reloc_fake = (dri_bo_fake *)reloc_buf;
1082 dri_bo_fake *target_fake = (dri_bo_fake *)target_buf;
1088 if (reloc_fake->relocs == NULL) {
1089 reloc_fake->relocs = malloc(sizeof(struct fake_buffer_reloc) *
1093 r = &reloc_fake->relocs[reloc_fake->nr_relocs++];
1095 assert(reloc_fake->nr_relocs <= MAX_RELOCS);
1097 dri_bo_reference(target_buf);
1099 if (!target_fake->is_static)
1100 reloc_fake->child_size += ALIGN(target_buf->size, target_fake->alignment);
1102 r->target_buf = target_buf;
1104 r->last_target_offset = target_buf->offset;
1106 r->read_domains = read_domains;
1107 r->write_domain = write_domain;
1109 if (bufmgr_fake->debug) {
1110 /* Check that a conflicting relocation hasn't already been emitted. */
1111 for (i = 0; i < reloc_fake->nr_relocs - 1; i++) {
1112 struct fake_buffer_reloc *r2 = &reloc_fake->relocs[i];
1114 assert(r->offset != r2->offset);
1122 * Incorporates the validation flags associated with each relocation into
1123 * the combined validation flags for the buffer on this batchbuffer submission.
1126 dri_fake_calculate_domains(dri_bo *bo)
1128 dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
1131 for (i = 0; i < bo_fake->nr_relocs; i++) {
1132 struct fake_buffer_reloc *r = &bo_fake->relocs[i];
1133 dri_bo_fake *target_fake = (dri_bo_fake *)r->target_buf;
1135 /* Do the same for the tree of buffers we depend on */
1136 dri_fake_calculate_domains(r->target_buf);
1138 target_fake->read_domains |= r->read_domains;
1139 if (target_fake->write_domain != 0)
1140 target_fake->write_domain = r->write_domain;
1146 dri_fake_reloc_and_validate_buffer(dri_bo *bo)
1148 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
1149 dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
1152 assert(bo_fake->map_count == 0);
1154 for (i = 0; i < bo_fake->nr_relocs; i++) {
1155 struct fake_buffer_reloc *r = &bo_fake->relocs[i];
1156 dri_bo_fake *target_fake = (dri_bo_fake *)r->target_buf;
1157 uint32_t reloc_data;
1159 /* Validate the target buffer if that hasn't been done. */
1160 if (!target_fake->validated) {
1161 ret = dri_fake_reloc_and_validate_buffer(r->target_buf);
1163 if (bo->virtual != NULL)
1169 /* Calculate the value of the relocation entry. */
1170 if (r->target_buf->offset != r->last_target_offset) {
1171 reloc_data = r->target_buf->offset + r->delta;
1173 if (bo->virtual == NULL)
1176 *(uint32_t *)((uint8_t *)bo->virtual + r->offset) = reloc_data;
1178 r->last_target_offset = r->target_buf->offset;
1182 if (bo->virtual != NULL)
1185 if (bo_fake->write_domain != 0) {
1186 if (!(bo_fake->flags & (BM_NO_BACKING_STORE|BM_PINNED))) {
1187 if (bo_fake->backing_store == 0)
1188 alloc_backing_store(bo);
1190 bo_fake->card_dirty = 1;
1192 bufmgr_fake->performed_rendering = 1;
1195 return dri_fake_bo_validate(bo);
1199 dri_bo_fake_post_submit(dri_bo *bo)
1201 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
1202 dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
1205 for (i = 0; i < bo_fake->nr_relocs; i++) {
1206 struct fake_buffer_reloc *r = &bo_fake->relocs[i];
1207 dri_bo_fake *target_fake = (dri_bo_fake *)r->target_buf;
1209 if (target_fake->validated)
1210 dri_bo_fake_post_submit(r->target_buf);
1212 DBG("%s@0x%08x + 0x%08x -> %s@0x%08x + 0x%08x\n",
1213 bo_fake->name, (uint32_t)bo->offset, r->offset,
1214 target_fake->name, (uint32_t)r->target_buf->offset, r->delta);
1217 assert(bo_fake->map_count == 0);
1218 bo_fake->validated = 0;
1219 bo_fake->read_domains = 0;
1220 bo_fake->write_domain = 0;
1224 void intel_bufmgr_fake_set_exec_callback(dri_bufmgr *bufmgr,
1225 int (*exec)(dri_bo *bo,
1230 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr;
1232 bufmgr_fake->exec = exec;
1233 bufmgr_fake->exec_priv = priv;
1237 dri_fake_bo_exec(dri_bo *bo, int used,
1238 drm_clip_rect_t *cliprects, int num_cliprects,
1241 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
1242 dri_bo_fake *batch_fake = (dri_bo_fake *)bo;
1243 struct drm_i915_batchbuffer batch;
1245 int retry_count = 0;
1247 bufmgr_fake->performed_rendering = 0;
1249 dri_fake_calculate_domains(bo);
1251 batch_fake->read_domains = I915_GEM_DOMAIN_COMMAND;
1253 /* we've ran out of RAM so blow the whole lot away and retry */
1255 ret = dri_fake_reloc_and_validate_buffer(bo);
1256 if (bufmgr_fake->fail == 1) {
1257 if (retry_count == 0) {
1259 dri_fake_kick_all(bufmgr_fake);
1260 bufmgr_fake->fail = 0;
1262 } else /* dump out the memory here */
1263 mmDumpMemInfo(bufmgr_fake->heap);
1268 if (bufmgr_fake->exec != NULL) {
1269 int ret = bufmgr_fake->exec(bo, used, bufmgr_fake->exec_priv);
1273 batch.start = bo->offset;
1275 batch.cliprects = cliprects;
1276 batch.num_cliprects = num_cliprects;
1280 if (drmCommandWrite(bufmgr_fake->fd, DRM_I915_BATCHBUFFER, &batch,
1282 drmMsg("DRM_I915_BATCHBUFFER: %d\n", -errno);
1287 dri_fake_fence_validated(bo->bufmgr);
1289 dri_bo_fake_post_submit(bo);
1295 * Return an error if the list of BOs will exceed the aperture size.
1297 * This is a rough guess and likely to fail, as during the validate sequence we
1298 * may place a buffer in an inopportune spot early on and then fail to fit
1299 * a set smaller than the aperture.
1302 dri_fake_check_aperture_space(dri_bo **bo_array, int count)
1304 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo_array[0]->bufmgr;
1305 unsigned int sz = 0;
1308 for (i = 0; i < count; i++) {
1309 dri_bo_fake *bo_fake = (dri_bo_fake *)bo_array[i];
1311 if (bo_fake == NULL)
1314 if (!bo_fake->is_static)
1315 sz += ALIGN(bo_array[i]->size, bo_fake->alignment);
1316 sz += bo_fake->child_size;
1319 if (sz > bufmgr_fake->size) {
1320 DBG("check_space: overflowed bufmgr size, %dkb vs %dkb\n",
1321 sz / 1024, bufmgr_fake->size / 1024);
1325 DBG("drm_check_space: sz %dkb vs bufgr %dkb\n", sz / 1024 ,
1326 bufmgr_fake->size / 1024);
1331 * Evicts all buffers, waiting for fences to pass and copying contents out
1334 * Used by the X Server on LeaveVT, when the card memory is no longer our
1338 intel_bufmgr_fake_evict_all(dri_bufmgr *bufmgr)
1340 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr;
1341 struct block *block, *tmp;
1343 bufmgr_fake->need_fence = 1;
1344 bufmgr_fake->fail = 0;
1346 /* Wait for hardware idle. We don't know where acceleration has been
1347 * happening, so we'll need to wait anyway before letting anything get
1348 * put on the card again.
1350 dri_bufmgr_fake_wait_idle(bufmgr_fake);
1352 /* Check that we hadn't released the lock without having fenced the last
1355 assert(DRMLISTEMPTY(&bufmgr_fake->fenced));
1356 assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware));
1358 DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) {
1359 /* Releases the memory, and memcpys dirty contents out if necessary. */
1360 free_block(bufmgr_fake, block);
1363 void intel_bufmgr_fake_set_last_dispatch(dri_bufmgr *bufmgr,
1364 volatile unsigned int *last_dispatch)
1366 dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr;
1368 bufmgr_fake->last_dispatch = (volatile int *)last_dispatch;
1372 intel_bufmgr_fake_init(int fd,
1373 unsigned long low_offset, void *low_virtual,
1375 volatile unsigned int *last_dispatch)
1377 dri_bufmgr_fake *bufmgr_fake;
1379 bufmgr_fake = calloc(1, sizeof(*bufmgr_fake));
1381 /* Initialize allocator */
1382 DRMINITLISTHEAD(&bufmgr_fake->fenced);
1383 DRMINITLISTHEAD(&bufmgr_fake->on_hardware);
1384 DRMINITLISTHEAD(&bufmgr_fake->lru);
1386 bufmgr_fake->low_offset = low_offset;
1387 bufmgr_fake->virtual = low_virtual;
1388 bufmgr_fake->size = size;
1389 bufmgr_fake->heap = mmInit(low_offset, size);
1391 /* Hook in methods */
1392 bufmgr_fake->bufmgr.bo_alloc = dri_fake_bo_alloc;
1393 bufmgr_fake->bufmgr.bo_reference = dri_fake_bo_reference;
1394 bufmgr_fake->bufmgr.bo_unreference = dri_fake_bo_unreference;
1395 bufmgr_fake->bufmgr.bo_map = dri_fake_bo_map;
1396 bufmgr_fake->bufmgr.bo_unmap = dri_fake_bo_unmap;
1397 bufmgr_fake->bufmgr.bo_wait_rendering = dri_fake_bo_wait_rendering;
1398 bufmgr_fake->bufmgr.bo_emit_reloc = dri_fake_emit_reloc;
1399 bufmgr_fake->bufmgr.destroy = dri_fake_destroy;
1400 bufmgr_fake->bufmgr.bo_exec = dri_fake_bo_exec;
1401 bufmgr_fake->bufmgr.check_aperture_space = dri_fake_check_aperture_space;
1402 bufmgr_fake->bufmgr.debug = 0;
1404 bufmgr_fake->fd = fd;
1405 bufmgr_fake->last_dispatch = (volatile int *)last_dispatch;
1407 return &bufmgr_fake->bufmgr;