Fix and hook up bufmgr code to the build.
[profile/ivi/libdrm.git] / libdrm / intel / intel_bufmgr_gem.c
1 /**************************************************************************
2  *
3  * Copyright © 2007 Red Hat Inc.
4  * Copyright © 2007 Intel Corporation
5  * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
6  * All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the
10  * "Software"), to deal in the Software without restriction, including
11  * without limitation the rights to use, copy, modify, merge, publish,
12  * distribute, sub license, and/or sell copies of the Software, and to
13  * permit persons to whom the Software is furnished to do so, subject to
14  * the following conditions:
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
20  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22  * USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * The above copyright notice and this permission notice (including the
25  * next paragraph) shall be included in all copies or substantial portions
26  * of the Software.
27  *
28  *
29  **************************************************************************/
30 /*
31  * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
32  *          Keith Whitwell <keithw-at-tungstengraphics-dot-com>
33  *          Eric Anholt <eric@anholt.net>
34  *          Dave Airlie <airlied@linux.ie>
35  */
36
37 #include <xf86drm.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <assert.h>
43 #include <sys/ioctl.h>
44 #include <sys/mman.h>
45
46 #include "errno.h"
47 #include "dri_bufmgr.h"
48 #include "intel_bufmgr.h"
49 #include "string.h"
50
51 #include "i915_drm.h"
52
53 #define DBG(...) do {                                   \
54    if (bufmgr_gem->bufmgr.debug)                        \
55       fprintf(stderr, __VA_ARGS__);                     \
56 } while (0)
57
58 struct intel_validate_entry {
59     dri_bo *bo;
60     struct drm_i915_op_arg bo_arg;
61 };
62
63 struct dri_gem_bo_bucket_entry {
64    uint32_t gem_handle;
65    uint32_t last_offset;
66    struct dri_gem_bo_bucket_entry *next;
67 };
68
69 struct dri_gem_bo_bucket {
70    struct dri_gem_bo_bucket_entry *head;
71    struct dri_gem_bo_bucket_entry **tail;
72    /**
73     * Limit on the number of entries in this bucket.
74     *
75     * 0 means that this caching at this bucket size is disabled.
76     * -1 means that there is no limit to caching at this size.
77     */
78    int max_entries;
79    int num_entries;
80 };
81
82 /* Arbitrarily chosen, 16 means that the maximum size we'll cache for reuse
83  * is 1 << 16 pages, or 256MB.
84  */
85 #define INTEL_GEM_BO_BUCKETS    16
86 typedef struct _dri_bufmgr_gem {
87     dri_bufmgr bufmgr;
88
89     struct intel_bufmgr intel_bufmgr;
90
91     int fd;
92
93     int max_relocs;
94
95     struct drm_i915_gem_exec_object *exec_objects;
96     dri_bo **exec_bos;
97     int exec_size;
98     int exec_count;
99
100     /** Array of lists of cached gem objects of power-of-two sizes */
101     struct dri_gem_bo_bucket cache_bucket[INTEL_GEM_BO_BUCKETS];
102
103     struct drm_i915_gem_execbuffer exec_arg;
104 } dri_bufmgr_gem;
105
106 typedef struct _dri_bo_gem {
107     dri_bo bo;
108
109     int refcount;
110     /** Boolean whether the mmap ioctl has been called for this buffer yet. */
111     int mapped;
112     uint32_t gem_handle;
113     const char *name;
114
115     /**
116      * Index of the buffer within the validation list while preparing a
117      * batchbuffer execution.
118      */
119     int validate_index;
120
121     /**
122      * Boolean whether set_domain to CPU is current
123      * Set when set_domain has been called
124      * Cleared when a batch has been submitted
125      */
126     int cpu_domain_set;
127
128     /** Array passed to the DRM containing relocation information. */
129     struct drm_i915_gem_relocation_entry *relocs;
130     /** Array of bos corresponding to relocs[i].target_handle */
131     dri_bo **reloc_target_bo;
132     /** Number of entries in relocs */
133     int reloc_count;
134     /** Mapped address for the buffer */
135     void *virtual;
136 } dri_bo_gem;
137
138 static int
139 logbase2(int n)
140 {
141    int i = 1;
142    int log2 = 0;
143
144    while (n > i) {
145       i *= 2;
146       log2++;
147    }
148
149    return log2;
150 }
151
152 static struct dri_gem_bo_bucket *
153 dri_gem_bo_bucket_for_size(dri_bufmgr_gem *bufmgr_gem, unsigned long size)
154 {
155     int i;
156
157     /* We only do buckets in power of two increments */
158     if ((size & (size - 1)) != 0)
159         return NULL;
160
161     /* We should only see sizes rounded to pages. */
162     assert((size % 4096) == 0);
163
164     /* We always allocate in units of pages */
165     i = ffs(size / 4096) - 1;
166     if (i >= INTEL_GEM_BO_BUCKETS)
167         return NULL;
168
169     return &bufmgr_gem->cache_bucket[i];
170 }
171
172
173 static void dri_gem_dump_validation_list(dri_bufmgr_gem *bufmgr_gem)
174 {
175     int i, j;
176
177     for (i = 0; i < bufmgr_gem->exec_count; i++) {
178         dri_bo *bo = bufmgr_gem->exec_bos[i];
179         dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
180
181         if (bo_gem->relocs == NULL) {
182             DBG("%2d: %d (%s)\n", i, bo_gem->gem_handle, bo_gem->name);
183             continue;
184         }
185
186         for (j = 0; j < bo_gem->reloc_count; j++) {
187             dri_bo *target_bo = bo_gem->reloc_target_bo[j];
188             dri_bo_gem *target_gem = (dri_bo_gem *)target_bo;
189
190             DBG("%2d: %d (%s)@0x%08llx -> %d (%s)@0x%08lx + 0x%08x\n",
191                 i,
192                 bo_gem->gem_handle, bo_gem->name, bo_gem->relocs[j].offset,
193                 target_gem->gem_handle, target_gem->name, target_bo->offset,
194                 bo_gem->relocs[j].delta);
195         }
196     }
197 }
198
199 /**
200  * Adds the given buffer to the list of buffers to be validated (moved into the
201  * appropriate memory type) with the next batch submission.
202  *
203  * If a buffer is validated multiple times in a batch submission, it ends up
204  * with the intersection of the memory type flags and the union of the
205  * access flags.
206  */
207 static void
208 intel_add_validate_buffer(dri_bo *bo)
209 {
210     dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
211     dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
212     int index;
213
214     if (bo_gem->validate_index != -1)
215         return;
216
217     /* Extend the array of validation entries as necessary. */
218     if (bufmgr_gem->exec_count == bufmgr_gem->exec_size) {
219         int new_size = bufmgr_gem->exec_size * 2;
220
221         if (new_size == 0)
222             new_size = 5;
223
224         bufmgr_gem->exec_objects =
225             realloc(bufmgr_gem->exec_objects,
226                     sizeof(*bufmgr_gem->exec_objects) * new_size);
227         bufmgr_gem->exec_bos =
228             realloc(bufmgr_gem->exec_bos,
229                     sizeof(*bufmgr_gem->exec_bos) * new_size);
230         bufmgr_gem->exec_size = new_size;
231     }
232
233     index = bufmgr_gem->exec_count;
234     bo_gem->validate_index = index;
235     /* Fill in array entry */
236     bufmgr_gem->exec_objects[index].handle = bo_gem->gem_handle;
237     bufmgr_gem->exec_objects[index].relocation_count = bo_gem->reloc_count;
238     bufmgr_gem->exec_objects[index].relocs_ptr = (uintptr_t)bo_gem->relocs;
239     bufmgr_gem->exec_objects[index].alignment = 0;
240     bufmgr_gem->exec_objects[index].offset = 0;
241     bufmgr_gem->exec_bos[index] = bo;
242     dri_bo_reference(bo);
243     bufmgr_gem->exec_count++;
244 }
245
246
247 #define RELOC_BUF_SIZE(x) ((I915_RELOC_HEADER + x * I915_RELOC0_STRIDE) * \
248         sizeof(uint32_t))
249
250 static int
251 intel_setup_reloc_list(dri_bo *bo)
252 {
253     dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
254     dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
255
256     bo_gem->relocs = malloc(bufmgr_gem->max_relocs *
257                             sizeof(struct drm_i915_gem_relocation_entry));
258     bo_gem->reloc_target_bo = malloc(bufmgr_gem->max_relocs * sizeof(dri_bo *));
259
260     return 0;
261 }
262
263 static dri_bo *
264 dri_gem_bo_alloc(dri_bufmgr *bufmgr, const char *name,
265                  unsigned long size, unsigned int alignment)
266 {
267     dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bufmgr;
268     dri_bo_gem *bo_gem;
269     unsigned int page_size = getpagesize();
270     int ret;
271     struct dri_gem_bo_bucket *bucket;
272     int alloc_from_cache = 0;
273
274     bo_gem = calloc(1, sizeof(*bo_gem));
275     if (!bo_gem)
276         return NULL;
277
278     /* Round the allocated size up to a power of two number of pages. */
279     bo_gem->bo.size = 1 << logbase2(size);
280     if (bo_gem->bo.size < page_size)
281         bo_gem->bo.size = page_size;
282     bucket = dri_gem_bo_bucket_for_size(bufmgr_gem, bo_gem->bo.size);
283
284     /* If we don't have caching at this size, don't actually round the
285      * allocation up.
286      */
287     if (bucket == NULL || bucket->max_entries == 0) {
288         bo_gem->bo.size = size;
289         if (bo_gem->bo.size < page_size)
290             bo_gem->bo.size = page_size;
291     }
292
293     /* Get a buffer out of the cache if available */
294     if (bucket != NULL && bucket->num_entries > 0) {
295         struct dri_gem_bo_bucket_entry *entry = bucket->head;
296         struct drm_i915_gem_busy busy;
297         
298         busy.handle = entry->gem_handle;
299         ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
300         alloc_from_cache = (ret == 0 && busy.busy == 0);
301
302         if (alloc_from_cache) {
303             bucket->head = entry->next;
304             if (entry->next == NULL)
305                 bucket->tail = &bucket->head;
306             bucket->num_entries--;
307
308             bo_gem->gem_handle = entry->gem_handle;
309             bo_gem->bo.offset = entry->last_offset;
310             free(entry);
311         }
312     }
313
314     if (!alloc_from_cache) {
315         struct drm_gem_create create;
316
317         memset(&create, 0, sizeof(create));
318         create.size = bo_gem->bo.size;
319
320         ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_CREATE, &create);
321         bo_gem->gem_handle = create.handle;
322         if (ret != 0) {
323             free(bo_gem);
324             return NULL;
325         }
326     }
327
328     bo_gem->bo.virtual = NULL;
329     bo_gem->bo.bufmgr = bufmgr;
330     bo_gem->name = name;
331     bo_gem->refcount = 1;
332     bo_gem->validate_index = -1;
333
334     DBG("bo_create: buf %d (%s) %ldb\n",
335         bo_gem->gem_handle, bo_gem->name, size);
336
337     return &bo_gem->bo;
338 }
339
340 /**
341  * Returns a dri_bo wrapping the given buffer object handle.
342  *
343  * This can be used when one application needs to pass a buffer object
344  * to another.
345  */
346 dri_bo *
347 intel_bo_gem_create_from_name(dri_bufmgr *bufmgr, const char *name,
348                               unsigned int handle)
349 {
350     dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bufmgr;
351     dri_bo_gem *bo_gem;
352     int ret;
353     struct drm_gem_open open_arg;
354
355     bo_gem = calloc(1, sizeof(*bo_gem));
356     if (!bo_gem)
357         return NULL;
358
359     memset(&open_arg, 0, sizeof(open_arg));
360     open_arg.name = handle;
361     ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_OPEN, &open_arg);
362     if (ret != 0) {
363         fprintf(stderr, "Couldn't reference %s handle 0x%08x: %s\n",
364                name, handle, strerror(-ret));
365         free(bo_gem);
366         return NULL;
367     }
368     bo_gem->bo.size = open_arg.size;
369     bo_gem->bo.offset = 0;
370     bo_gem->bo.virtual = NULL;
371     bo_gem->bo.bufmgr = bufmgr;
372     bo_gem->name = name;
373     bo_gem->refcount = 1;
374     bo_gem->validate_index = -1;
375     bo_gem->gem_handle = open_arg.handle;
376
377     DBG("bo_create_from_handle: %d (%s)\n", handle, bo_gem->name);
378
379     return &bo_gem->bo;
380 }
381
382 static void
383 dri_gem_bo_reference(dri_bo *bo)
384 {
385     dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
386
387     bo_gem->refcount++;
388 }
389
390 static void
391 dri_gem_bo_unreference(dri_bo *bo)
392 {
393     dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
394     dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
395
396     if (!bo)
397         return;
398
399     if (--bo_gem->refcount == 0) {
400         struct dri_gem_bo_bucket *bucket;
401         int ret;
402
403         if (bo_gem->mapped)
404             munmap (bo_gem->virtual, bo->size);
405
406         if (bo_gem->relocs != NULL) {
407             int i;
408
409             /* Unreference all the target buffers */
410             for (i = 0; i < bo_gem->reloc_count; i++)
411                  dri_bo_unreference(bo_gem->reloc_target_bo[i]);
412             free(bo_gem->reloc_target_bo);
413             free(bo_gem->relocs);
414         }
415
416         bucket = dri_gem_bo_bucket_for_size(bufmgr_gem, bo->size);
417         /* Put the buffer into our internal cache for reuse if we can. */
418         if (bucket != NULL &&
419             (bucket->max_entries == -1 ||
420              (bucket->max_entries > 0 &&
421               bucket->num_entries < bucket->max_entries)))
422         {
423             struct dri_gem_bo_bucket_entry *entry;
424
425             entry = calloc(1, sizeof(*entry));
426             entry->gem_handle = bo_gem->gem_handle;
427             entry->last_offset = bo->offset;
428
429             entry->next = NULL;
430             *bucket->tail = entry;
431             bucket->tail = &entry->next;
432             bucket->num_entries++;
433         } else {
434             struct drm_gem_close close;
435
436             /* Close this object */
437             close.handle = bo_gem->gem_handle;
438             ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_CLOSE, &close);
439             if (ret != 0) {
440                fprintf(stderr,
441                        "DRM_IOCTL_GEM_CLOSE %d failed (%s): %s\n",
442                        bo_gem->gem_handle, bo_gem->name, strerror(-ret));
443             }
444         }
445
446         DBG("bo_unreference final: %d (%s)\n",
447             bo_gem->gem_handle, bo_gem->name);
448
449         free(bo);
450         return;
451     }
452 }
453
454 static int
455 dri_gem_bo_map(dri_bo *bo, int write_enable)
456 {
457     dri_bufmgr_gem *bufmgr_gem;
458     dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
459     struct drm_gem_set_domain set_domain;
460     int ret;
461
462     bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
463
464     /* Allow recursive mapping. Mesa may recursively map buffers with
465      * nested display loops.
466      */
467     if (!bo_gem->mapped) {
468     
469         assert(bo->virtual == NULL);
470     
471         DBG("bo_map: %d (%s)\n", bo_gem->gem_handle, bo_gem->name);
472     
473         if (bo_gem->virtual == NULL) {
474             struct drm_gem_mmap mmap_arg;
475     
476             memset(&mmap_arg, 0, sizeof(mmap_arg));
477             mmap_arg.handle = bo_gem->gem_handle;
478             mmap_arg.offset = 0;
479             mmap_arg.size = bo->size;
480             ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_MMAP, &mmap_arg);
481             if (ret != 0) {
482                 fprintf(stderr, "%s:%d: Error mapping buffer %d (%s): %s .\n",
483                         __FILE__, __LINE__,
484                         bo_gem->gem_handle, bo_gem->name, strerror(errno));
485             }
486             bo_gem->virtual = (void *)(uintptr_t)mmap_arg.addr_ptr;
487         }
488         bo->virtual = bo_gem->virtual;
489         bo_gem->mapped = 1;
490         DBG("bo_map: %d (%s) -> %p\n", bo_gem->gem_handle, bo_gem->name, bo_gem->virtual);
491     }
492
493     if (!bo_gem->cpu_domain_set) {
494         set_domain.handle = bo_gem->gem_handle;
495         set_domain.read_domains = DRM_GEM_DOMAIN_CPU;
496         set_domain.write_domain = write_enable ? DRM_GEM_DOMAIN_CPU : 0;
497         ret = ioctl (bufmgr_gem->fd, DRM_IOCTL_GEM_SET_DOMAIN, &set_domain);
498         if (ret != 0) {
499             fprintf (stderr, "%s:%d: Error setting memory domains %d (%08x %08x): %s .\n",
500                      __FILE__, __LINE__,
501                      bo_gem->gem_handle, set_domain.read_domains, set_domain.write_domain,
502                      strerror (errno));
503         }
504         bo_gem->cpu_domain_set = 1;
505     }
506
507     return 0;
508 }
509
510 static int
511 dri_gem_bo_unmap(dri_bo *bo)
512 {
513     dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
514
515     if (bo == NULL)
516         return 0;
517
518     assert(bo_gem->mapped);
519
520     return 0;
521 }
522
523 static int
524 dri_gem_bo_subdata (dri_bo *bo, unsigned long offset,
525                     unsigned long size, const void *data)
526 {
527     dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
528     dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
529     struct drm_gem_pwrite pwrite;
530     int ret;
531
532     memset (&pwrite, 0, sizeof (pwrite));
533     pwrite.handle = bo_gem->gem_handle;
534     pwrite.offset = offset;
535     pwrite.size = size;
536     pwrite.data_ptr = (uint64_t) (uintptr_t) data;
537     ret = ioctl (bufmgr_gem->fd, DRM_IOCTL_GEM_PWRITE, &pwrite);
538     if (ret != 0) {
539         fprintf (stderr, "%s:%d: Error writing data to buffer %d: (%d %d) %s .\n",
540                  __FILE__, __LINE__,
541                  bo_gem->gem_handle, (int) offset, (int) size,
542                  strerror (errno));
543     }
544     return 0;
545 }
546
547 static int
548 dri_gem_bo_get_subdata (dri_bo *bo, unsigned long offset,
549                         unsigned long size, void *data)
550 {
551     dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
552     dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
553     struct drm_gem_pread pread;
554     int ret;
555
556     memset (&pread, 0, sizeof (pread));
557     pread.handle = bo_gem->gem_handle;
558     pread.offset = offset;
559     pread.size = size;
560     pread.data_ptr = (uint64_t) (uintptr_t) data;
561     ret = ioctl (bufmgr_gem->fd, DRM_IOCTL_GEM_PREAD, &pread);
562     if (ret != 0) {
563         fprintf (stderr, "%s:%d: Error reading data from buffer %d: (%d %d) %s .\n",
564                  __FILE__, __LINE__,
565                  bo_gem->gem_handle, (int) offset, (int) size,
566                  strerror (errno));
567     }
568     return 0;
569 }
570
571 static void
572 dri_gem_bo_wait_rendering(dri_bo *bo)
573 {
574     dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
575     dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
576     struct drm_gem_set_domain set_domain;
577     int ret;
578
579     set_domain.handle = bo_gem->gem_handle;
580     set_domain.read_domains = DRM_GEM_DOMAIN_CPU;
581     set_domain.write_domain = 0;
582     ret = ioctl (bufmgr_gem->fd, DRM_IOCTL_GEM_SET_DOMAIN, &set_domain);
583     if (ret != 0) {
584         fprintf (stderr, "%s:%d: Error setting memory domains %d (%08x %08x): %s .\n",
585                  __FILE__, __LINE__,
586                  bo_gem->gem_handle, set_domain.read_domains, set_domain.write_domain,
587                  strerror (errno));
588     }
589 }
590
591 static void
592 dri_bufmgr_gem_destroy(dri_bufmgr *bufmgr)
593 {
594     dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bufmgr;
595     int i;
596
597     free(bufmgr_gem->exec_objects);
598     free(bufmgr_gem->exec_bos);
599
600     /* Free any cached buffer objects we were going to reuse */
601     for (i = 0; i < INTEL_GEM_BO_BUCKETS; i++) {
602         struct dri_gem_bo_bucket *bucket = &bufmgr_gem->cache_bucket[i];
603         struct dri_gem_bo_bucket_entry *entry;
604
605         while ((entry = bucket->head) != NULL) {
606             struct drm_gem_close close;
607             int ret;
608
609             bucket->head = entry->next;
610             if (entry->next == NULL)
611                 bucket->tail = &bucket->head;
612             bucket->num_entries--;
613
614             /* Close this object */
615             close.handle = entry->gem_handle;
616             ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_CLOSE, &close);
617             if (ret != 0) {
618                fprintf(stderr, "DRM_IOCTL_GEM_CLOSE failed: %s\n",
619                        strerror(-ret));
620             }
621
622             free(entry);
623         }
624     }
625
626     free(bufmgr);
627 }
628
629 /**
630  * Adds the target buffer to the validation list and adds the relocation
631  * to the reloc_buffer's relocation list.
632  *
633  * The relocation entry at the given offset must already contain the
634  * precomputed relocation value, because the kernel will optimize out
635  * the relocation entry write when the buffer hasn't moved from the
636  * last known offset in target_bo.
637  */
638 static int
639 dri_gem_emit_reloc(dri_bo *bo, uint32_t read_domains, uint32_t write_domain,
640                    uint32_t delta, uint32_t offset, dri_bo *target_bo)
641 {
642     dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr;
643     dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
644     dri_bo_gem *target_bo_gem = (dri_bo_gem *)target_bo;
645
646     /* Create a new relocation list if needed */
647     if (bo_gem->relocs == NULL)
648         intel_setup_reloc_list(bo);
649
650     /* Check overflow */
651     assert(bo_gem->reloc_count < bufmgr_gem->max_relocs);
652
653     /* Check args */
654     assert (offset <= bo->size - 4);
655     assert ((write_domain & (write_domain-1)) == 0);
656
657     bo_gem->relocs[bo_gem->reloc_count].offset = offset;
658     bo_gem->relocs[bo_gem->reloc_count].delta = delta;
659     bo_gem->relocs[bo_gem->reloc_count].target_handle =
660         target_bo_gem->gem_handle;
661     bo_gem->relocs[bo_gem->reloc_count].read_domains = read_domains;
662     bo_gem->relocs[bo_gem->reloc_count].write_domain = write_domain;
663     bo_gem->relocs[bo_gem->reloc_count].presumed_offset = target_bo->offset;
664
665     bo_gem->reloc_target_bo[bo_gem->reloc_count] = target_bo;
666     dri_bo_reference(target_bo);
667
668     bo_gem->reloc_count++;
669     return 0;
670 }
671
672 /**
673  * Walk the tree of relocations rooted at BO and accumulate the list of
674  * validations to be performed and update the relocation buffers with
675  * index values into the validation list.
676  */
677 static void
678 dri_gem_bo_process_reloc(dri_bo *bo)
679 {
680     dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
681     int i;
682
683     if (bo_gem->relocs == NULL)
684         return;
685
686     for (i = 0; i < bo_gem->reloc_count; i++) {
687         dri_bo *target_bo = bo_gem->reloc_target_bo[i];
688
689         /* Continue walking the tree depth-first. */
690         dri_gem_bo_process_reloc(target_bo);
691
692         /* Add the target to the validate list */
693         intel_add_validate_buffer(target_bo);
694     }
695 }
696
697 static void *
698 dri_gem_process_reloc(dri_bo *batch_buf)
699 {
700     dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *) batch_buf->bufmgr;
701
702     /* Update indices and set up the validate list. */
703     dri_gem_bo_process_reloc(batch_buf);
704
705     /* Add the batch buffer to the validation list.  There are no relocations
706      * pointing to it.
707      */
708     intel_add_validate_buffer(batch_buf);
709
710     bufmgr_gem->exec_arg.buffers_ptr = (uintptr_t)bufmgr_gem->exec_objects;
711     bufmgr_gem->exec_arg.buffer_count = bufmgr_gem->exec_count;
712     bufmgr_gem->exec_arg.batch_start_offset = 0;
713     bufmgr_gem->exec_arg.batch_len = 0; /* written in intel_exec_ioctl */
714
715     return &bufmgr_gem->exec_arg;
716 }
717
718 static void
719 intel_update_buffer_offsets (dri_bufmgr_gem *bufmgr_gem)
720 {
721     int i;
722
723     for (i = 0; i < bufmgr_gem->exec_count; i++) {
724         dri_bo *bo = bufmgr_gem->exec_bos[i];
725         dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
726
727         /* Update the buffer offset */
728         if (bufmgr_gem->exec_objects[i].offset != bo->offset) {
729             DBG("BO %d (%s) migrated: 0x%08lx -> 0x%08llx\n",
730                 bo_gem->gem_handle, bo_gem->name, bo->offset,
731                 bufmgr_gem->exec_objects[i].offset);
732             bo->offset = bufmgr_gem->exec_objects[i].offset;
733         }
734     }
735 }
736
737 static void
738 dri_gem_post_submit(dri_bo *batch_buf)
739 {
740     dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)batch_buf->bufmgr;
741     int i;
742
743     intel_update_buffer_offsets (bufmgr_gem);
744
745     if (bufmgr_gem->bufmgr.debug)
746         dri_gem_dump_validation_list(bufmgr_gem);
747
748     for (i = 0; i < bufmgr_gem->exec_count; i++) {
749         dri_bo *bo = bufmgr_gem->exec_bos[i];
750         dri_bo_gem *bo_gem = (dri_bo_gem *)bo;
751
752         /* Need to call set_domain on next bo_map */
753         bo_gem->cpu_domain_set = 0;
754
755         /* Disconnect the buffer from the validate list */
756         bo_gem->validate_index = -1;
757         dri_bo_unreference(bo);
758         bufmgr_gem->exec_bos[i] = NULL;
759     }
760     bufmgr_gem->exec_count = 0;
761 }
762
763 /**
764  * Enables unlimited caching of buffer objects for reuse.
765  *
766  * This is potentially very memory expensive, as the cache at each bucket
767  * size is only bounded by how many buffers of that size we've managed to have
768  * in flight at once.
769  */
770 void
771 intel_bufmgr_gem_enable_reuse(dri_bufmgr *bufmgr)
772 {
773     dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bufmgr;
774     int i;
775
776     for (i = 0; i < INTEL_GEM_BO_BUCKETS; i++) {
777         bufmgr_gem->cache_bucket[i].max_entries = -1;
778     }
779 }
780
781 /*
782  *
783  */
784 static int
785 dri_gem_check_aperture_space(dri_bo *bo)
786 {
787     return 0;
788 }
789
790 /**
791  * Initializes the GEM buffer manager, which uses the kernel to allocate, map,
792  * and manage map buffer objections.
793  *
794  * \param fd File descriptor of the opened DRM device.
795  */
796 dri_bufmgr *
797 intel_bufmgr_gem_init(int fd, int batch_size)
798 {
799     dri_bufmgr_gem *bufmgr_gem;
800     int i;
801
802     bufmgr_gem = calloc(1, sizeof(*bufmgr_gem));
803     bufmgr_gem->fd = fd;
804
805     /* Let's go with one relocation per every 2 dwords (but round down a bit
806      * since a power of two will mean an extra page allocation for the reloc
807      * buffer).
808      *
809      * Every 4 was too few for the blender benchmark.
810      */
811     bufmgr_gem->max_relocs = batch_size / sizeof(uint32_t) / 2 - 2;
812
813     bufmgr_gem->bufmgr.bo_alloc = dri_gem_bo_alloc;
814     bufmgr_gem->bufmgr.bo_reference = dri_gem_bo_reference;
815     bufmgr_gem->bufmgr.bo_unreference = dri_gem_bo_unreference;
816     bufmgr_gem->bufmgr.bo_map = dri_gem_bo_map;
817     bufmgr_gem->bufmgr.bo_unmap = dri_gem_bo_unmap;
818     bufmgr_gem->bufmgr.bo_subdata = dri_gem_bo_subdata;
819     bufmgr_gem->bufmgr.bo_get_subdata = dri_gem_bo_get_subdata;
820     bufmgr_gem->bufmgr.bo_wait_rendering = dri_gem_bo_wait_rendering;
821     bufmgr_gem->bufmgr.destroy = dri_bufmgr_gem_destroy;
822     bufmgr_gem->bufmgr.process_relocs = dri_gem_process_reloc;
823     bufmgr_gem->bufmgr.post_submit = dri_gem_post_submit;
824     bufmgr_gem->bufmgr.debug = 0;
825     bufmgr_gem->bufmgr.check_aperture_space = dri_gem_check_aperture_space;
826     bufmgr_gem->intel_bufmgr.emit_reloc = dri_gem_emit_reloc;
827     /* Initialize the linked lists for BO reuse cache. */
828     for (i = 0; i < INTEL_GEM_BO_BUCKETS; i++)
829         bufmgr_gem->cache_bucket[i].tail = &bufmgr_gem->cache_bucket[i].head;
830
831     return &bufmgr_gem->bufmgr;
832 }
833
834 int
835 intel_bo_emit_reloc(dri_bo *reloc_buf,
836                     uint32_t read_domains, uint32_t write_domain,
837                     uint32_t delta, uint32_t offset, dri_bo *target_buf)
838 {
839     struct intel_bufmgr *intel_bufmgr;
840
841     intel_bufmgr = (struct intel_bufmgr *)(reloc_buf->bufmgr + 1);
842
843     return intel_bufmgr->emit_reloc(reloc_buf, read_domains, write_domain,
844                                     delta, offset, target_buf);
845 }