]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/libdrm.git/blob - intel/intel_bufmgr_fake.c
libdrm_radeon: add radeon_bo_is_referenced_by_cs function
[glsdk/libdrm.git] / intel / intel_bufmgr_fake.c
1 /**************************************************************************
2  * 
3  * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
4  * All Rights Reserved.
5  * 
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  * 
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  * 
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.
25  * 
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.
31  *
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.
35  */
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
41 #include <stdlib.h>
42 #include <string.h>
43 #include <assert.h>
44 #include <errno.h>
45 #include <xf86drm.h>
46 #include <pthread.h>
47 #include "intel_bufmgr.h"
48 #include "intel_bufmgr_priv.h"
49 #include "drm.h"
50 #include "i915_drm.h"
51 #include "mm.h"
52 #include "libdrm_lists.h"
54 #define DBG(...) do {                                   \
55         if (bufmgr_fake->bufmgr.debug)                  \
56                 drmMsg(__VA_ARGS__);                    \
57 } while (0)
59 /* Internal flags:
60  */
61 #define BM_NO_BACKING_STORE                     0x00000001
62 #define BM_NO_FENCE_SUBDATA                     0x00000002
63 #define BM_PINNED                               0x00000004
65 /* Wrapper around mm.c's mem_block, which understands that you must
66  * wait for fences to expire before memory can be freed.  This is
67  * specific to our use of memcpy for uploads - an upload that was
68  * processed through the command queue wouldn't need to care about
69  * fences.
70  */
71 #define MAX_RELOCS 4096
73 struct fake_buffer_reloc {
74         /** Buffer object that the relocation points at. */
75         drm_intel_bo *target_buf;
76         /** Offset of the relocation entry within reloc_buf. */
77         uint32_t offset;
78         /**
79          * Cached value of the offset when we last performed this relocation.
80          */
81         uint32_t last_target_offset;
82         /** Value added to target_buf's offset to get the relocation entry. */
83         uint32_t delta;
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;
88 };
90 struct block {
91         struct block *next, *prev;
92         struct mem_block *mem;  /* BM_MEM_AGP */
94         /**
95          * Marks that the block is currently in the aperture and has yet to be
96          * fenced.
97          */
98         unsigned on_hardware:1;
99         /**
100          * Marks that the block is currently fenced (being used by rendering)
101          * and can't be freed until @fence is passed.
102          */
103         unsigned fenced:1;
105         /** Fence cookie for the block. */
106         unsigned fence;         /* Split to read_fence, write_fence */
108         drm_intel_bo *bo;
109         void *virtual;
110 };
112 typedef struct _bufmgr_fake {
113         drm_intel_bufmgr bufmgr;
115         pthread_mutex_t lock;
117         unsigned long low_offset;
118         unsigned long size;
119         void *virtual;
121         struct mem_block *heap;
123         unsigned buf_nr;        /* for generating ids */
125         /**
126          * List of blocks which are currently in the GART but haven't been
127          * fenced yet.
128          */
129         struct block on_hardware;
130         /**
131          * List of blocks which are in the GART and have an active fence on
132          * them.
133          */
134         struct block fenced;
135         /**
136          * List of blocks which have an expired fence and are ready to be
137          * evicted.
138          */
139         struct block lru;
141         unsigned int last_fence;
143         unsigned fail:1;
144         unsigned need_fence:1;
145         int thrashing;
147         /**
148          * Driver callback to emit a fence, returning the cookie.
149          *
150          * This allows the driver to hook in a replacement for the DRM usage in
151          * bufmgr_fake.
152          *
153          * Currently, this also requires that a write flush be emitted before
154          * emitting the fence, but this should change.
155          */
156         unsigned int (*fence_emit) (void *private);
157         /** Driver callback to wait for a fence cookie to have passed. */
158         void (*fence_wait) (unsigned int fence, void *private);
159         void *fence_priv;
161         /**
162          * Driver callback to execute a buffer.
163          *
164          * This allows the driver to hook in a replacement for the DRM usage in
165          * bufmgr_fake.
166          */
167         int (*exec) (drm_intel_bo *bo, unsigned int used, void *priv);
168         void *exec_priv;
170         /** Driver-supplied argument to driver callbacks */
171         void *driver_priv;
172         /**
173          * Pointer to kernel-updated sarea data for the last completed user irq
174          */
175         volatile int *last_dispatch;
177         int fd;
179         int debug;
181         int performed_rendering;
182 } drm_intel_bufmgr_fake;
184 typedef struct _drm_intel_bo_fake {
185         drm_intel_bo bo;
187         unsigned id;            /* debug only */
188         const char *name;
190         unsigned dirty:1;
191         /**
192          * has the card written to this buffer - we make need to copy it back
193          */
194         unsigned card_dirty:1;
195         unsigned int refcount;
196         /* Flags may consist of any of the DRM_BO flags, plus
197          * DRM_BO_NO_BACKING_STORE and BM_NO_FENCE_SUBDATA, which are the
198          * first two driver private flags.
199          */
200         uint64_t flags;
201         /** Cache domains the target buffer is read into. */
202         uint32_t read_domains;
203         /** Cache domain the target buffer will have dirty cachelines in. */
204         uint32_t write_domain;
206         unsigned int alignment;
207         int is_static, validated;
208         unsigned int map_count;
210         /** relocation list */
211         struct fake_buffer_reloc *relocs;
212         int nr_relocs;
213         /**
214          * Total size of the target_bos of this buffer.
215          *
216          * Used for estimation in check_aperture.
217          */
218         unsigned int child_size;
220         struct block *block;
221         void *backing_store;
222         void (*invalidate_cb) (drm_intel_bo *bo, void *ptr);
223         void *invalidate_ptr;
224 } drm_intel_bo_fake;
226 static int clear_fenced(drm_intel_bufmgr_fake *bufmgr_fake,
227                         unsigned int fence_cookie);
229 #define MAXFENCE 0x7fffffff
231 static int
232 FENCE_LTE(unsigned a, unsigned b)
234         if (a == b)
235                 return 1;
237         if (a < b && b - a < (1 << 24))
238                 return 1;
240         if (a > b && MAXFENCE - a + b < (1 << 24))
241                 return 1;
243         return 0;
246 void
247 drm_intel_bufmgr_fake_set_fence_callback(drm_intel_bufmgr *bufmgr,
248                                          unsigned int (*emit) (void *priv),
249                                          void (*wait) (unsigned int fence,
250                                                        void *priv),
251                                          void *priv)
253         drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
255         bufmgr_fake->fence_emit = emit;
256         bufmgr_fake->fence_wait = wait;
257         bufmgr_fake->fence_priv = priv;
260 static unsigned int
261 _fence_emit_internal(drm_intel_bufmgr_fake *bufmgr_fake)
263         struct drm_i915_irq_emit ie;
264         int ret, seq = 1;
266         if (bufmgr_fake->fence_emit != NULL) {
267                 seq = bufmgr_fake->fence_emit(bufmgr_fake->fence_priv);
268                 return seq;
269         }
271         ie.irq_seq = &seq;
272         ret = drmCommandWriteRead(bufmgr_fake->fd, DRM_I915_IRQ_EMIT,
273                                   &ie, sizeof(ie));
274         if (ret) {
275                 drmMsg("%s: drm_i915_irq_emit: %d\n", __FUNCTION__, ret);
276                 abort();
277         }
279         DBG("emit 0x%08x\n", seq);
280         return seq;
283 static void
284 _fence_wait_internal(drm_intel_bufmgr_fake *bufmgr_fake, int seq)
286         struct drm_i915_irq_wait iw;
287         int hw_seq, busy_count = 0;
288         int ret;
289         int kernel_lied;
291         if (bufmgr_fake->fence_wait != NULL) {
292                 bufmgr_fake->fence_wait(seq, bufmgr_fake->fence_priv);
293                 clear_fenced(bufmgr_fake, seq);
294                 return;
295         }
297         DBG("wait 0x%08x\n", iw.irq_seq);
299         iw.irq_seq = seq;
301         /* The kernel IRQ_WAIT implementation is all sorts of broken.
302          * 1) It returns 1 to 0x7fffffff instead of using the full 32-bit
303          *    unsigned range.
304          * 2) It returns 0 if hw_seq >= seq, not seq - hw_seq < 0 on the 32-bit
305          *    signed range.
306          * 3) It waits if seq < hw_seq, not seq - hw_seq > 0 on the 32-bit
307          *    signed range.
308          * 4) It returns -EBUSY in 3 seconds even if the hardware is still
309          *    successfully chewing through buffers.
310          *
311          * Assume that in userland we treat sequence numbers as ints, which
312          * makes some of the comparisons convenient, since the sequence
313          * numbers are all postive signed integers.
314          *
315          * From this we get several cases we need to handle.  Here's a timeline.
316          * 0x2   0x7                                    0x7ffffff8   0x7ffffffd
317          *   |    |                                             |    |
318          * ------------------------------------------------------------
319          *
320          * A) Normal wait for hw to catch up
321          * hw_seq seq
322          *   |    |
323          * ------------------------------------------------------------
324          * seq - hw_seq = 5.  If we call IRQ_WAIT, it will wait for hw to
325          * catch up.
326          *
327          * B) Normal wait for a sequence number that's already passed.
328          * seq    hw_seq
329          *   |    |
330          * ------------------------------------------------------------
331          * seq - hw_seq = -5.  If we call IRQ_WAIT, it returns 0 quickly.
332          *
333          * C) Hardware has already wrapped around ahead of us
334          * hw_seq                                                    seq
335          *   |                                                       |
336          * ------------------------------------------------------------
337          * seq - hw_seq = 0x80000000 - 5.  If we called IRQ_WAIT, it would wait
338          * for hw_seq >= seq, which may never occur.  Thus, we want to catch
339          * this in userland and return 0.
340          *
341          * D) We've wrapped around ahead of the hardware.
342          * seq                                                      hw_seq
343          *   |                                                       |
344          * ------------------------------------------------------------
345          * seq - hw_seq = -(0x80000000 - 5).  If we called IRQ_WAIT, it would
346          * return 0 quickly because hw_seq >= seq, even though the hardware
347          * isn't caught up. Thus, we need to catch this early return in
348          * userland and bother the kernel until the hardware really does
349          * catch up.
350          *
351          * E) Hardware might wrap after we test in userland.
352          *                                                  hw_seq  seq
353          *                                                      |    |
354          * ------------------------------------------------------------
355          * seq - hw_seq = 5.  If we call IRQ_WAIT, it will likely see seq >=
356          * hw_seq and wait.  However, suppose hw_seq wraps before we make it
357          * into the kernel.  The kernel sees hw_seq >= seq and waits for 3
358          * seconds then returns -EBUSY.  This is case C).  We should catch
359          * this and then return successfully.
360          *
361          * F) Hardware might take a long time on a buffer.
362          * hw_seq seq
363          *   |    |
364          * -------------------------------------------------------------------
365          * seq - hw_seq = 5.  If we call IRQ_WAIT, if sequence 2 through 5
366          * take too long, it will return -EBUSY.  Batchbuffers in the
367          * gltestperf demo were seen to take up to 7 seconds.  We should
368          * catch early -EBUSY return and keep trying.
369          */
371         do {
372                 /* Keep a copy of last_dispatch so that if the wait -EBUSYs
373                  * because the hardware didn't catch up in 3 seconds, we can
374                  * see if it at least made progress and retry.
375                  */
376                 hw_seq = *bufmgr_fake->last_dispatch;
378                 /* Catch case C */
379                 if (seq - hw_seq > 0x40000000)
380                         return;
382                 ret = drmCommandWrite(bufmgr_fake->fd, DRM_I915_IRQ_WAIT,
383                                       &iw, sizeof(iw));
384                 /* Catch case D */
385                 kernel_lied = (ret == 0) && (seq - *bufmgr_fake->last_dispatch <
386                                              -0x40000000);
388                 /* Catch case E */
389                 if (ret == -EBUSY
390                     && (seq - *bufmgr_fake->last_dispatch > 0x40000000))
391                         ret = 0;
393                 /* Catch case F: Allow up to 15 seconds chewing on one buffer. */
394                 if ((ret == -EBUSY) && (hw_seq != *bufmgr_fake->last_dispatch))
395                         busy_count = 0;
396                 else
397                         busy_count++;
398         } while (kernel_lied || ret == -EAGAIN || ret == -EINTR ||
399                  (ret == -EBUSY && busy_count < 5));
401         if (ret != 0) {
402                 drmMsg("%s:%d: Error waiting for fence: %s.\n", __FILE__,
403                        __LINE__, strerror(-ret));
404                 abort();
405         }
406         clear_fenced(bufmgr_fake, seq);
409 static int
410 _fence_test(drm_intel_bufmgr_fake *bufmgr_fake, unsigned fence)
412         /* Slight problem with wrap-around:
413          */
414         return fence == 0 || FENCE_LTE(fence, bufmgr_fake->last_fence);
417 /**
418  * Allocate a memory manager block for the buffer.
419  */
420 static int
421 alloc_block(drm_intel_bo *bo)
423         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
424         drm_intel_bufmgr_fake *bufmgr_fake =
425             (drm_intel_bufmgr_fake *) bo->bufmgr;
426         struct block *block = (struct block *)calloc(sizeof *block, 1);
427         unsigned int align_log2 = ffs(bo_fake->alignment) - 1;
428         unsigned int sz;
430         if (!block)
431                 return 1;
433         sz = (bo->size + bo_fake->alignment - 1) & ~(bo_fake->alignment - 1);
435         block->mem = mmAllocMem(bufmgr_fake->heap, sz, align_log2, 0);
436         if (!block->mem) {
437                 free(block);
438                 return 0;
439         }
441         DRMINITLISTHEAD(block);
443         /* Insert at head or at tail??? */
444         DRMLISTADDTAIL(block, &bufmgr_fake->lru);
446         block->virtual = (uint8_t *) bufmgr_fake->virtual +
447             block->mem->ofs - bufmgr_fake->low_offset;
448         block->bo = bo;
450         bo_fake->block = block;
452         return 1;
455 /* Release the card storage associated with buf:
456  */
457 static void
458 free_block(drm_intel_bufmgr_fake *bufmgr_fake, struct block *block,
459            int skip_dirty_copy)
461         drm_intel_bo_fake *bo_fake;
462         DBG("free block %p %08x %d %d\n", block, block->mem->ofs,
463             block->on_hardware, block->fenced);
465         if (!block)
466                 return;
468         bo_fake = (drm_intel_bo_fake *) block->bo;
470         if (bo_fake->flags & (BM_PINNED | BM_NO_BACKING_STORE))
471                 skip_dirty_copy = 1;
473         if (!skip_dirty_copy && (bo_fake->card_dirty == 1)) {
474                 memcpy(bo_fake->backing_store, block->virtual, block->bo->size);
475                 bo_fake->card_dirty = 0;
476                 bo_fake->dirty = 1;
477         }
479         if (block->on_hardware) {
480                 block->bo = NULL;
481         } else if (block->fenced) {
482                 block->bo = NULL;
483         } else {
484                 DBG("    - free immediately\n");
485                 DRMLISTDEL(block);
487                 mmFreeMem(block->mem);
488                 free(block);
489         }
492 static void
493 alloc_backing_store(drm_intel_bo *bo)
495         drm_intel_bufmgr_fake *bufmgr_fake =
496             (drm_intel_bufmgr_fake *) bo->bufmgr;
497         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
498         assert(!bo_fake->backing_store);
499         assert(!(bo_fake->flags & (BM_PINNED | BM_NO_BACKING_STORE)));
501         bo_fake->backing_store = malloc(bo->size);
503         DBG("alloc_backing - buf %d %p %d\n", bo_fake->id,
504             bo_fake->backing_store, bo->size);
505         assert(bo_fake->backing_store);
508 static void
509 free_backing_store(drm_intel_bo *bo)
511         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
513         if (bo_fake->backing_store) {
514                 assert(!(bo_fake->flags & (BM_PINNED | BM_NO_BACKING_STORE)));
515                 free(bo_fake->backing_store);
516                 bo_fake->backing_store = NULL;
517         }
520 static void
521 set_dirty(drm_intel_bo *bo)
523         drm_intel_bufmgr_fake *bufmgr_fake =
524             (drm_intel_bufmgr_fake *) bo->bufmgr;
525         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
527         if (bo_fake->flags & BM_NO_BACKING_STORE
528             && bo_fake->invalidate_cb != NULL)
529                 bo_fake->invalidate_cb(bo, bo_fake->invalidate_ptr);
531         assert(!(bo_fake->flags & BM_PINNED));
533         DBG("set_dirty - buf %d\n", bo_fake->id);
534         bo_fake->dirty = 1;
537 static int
538 evict_lru(drm_intel_bufmgr_fake *bufmgr_fake, unsigned int max_fence)
540         struct block *block, *tmp;
542         DBG("%s\n", __FUNCTION__);
544         DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) {
545                 drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo;
547                 if (bo_fake != NULL && (bo_fake->flags & BM_NO_FENCE_SUBDATA))
548                         continue;
550                 if (block->fence && max_fence && !FENCE_LTE(block->fence,
551                                                             max_fence))
552                         return 0;
554                 set_dirty(&bo_fake->bo);
555                 bo_fake->block = NULL;
557                 free_block(bufmgr_fake, block, 0);
558                 return 1;
559         }
561         return 0;
564 static int
565 evict_mru(drm_intel_bufmgr_fake *bufmgr_fake)
567         struct block *block, *tmp;
569         DBG("%s\n", __FUNCTION__);
571         DRMLISTFOREACHSAFEREVERSE(block, tmp, &bufmgr_fake->lru) {
572                 drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo;
574                 if (bo_fake && (bo_fake->flags & BM_NO_FENCE_SUBDATA))
575                         continue;
577                 set_dirty(&bo_fake->bo);
578                 bo_fake->block = NULL;
580                 free_block(bufmgr_fake, block, 0);
581                 return 1;
582         }
584         return 0;
587 /**
588  * Removes all objects from the fenced list older than the given fence.
589  */
590 static int
591 clear_fenced(drm_intel_bufmgr_fake *bufmgr_fake, unsigned int fence_cookie)
593         struct block *block, *tmp;
594         int ret = 0;
596         bufmgr_fake->last_fence = fence_cookie;
597         DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->fenced) {
598                 assert(block->fenced);
600                 if (_fence_test(bufmgr_fake, block->fence)) {
602                         block->fenced = 0;
604                         if (!block->bo) {
605                                 DBG("delayed free: offset %x sz %x\n",
606                                     block->mem->ofs, block->mem->size);
607                                 DRMLISTDEL(block);
608                                 mmFreeMem(block->mem);
609                                 free(block);
610                         } else {
611                                 DBG("return to lru: offset %x sz %x\n",
612                                     block->mem->ofs, block->mem->size);
613                                 DRMLISTDEL(block);
614                                 DRMLISTADDTAIL(block, &bufmgr_fake->lru);
615                         }
617                         ret = 1;
618                 } else {
619                         /* Blocks are ordered by fence, so if one fails, all
620                          * from here will fail also:
621                          */
622                         DBG("fence not passed: offset %x sz %x %d %d \n",
623                             block->mem->ofs, block->mem->size, block->fence,
624                             bufmgr_fake->last_fence);
625                         break;
626                 }
627         }
629         DBG("%s: %d\n", __FUNCTION__, ret);
630         return ret;
633 static void
634 fence_blocks(drm_intel_bufmgr_fake *bufmgr_fake, unsigned fence)
636         struct block *block, *tmp;
638         DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->on_hardware) {
639                 DBG("Fence block %p (sz 0x%x ofs %x buf %p) with fence %d\n",
640                     block, block->mem->size, block->mem->ofs, block->bo, fence);
641                 block->fence = fence;
643                 block->on_hardware = 0;
644                 block->fenced = 1;
646                 /* Move to tail of pending list here
647                  */
648                 DRMLISTDEL(block);
649                 DRMLISTADDTAIL(block, &bufmgr_fake->fenced);
650         }
652         assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware));
655 static int
656 evict_and_alloc_block(drm_intel_bo *bo)
658         drm_intel_bufmgr_fake *bufmgr_fake =
659             (drm_intel_bufmgr_fake *) bo->bufmgr;
660         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
662         assert(bo_fake->block == NULL);
664         /* Search for already free memory:
665          */
666         if (alloc_block(bo))
667                 return 1;
669         /* If we're not thrashing, allow lru eviction to dig deeper into
670          * recently used textures.  We'll probably be thrashing soon:
671          */
672         if (!bufmgr_fake->thrashing) {
673                 while (evict_lru(bufmgr_fake, 0))
674                         if (alloc_block(bo))
675                                 return 1;
676         }
678         /* Keep thrashing counter alive?
679          */
680         if (bufmgr_fake->thrashing)
681                 bufmgr_fake->thrashing = 20;
683         /* Wait on any already pending fences - here we are waiting for any
684          * freed memory that has been submitted to hardware and fenced to
685          * become available:
686          */
687         while (!DRMLISTEMPTY(&bufmgr_fake->fenced)) {
688                 uint32_t fence = bufmgr_fake->fenced.next->fence;
689                 _fence_wait_internal(bufmgr_fake, fence);
691                 if (alloc_block(bo))
692                         return 1;
693         }
695         if (!DRMLISTEMPTY(&bufmgr_fake->on_hardware)) {
696                 while (!DRMLISTEMPTY(&bufmgr_fake->fenced)) {
697                         uint32_t fence = bufmgr_fake->fenced.next->fence;
698                         _fence_wait_internal(bufmgr_fake, fence);
699                 }
701                 if (!bufmgr_fake->thrashing) {
702                         DBG("thrashing\n");
703                 }
704                 bufmgr_fake->thrashing = 20;
706                 if (alloc_block(bo))
707                         return 1;
708         }
710         while (evict_mru(bufmgr_fake))
711                 if (alloc_block(bo))
712                         return 1;
714         DBG("%s 0x%x bytes failed\n", __FUNCTION__, bo->size);
716         return 0;
719 /***********************************************************************
720  * Public functions
721  */
723 /**
724  * Wait for hardware idle by emitting a fence and waiting for it.
725  */
726 static void
727 drm_intel_bufmgr_fake_wait_idle(drm_intel_bufmgr_fake *bufmgr_fake)
729         unsigned int cookie;
731         cookie = _fence_emit_internal(bufmgr_fake);
732         _fence_wait_internal(bufmgr_fake, cookie);
735 /**
736  * Wait for rendering to a buffer to complete.
737  *
738  * It is assumed that the bathcbuffer which performed the rendering included
739  * the necessary flushing.
740  */
741 static void
742 drm_intel_fake_bo_wait_rendering_locked(drm_intel_bo *bo)
744         drm_intel_bufmgr_fake *bufmgr_fake =
745             (drm_intel_bufmgr_fake *) bo->bufmgr;
746         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
748         if (bo_fake->block == NULL || !bo_fake->block->fenced)
749                 return;
751         _fence_wait_internal(bufmgr_fake, bo_fake->block->fence);
754 static void
755 drm_intel_fake_bo_wait_rendering(drm_intel_bo *bo)
757         drm_intel_bufmgr_fake *bufmgr_fake =
758             (drm_intel_bufmgr_fake *) bo->bufmgr;
760         pthread_mutex_lock(&bufmgr_fake->lock);
761         drm_intel_fake_bo_wait_rendering_locked(bo);
762         pthread_mutex_unlock(&bufmgr_fake->lock);
765 /* Specifically ignore texture memory sharing.
766  *  -- just evict everything
767  *  -- and wait for idle
768  */
769 void
770 drm_intel_bufmgr_fake_contended_lock_take(drm_intel_bufmgr *bufmgr)
772         drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
773         struct block *block, *tmp;
775         pthread_mutex_lock(&bufmgr_fake->lock);
777         bufmgr_fake->need_fence = 1;
778         bufmgr_fake->fail = 0;
780         /* Wait for hardware idle.  We don't know where acceleration has been
781          * happening, so we'll need to wait anyway before letting anything get
782          * put on the card again.
783          */
784         drm_intel_bufmgr_fake_wait_idle(bufmgr_fake);
786         /* Check that we hadn't released the lock without having fenced the last
787          * set of buffers.
788          */
789         assert(DRMLISTEMPTY(&bufmgr_fake->fenced));
790         assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware));
792         DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) {
793                 assert(_fence_test(bufmgr_fake, block->fence));
794                 set_dirty(block->bo);
795         }
797         pthread_mutex_unlock(&bufmgr_fake->lock);
800 static drm_intel_bo *
801 drm_intel_fake_bo_alloc(drm_intel_bufmgr *bufmgr,
802                         const char *name,
803                         unsigned long size,
804                         unsigned int alignment)
806         drm_intel_bufmgr_fake *bufmgr_fake;
807         drm_intel_bo_fake *bo_fake;
809         bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
811         assert(size != 0);
813         bo_fake = calloc(1, sizeof(*bo_fake));
814         if (!bo_fake)
815                 return NULL;
817         bo_fake->bo.size = size;
818         bo_fake->bo.offset = -1;
819         bo_fake->bo.virtual = NULL;
820         bo_fake->bo.bufmgr = bufmgr;
821         bo_fake->refcount = 1;
823         /* Alignment must be a power of two */
824         assert((alignment & (alignment - 1)) == 0);
825         if (alignment == 0)
826                 alignment = 1;
827         bo_fake->alignment = alignment;
828         bo_fake->id = ++bufmgr_fake->buf_nr;
829         bo_fake->name = name;
830         bo_fake->flags = 0;
831         bo_fake->is_static = 0;
833         DBG("drm_bo_alloc: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name,
834             bo_fake->bo.size / 1024);
836         return &bo_fake->bo;
839 static drm_intel_bo *
840 drm_intel_fake_bo_alloc_tiled(drm_intel_bufmgr * bufmgr,
841                               const char *name,
842                               int x, int y, int cpp,
843                               uint32_t *tiling_mode,
844                               unsigned long *pitch,
845                               unsigned long flags)
847         unsigned long stride, aligned_y;
849         /* No runtime tiling support for fake. */
850         *tiling_mode = I915_TILING_NONE;
852         /* Align it for being a render target.  Shouldn't need anything else. */
853         stride = x * cpp;
854         stride = ROUND_UP_TO(stride, 64);
856         /* 965 subspan loading alignment */
857         aligned_y = ALIGN(y, 2);
859         *pitch = stride;
861         return drm_intel_fake_bo_alloc(bufmgr, name, stride * aligned_y,
862                                        4096);
865 drm_intel_bo *
866 drm_intel_bo_fake_alloc_static(drm_intel_bufmgr *bufmgr,
867                                const char *name,
868                                unsigned long offset,
869                                unsigned long size, void *virtual)
871         drm_intel_bufmgr_fake *bufmgr_fake;
872         drm_intel_bo_fake *bo_fake;
874         bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
876         assert(size != 0);
878         bo_fake = calloc(1, sizeof(*bo_fake));
879         if (!bo_fake)
880                 return NULL;
882         bo_fake->bo.size = size;
883         bo_fake->bo.offset = offset;
884         bo_fake->bo.virtual = virtual;
885         bo_fake->bo.bufmgr = bufmgr;
886         bo_fake->refcount = 1;
887         bo_fake->id = ++bufmgr_fake->buf_nr;
888         bo_fake->name = name;
889         bo_fake->flags = BM_PINNED;
890         bo_fake->is_static = 1;
892         DBG("drm_bo_alloc_static: (buf %d: %s, %d kb)\n", bo_fake->id,
893             bo_fake->name, bo_fake->bo.size / 1024);
895         return &bo_fake->bo;
898 static void
899 drm_intel_fake_bo_reference(drm_intel_bo *bo)
901         drm_intel_bufmgr_fake *bufmgr_fake =
902             (drm_intel_bufmgr_fake *) bo->bufmgr;
903         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
905         pthread_mutex_lock(&bufmgr_fake->lock);
906         bo_fake->refcount++;
907         pthread_mutex_unlock(&bufmgr_fake->lock);
910 static void
911 drm_intel_fake_bo_reference_locked(drm_intel_bo *bo)
913         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
915         bo_fake->refcount++;
918 static void
919 drm_intel_fake_bo_unreference_locked(drm_intel_bo *bo)
921         drm_intel_bufmgr_fake *bufmgr_fake =
922             (drm_intel_bufmgr_fake *) bo->bufmgr;
923         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
924         int i;
926         if (--bo_fake->refcount == 0) {
927                 assert(bo_fake->map_count == 0);
928                 /* No remaining references, so free it */
929                 if (bo_fake->block)
930                         free_block(bufmgr_fake, bo_fake->block, 1);
931                 free_backing_store(bo);
933                 for (i = 0; i < bo_fake->nr_relocs; i++)
934                         drm_intel_fake_bo_unreference_locked(bo_fake->relocs[i].
935                                                              target_buf);
937                 DBG("drm_bo_unreference: free buf %d %s\n", bo_fake->id,
938                     bo_fake->name);
940                 free(bo_fake->relocs);
941                 free(bo);
942         }
945 static void
946 drm_intel_fake_bo_unreference(drm_intel_bo *bo)
948         drm_intel_bufmgr_fake *bufmgr_fake =
949             (drm_intel_bufmgr_fake *) bo->bufmgr;
951         pthread_mutex_lock(&bufmgr_fake->lock);
952         drm_intel_fake_bo_unreference_locked(bo);
953         pthread_mutex_unlock(&bufmgr_fake->lock);
956 /**
957  * Set the buffer as not requiring backing store, and instead get the callback
958  * invoked whenever it would be set dirty.
959  */
960 void
961 drm_intel_bo_fake_disable_backing_store(drm_intel_bo *bo,
962                                         void (*invalidate_cb) (drm_intel_bo *bo,
963                                                                void *ptr),
964                                         void *ptr)
966         drm_intel_bufmgr_fake *bufmgr_fake =
967             (drm_intel_bufmgr_fake *) bo->bufmgr;
968         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
970         pthread_mutex_lock(&bufmgr_fake->lock);
972         if (bo_fake->backing_store)
973                 free_backing_store(bo);
975         bo_fake->flags |= BM_NO_BACKING_STORE;
977         DBG("disable_backing_store set buf %d dirty\n", bo_fake->id);
978         bo_fake->dirty = 1;
979         bo_fake->invalidate_cb = invalidate_cb;
980         bo_fake->invalidate_ptr = ptr;
982         /* Note that it is invalid right from the start.  Also note
983          * invalidate_cb is called with the bufmgr locked, so cannot
984          * itself make bufmgr calls.
985          */
986         if (invalidate_cb != NULL)
987                 invalidate_cb(bo, ptr);
989         pthread_mutex_unlock(&bufmgr_fake->lock);
992 /**
993  * Map a buffer into bo->virtual, allocating either card memory space (If
994  * BM_NO_BACKING_STORE or BM_PINNED) or backing store, as necessary.
995  */
996 static int
997  drm_intel_fake_bo_map_locked(drm_intel_bo *bo, int write_enable)
999         drm_intel_bufmgr_fake *bufmgr_fake =
1000             (drm_intel_bufmgr_fake *) bo->bufmgr;
1001         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
1003         /* Static buffers are always mapped. */
1004         if (bo_fake->is_static) {
1005                 if (bo_fake->card_dirty) {
1006                         drm_intel_bufmgr_fake_wait_idle(bufmgr_fake);
1007                         bo_fake->card_dirty = 0;
1008                 }
1009                 return 0;
1010         }
1012         /* Allow recursive mapping.  Mesa may recursively map buffers with
1013          * nested display loops, and it is used internally in bufmgr_fake
1014          * for relocation.
1015          */
1016         if (bo_fake->map_count++ != 0)
1017                 return 0;
1019         {
1020                 DBG("drm_bo_map: (buf %d: %s, %d kb)\n", bo_fake->id,
1021                     bo_fake->name, bo_fake->bo.size / 1024);
1023                 if (bo->virtual != NULL) {
1024                         drmMsg("%s: already mapped\n", __FUNCTION__);
1025                         abort();
1026                 } else if (bo_fake->flags & (BM_NO_BACKING_STORE | BM_PINNED)) {
1028                         if (!bo_fake->block && !evict_and_alloc_block(bo)) {
1029                                 DBG("%s: alloc failed\n", __FUNCTION__);
1030                                 bufmgr_fake->fail = 1;
1031                                 return 1;
1032                         } else {
1033                                 assert(bo_fake->block);
1034                                 bo_fake->dirty = 0;
1036                                 if (!(bo_fake->flags & BM_NO_FENCE_SUBDATA) &&
1037                                     bo_fake->block->fenced) {
1038                                         drm_intel_fake_bo_wait_rendering_locked
1039                                             (bo);
1040                                 }
1042                                 bo->virtual = bo_fake->block->virtual;
1043                         }
1044                 } else {
1045                         if (write_enable)
1046                                 set_dirty(bo);
1048                         if (bo_fake->backing_store == 0)
1049                                 alloc_backing_store(bo);
1051                         if ((bo_fake->card_dirty == 1) && bo_fake->block) {
1052                                 if (bo_fake->block->fenced)
1053                                         drm_intel_fake_bo_wait_rendering_locked
1054                                             (bo);
1056                                 memcpy(bo_fake->backing_store,
1057                                        bo_fake->block->virtual,
1058                                        bo_fake->block->bo->size);
1059                                 bo_fake->card_dirty = 0;
1060                         }
1062                         bo->virtual = bo_fake->backing_store;
1063                 }
1064         }
1066         return 0;
1069 static int
1070  drm_intel_fake_bo_map(drm_intel_bo *bo, int write_enable)
1072         drm_intel_bufmgr_fake *bufmgr_fake =
1073             (drm_intel_bufmgr_fake *) bo->bufmgr;
1074         int ret;
1076         pthread_mutex_lock(&bufmgr_fake->lock);
1077         ret = drm_intel_fake_bo_map_locked(bo, write_enable);
1078         pthread_mutex_unlock(&bufmgr_fake->lock);
1080         return ret;
1083 static int
1084  drm_intel_fake_bo_unmap_locked(drm_intel_bo *bo)
1086         drm_intel_bufmgr_fake *bufmgr_fake =
1087             (drm_intel_bufmgr_fake *) bo->bufmgr;
1088         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
1090         /* Static buffers are always mapped. */
1091         if (bo_fake->is_static)
1092                 return 0;
1094         assert(bo_fake->map_count != 0);
1095         if (--bo_fake->map_count != 0)
1096                 return 0;
1098         DBG("drm_bo_unmap: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name,
1099             bo_fake->bo.size / 1024);
1101         bo->virtual = NULL;
1103         return 0;
1106 static int drm_intel_fake_bo_unmap(drm_intel_bo *bo)
1108         drm_intel_bufmgr_fake *bufmgr_fake =
1109             (drm_intel_bufmgr_fake *) bo->bufmgr;
1110         int ret;
1112         pthread_mutex_lock(&bufmgr_fake->lock);
1113         ret = drm_intel_fake_bo_unmap_locked(bo);
1114         pthread_mutex_unlock(&bufmgr_fake->lock);
1116         return ret;
1119 static void
1120  drm_intel_fake_kick_all_locked(drm_intel_bufmgr_fake *bufmgr_fake)
1122         struct block *block, *tmp;
1124         bufmgr_fake->performed_rendering = 0;
1125         /* okay for ever BO that is on the HW kick it off.
1126            seriously not afraid of the POLICE right now */
1127         DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->on_hardware) {
1128                 drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo;
1130                 block->on_hardware = 0;
1131                 free_block(bufmgr_fake, block, 0);
1132                 bo_fake->block = NULL;
1133                 bo_fake->validated = 0;
1134                 if (!(bo_fake->flags & BM_NO_BACKING_STORE))
1135                         bo_fake->dirty = 1;
1136         }
1140 static int
1141  drm_intel_fake_bo_validate(drm_intel_bo *bo)
1143         drm_intel_bufmgr_fake *bufmgr_fake;
1144         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
1146         bufmgr_fake = (drm_intel_bufmgr_fake *) bo->bufmgr;
1148         DBG("drm_bo_validate: (buf %d: %s, %d kb)\n", bo_fake->id,
1149             bo_fake->name, bo_fake->bo.size / 1024);
1151         /* Sanity check: Buffers should be unmapped before being validated.
1152          * This is not so much of a problem for bufmgr_fake, but TTM refuses,
1153          * and the problem is harder to debug there.
1154          */
1155         assert(bo_fake->map_count == 0);
1157         if (bo_fake->is_static) {
1158                 /* Add it to the needs-fence list */
1159                 bufmgr_fake->need_fence = 1;
1160                 return 0;
1161         }
1163         /* Allocate the card memory */
1164         if (!bo_fake->block && !evict_and_alloc_block(bo)) {
1165                 bufmgr_fake->fail = 1;
1166                 DBG("Failed to validate buf %d:%s\n", bo_fake->id,
1167                     bo_fake->name);
1168                 return -1;
1169         }
1171         assert(bo_fake->block);
1172         assert(bo_fake->block->bo == &bo_fake->bo);
1174         bo->offset = bo_fake->block->mem->ofs;
1176         /* Upload the buffer contents if necessary */
1177         if (bo_fake->dirty) {
1178                 DBG("Upload dirty buf %d:%s, sz %d offset 0x%x\n", bo_fake->id,
1179                     bo_fake->name, bo->size, bo_fake->block->mem->ofs);
1181                 assert(!(bo_fake->flags & (BM_NO_BACKING_STORE | BM_PINNED)));
1183                 /* Actually, should be able to just wait for a fence on the
1184                  * mmory, hich we would be tracking when we free it.  Waiting
1185                  * for idle is a sufficiently large hammer for now.
1186                  */
1187                 drm_intel_bufmgr_fake_wait_idle(bufmgr_fake);
1189                 /* we may never have mapped this BO so it might not have any
1190                  * backing store if this happens it should be rare, but 0 the
1191                  * card memory in any case */
1192                 if (bo_fake->backing_store)
1193                         memcpy(bo_fake->block->virtual, bo_fake->backing_store,
1194                                bo->size);
1195                 else
1196                         memset(bo_fake->block->virtual, 0, bo->size);
1198                 bo_fake->dirty = 0;
1199         }
1201         bo_fake->block->fenced = 0;
1202         bo_fake->block->on_hardware = 1;
1203         DRMLISTDEL(bo_fake->block);
1204         DRMLISTADDTAIL(bo_fake->block, &bufmgr_fake->on_hardware);
1206         bo_fake->validated = 1;
1207         bufmgr_fake->need_fence = 1;
1209         return 0;
1212 static void
1213 drm_intel_fake_fence_validated(drm_intel_bufmgr *bufmgr)
1215         drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
1216         unsigned int cookie;
1218         cookie = _fence_emit_internal(bufmgr_fake);
1219         fence_blocks(bufmgr_fake, cookie);
1221         DBG("drm_fence_validated: 0x%08x cookie\n", cookie);
1224 static void
1225 drm_intel_fake_destroy(drm_intel_bufmgr *bufmgr)
1227         drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
1229         pthread_mutex_destroy(&bufmgr_fake->lock);
1230         mmDestroy(bufmgr_fake->heap);
1231         free(bufmgr);
1234 static int
1235 drm_intel_fake_emit_reloc(drm_intel_bo *bo, uint32_t offset,
1236                           drm_intel_bo *target_bo, uint32_t target_offset,
1237                           uint32_t read_domains, uint32_t write_domain)
1239         drm_intel_bufmgr_fake *bufmgr_fake =
1240             (drm_intel_bufmgr_fake *) bo->bufmgr;
1241         struct fake_buffer_reloc *r;
1242         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
1243         drm_intel_bo_fake *target_fake = (drm_intel_bo_fake *) target_bo;
1244         int i;
1246         pthread_mutex_lock(&bufmgr_fake->lock);
1248         assert(bo);
1249         assert(target_bo);
1251         if (bo_fake->relocs == NULL) {
1252                 bo_fake->relocs =
1253                     malloc(sizeof(struct fake_buffer_reloc) * MAX_RELOCS);
1254         }
1256         r = &bo_fake->relocs[bo_fake->nr_relocs++];
1258         assert(bo_fake->nr_relocs <= MAX_RELOCS);
1260         drm_intel_fake_bo_reference_locked(target_bo);
1262         if (!target_fake->is_static) {
1263                 bo_fake->child_size +=
1264                     ALIGN(target_bo->size, target_fake->alignment);
1265                 bo_fake->child_size += target_fake->child_size;
1266         }
1267         r->target_buf = target_bo;
1268         r->offset = offset;
1269         r->last_target_offset = target_bo->offset;
1270         r->delta = target_offset;
1271         r->read_domains = read_domains;
1272         r->write_domain = write_domain;
1274         if (bufmgr_fake->debug) {
1275                 /* Check that a conflicting relocation hasn't already been
1276                  * emitted.
1277                  */
1278                 for (i = 0; i < bo_fake->nr_relocs - 1; i++) {
1279                         struct fake_buffer_reloc *r2 = &bo_fake->relocs[i];
1281                         assert(r->offset != r2->offset);
1282                 }
1283         }
1285         pthread_mutex_unlock(&bufmgr_fake->lock);
1287         return 0;
1290 /**
1291  * Incorporates the validation flags associated with each relocation into
1292  * the combined validation flags for the buffer on this batchbuffer submission.
1293  */
1294 static void
1295 drm_intel_fake_calculate_domains(drm_intel_bo *bo)
1297         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
1298         int i;
1300         for (i = 0; i < bo_fake->nr_relocs; i++) {
1301                 struct fake_buffer_reloc *r = &bo_fake->relocs[i];
1302                 drm_intel_bo_fake *target_fake =
1303                     (drm_intel_bo_fake *) r->target_buf;
1305                 /* Do the same for the tree of buffers we depend on */
1306                 drm_intel_fake_calculate_domains(r->target_buf);
1308                 target_fake->read_domains |= r->read_domains;
1309                 target_fake->write_domain |= r->write_domain;
1310         }
1313 static int
1314 drm_intel_fake_reloc_and_validate_buffer(drm_intel_bo *bo)
1316         drm_intel_bufmgr_fake *bufmgr_fake =
1317             (drm_intel_bufmgr_fake *) bo->bufmgr;
1318         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
1319         int i, ret;
1321         assert(bo_fake->map_count == 0);
1323         for (i = 0; i < bo_fake->nr_relocs; i++) {
1324                 struct fake_buffer_reloc *r = &bo_fake->relocs[i];
1325                 drm_intel_bo_fake *target_fake =
1326                     (drm_intel_bo_fake *) r->target_buf;
1327                 uint32_t reloc_data;
1329                 /* Validate the target buffer if that hasn't been done. */
1330                 if (!target_fake->validated) {
1331                         ret =
1332                             drm_intel_fake_reloc_and_validate_buffer(r->target_buf);
1333                         if (ret != 0) {
1334                                 if (bo->virtual != NULL)
1335                                         drm_intel_fake_bo_unmap_locked(bo);
1336                                 return ret;
1337                         }
1338                 }
1340                 /* Calculate the value of the relocation entry. */
1341                 if (r->target_buf->offset != r->last_target_offset) {
1342                         reloc_data = r->target_buf->offset + r->delta;
1344                         if (bo->virtual == NULL)
1345                                 drm_intel_fake_bo_map_locked(bo, 1);
1347                         *(uint32_t *) ((uint8_t *) bo->virtual + r->offset) =
1348                             reloc_data;
1350                         r->last_target_offset = r->target_buf->offset;
1351                 }
1352         }
1354         if (bo->virtual != NULL)
1355                 drm_intel_fake_bo_unmap_locked(bo);
1357         if (bo_fake->write_domain != 0) {
1358                 if (!(bo_fake->flags & (BM_NO_BACKING_STORE | BM_PINNED))) {
1359                         if (bo_fake->backing_store == 0)
1360                                 alloc_backing_store(bo);
1361                 }
1362                 bo_fake->card_dirty = 1;
1363                 bufmgr_fake->performed_rendering = 1;
1364         }
1366         return drm_intel_fake_bo_validate(bo);
1369 static void
1370 drm_intel_bo_fake_post_submit(drm_intel_bo *bo)
1372         drm_intel_bufmgr_fake *bufmgr_fake =
1373             (drm_intel_bufmgr_fake *) bo->bufmgr;
1374         drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo;
1375         int i;
1377         for (i = 0; i < bo_fake->nr_relocs; i++) {
1378                 struct fake_buffer_reloc *r = &bo_fake->relocs[i];
1379                 drm_intel_bo_fake *target_fake =
1380                     (drm_intel_bo_fake *) r->target_buf;
1382                 if (target_fake->validated)
1383                         drm_intel_bo_fake_post_submit(r->target_buf);
1385                 DBG("%s@0x%08x + 0x%08x -> %s@0x%08x + 0x%08x\n",
1386                     bo_fake->name, (uint32_t) bo->offset, r->offset,
1387                     target_fake->name, (uint32_t) r->target_buf->offset,
1388                     r->delta);
1389         }
1391         assert(bo_fake->map_count == 0);
1392         bo_fake->validated = 0;
1393         bo_fake->read_domains = 0;
1394         bo_fake->write_domain = 0;
1397 void
1398 drm_intel_bufmgr_fake_set_exec_callback(drm_intel_bufmgr *bufmgr,
1399                                              int (*exec) (drm_intel_bo *bo,
1400                                                           unsigned int used,
1401                                                           void *priv),
1402                                              void *priv)
1404         drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
1406         bufmgr_fake->exec = exec;
1407         bufmgr_fake->exec_priv = priv;
1410 static int
1411 drm_intel_fake_bo_exec(drm_intel_bo *bo, int used,
1412                        drm_clip_rect_t * cliprects, int num_cliprects, int DR4)
1414         drm_intel_bufmgr_fake *bufmgr_fake =
1415             (drm_intel_bufmgr_fake *) bo->bufmgr;
1416         drm_intel_bo_fake *batch_fake = (drm_intel_bo_fake *) bo;
1417         struct drm_i915_batchbuffer batch;
1418         int ret;
1419         int retry_count = 0;
1421         pthread_mutex_lock(&bufmgr_fake->lock);
1423         bufmgr_fake->performed_rendering = 0;
1425         drm_intel_fake_calculate_domains(bo);
1427         batch_fake->read_domains = I915_GEM_DOMAIN_COMMAND;
1429         /* we've ran out of RAM so blow the whole lot away and retry */
1430 restart:
1431         ret = drm_intel_fake_reloc_and_validate_buffer(bo);
1432         if (bufmgr_fake->fail == 1) {
1433                 if (retry_count == 0) {
1434                         retry_count++;
1435                         drm_intel_fake_kick_all_locked(bufmgr_fake);
1436                         bufmgr_fake->fail = 0;
1437                         goto restart;
1438                 } else          /* dump out the memory here */
1439                         mmDumpMemInfo(bufmgr_fake->heap);
1440         }
1442         assert(ret == 0);
1444         if (bufmgr_fake->exec != NULL) {
1445                 int ret = bufmgr_fake->exec(bo, used, bufmgr_fake->exec_priv);
1446                 if (ret != 0) {
1447                         pthread_mutex_unlock(&bufmgr_fake->lock);
1448                         return ret;
1449                 }
1450         } else {
1451                 batch.start = bo->offset;
1452                 batch.used = used;
1453                 batch.cliprects = cliprects;
1454                 batch.num_cliprects = num_cliprects;
1455                 batch.DR1 = 0;
1456                 batch.DR4 = DR4;
1458                 if (drmCommandWrite
1459                     (bufmgr_fake->fd, DRM_I915_BATCHBUFFER, &batch,
1460                      sizeof(batch))) {
1461                         drmMsg("DRM_I915_BATCHBUFFER: %d\n", -errno);
1462                         pthread_mutex_unlock(&bufmgr_fake->lock);
1463                         return -errno;
1464                 }
1465         }
1467         drm_intel_fake_fence_validated(bo->bufmgr);
1469         drm_intel_bo_fake_post_submit(bo);
1471         pthread_mutex_unlock(&bufmgr_fake->lock);
1473         return 0;
1476 /**
1477  * Return an error if the list of BOs will exceed the aperture size.
1478  *
1479  * This is a rough guess and likely to fail, as during the validate sequence we
1480  * may place a buffer in an inopportune spot early on and then fail to fit
1481  * a set smaller than the aperture.
1482  */
1483 static int
1484 drm_intel_fake_check_aperture_space(drm_intel_bo ** bo_array, int count)
1486         drm_intel_bufmgr_fake *bufmgr_fake =
1487             (drm_intel_bufmgr_fake *) bo_array[0]->bufmgr;
1488         unsigned int sz = 0;
1489         int i;
1491         for (i = 0; i < count; i++) {
1492                 drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo_array[i];
1494                 if (bo_fake == NULL)
1495                         continue;
1497                 if (!bo_fake->is_static)
1498                         sz += ALIGN(bo_array[i]->size, bo_fake->alignment);
1499                 sz += bo_fake->child_size;
1500         }
1502         if (sz > bufmgr_fake->size) {
1503                 DBG("check_space: overflowed bufmgr size, %dkb vs %dkb\n",
1504                     sz / 1024, bufmgr_fake->size / 1024);
1505                 return -1;
1506         }
1508         DBG("drm_check_space: sz %dkb vs bufgr %dkb\n", sz / 1024,
1509             bufmgr_fake->size / 1024);
1510         return 0;
1513 /**
1514  * Evicts all buffers, waiting for fences to pass and copying contents out
1515  * as necessary.
1516  *
1517  * Used by the X Server on LeaveVT, when the card memory is no longer our
1518  * own.
1519  */
1520 void drm_intel_bufmgr_fake_evict_all(drm_intel_bufmgr *bufmgr)
1522         drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
1523         struct block *block, *tmp;
1525         pthread_mutex_lock(&bufmgr_fake->lock);
1527         bufmgr_fake->need_fence = 1;
1528         bufmgr_fake->fail = 0;
1530         /* Wait for hardware idle.  We don't know where acceleration has been
1531          * happening, so we'll need to wait anyway before letting anything get
1532          * put on the card again.
1533          */
1534         drm_intel_bufmgr_fake_wait_idle(bufmgr_fake);
1536         /* Check that we hadn't released the lock without having fenced the last
1537          * set of buffers.
1538          */
1539         assert(DRMLISTEMPTY(&bufmgr_fake->fenced));
1540         assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware));
1542         DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) {
1543                 drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo;
1544                 /* Releases the memory, and memcpys dirty contents out if
1545                  * necessary.
1546                  */
1547                 free_block(bufmgr_fake, block, 0);
1548                 bo_fake->block = NULL;
1549         }
1551         pthread_mutex_unlock(&bufmgr_fake->lock);
1554 void drm_intel_bufmgr_fake_set_last_dispatch(drm_intel_bufmgr *bufmgr,
1555                                              volatile unsigned int
1556                                              *last_dispatch)
1558         drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr;
1560         bufmgr_fake->last_dispatch = (volatile int *)last_dispatch;
1563 drm_intel_bufmgr *drm_intel_bufmgr_fake_init(int fd,
1564                                              unsigned long low_offset,
1565                                              void *low_virtual,
1566                                              unsigned long size,
1567                                              volatile unsigned int
1568                                              *last_dispatch)
1570         drm_intel_bufmgr_fake *bufmgr_fake;
1572         bufmgr_fake = calloc(1, sizeof(*bufmgr_fake));
1574         if (pthread_mutex_init(&bufmgr_fake->lock, NULL) != 0) {
1575                 free(bufmgr_fake);
1576                 return NULL;
1577         }
1579         /* Initialize allocator */
1580         DRMINITLISTHEAD(&bufmgr_fake->fenced);
1581         DRMINITLISTHEAD(&bufmgr_fake->on_hardware);
1582         DRMINITLISTHEAD(&bufmgr_fake->lru);
1584         bufmgr_fake->low_offset = low_offset;
1585         bufmgr_fake->virtual = low_virtual;
1586         bufmgr_fake->size = size;
1587         bufmgr_fake->heap = mmInit(low_offset, size);
1589         /* Hook in methods */
1590         bufmgr_fake->bufmgr.bo_alloc = drm_intel_fake_bo_alloc;
1591         bufmgr_fake->bufmgr.bo_alloc_for_render = drm_intel_fake_bo_alloc;
1592         bufmgr_fake->bufmgr.bo_alloc_tiled = drm_intel_fake_bo_alloc_tiled;
1593         bufmgr_fake->bufmgr.bo_reference = drm_intel_fake_bo_reference;
1594         bufmgr_fake->bufmgr.bo_unreference = drm_intel_fake_bo_unreference;
1595         bufmgr_fake->bufmgr.bo_map = drm_intel_fake_bo_map;
1596         bufmgr_fake->bufmgr.bo_unmap = drm_intel_fake_bo_unmap;
1597         bufmgr_fake->bufmgr.bo_wait_rendering =
1598             drm_intel_fake_bo_wait_rendering;
1599         bufmgr_fake->bufmgr.bo_emit_reloc = drm_intel_fake_emit_reloc;
1600         bufmgr_fake->bufmgr.destroy = drm_intel_fake_destroy;
1601         bufmgr_fake->bufmgr.bo_exec = drm_intel_fake_bo_exec;
1602         bufmgr_fake->bufmgr.check_aperture_space =
1603             drm_intel_fake_check_aperture_space;
1604         bufmgr_fake->bufmgr.debug = 0;
1606         bufmgr_fake->fd = fd;
1607         bufmgr_fake->last_dispatch = (volatile int *)last_dispatch;
1609         return &bufmgr_fake->bufmgr;