OSDN Git Service

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