OSDN Git Service

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