intel: Add a new bufmgr alloc function to get BOs ready for rendering to.

This avoids using the oldest BO in the BO cache and waiting for it to be
idle before we turn around and render to it with the GPU.  Thanks to
Chris Wilson for pointing out how silly we were being.
main
Eric Anholt 2009-02-18 13:06:35 -08:00
parent a1345338fe
commit 72abe983ad
6 changed files with 79 additions and 24 deletions

View File

@ -51,6 +51,13 @@ drm_intel_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name,
return bufmgr->bo_alloc(bufmgr, name, size, alignment); return bufmgr->bo_alloc(bufmgr, name, size, alignment);
} }
drm_intel_bo *
drm_intel_bo_alloc_for_render(drm_intel_bufmgr *bufmgr, const char *name,
unsigned long size, unsigned int alignment)
{
return bufmgr->bo_alloc_for_render(bufmgr, name, size, alignment);
}
void void
drm_intel_bo_reference(drm_intel_bo *bo) drm_intel_bo_reference(drm_intel_bo *bo)
{ {

View File

@ -75,6 +75,10 @@ struct _drm_intel_bo {
drm_intel_bo *drm_intel_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name, drm_intel_bo *drm_intel_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name,
unsigned long size, unsigned int alignment); unsigned long size, unsigned int alignment);
drm_intel_bo *drm_intel_bo_alloc_for_render(drm_intel_bufmgr *bufmgr,
const char *name,
unsigned long size,
unsigned int alignment);
void drm_intel_bo_reference(drm_intel_bo *bo); void drm_intel_bo_reference(drm_intel_bo *bo);
void drm_intel_bo_unreference(drm_intel_bo *bo); void drm_intel_bo_unreference(drm_intel_bo *bo);
int drm_intel_bo_map(drm_intel_bo *bo, int write_enable); int drm_intel_bo_map(drm_intel_bo *bo, int write_enable);

View File

@ -1503,6 +1503,7 @@ drm_intel_bufmgr_fake_init(int fd,
/* Hook in methods */ /* Hook in methods */
bufmgr_fake->bufmgr.bo_alloc = drm_intel_fake_bo_alloc; bufmgr_fake->bufmgr.bo_alloc = drm_intel_fake_bo_alloc;
bufmgr_fake->bufmgr.bo_alloc_for_render = drm_intel_fake_bo_alloc;
bufmgr_fake->bufmgr.bo_reference = drm_intel_fake_bo_reference; bufmgr_fake->bufmgr.bo_reference = drm_intel_fake_bo_reference;
bufmgr_fake->bufmgr.bo_unreference = drm_intel_fake_bo_unreference; bufmgr_fake->bufmgr.bo_unreference = drm_intel_fake_bo_unreference;
bufmgr_fake->bufmgr.bo_map = drm_intel_fake_bo_map; bufmgr_fake->bufmgr.bo_map = drm_intel_fake_bo_map;

View File

@ -52,6 +52,7 @@
#include <sys/types.h> #include <sys/types.h>
#include "errno.h" #include "errno.h"
#include "libdrm_lists.h"
#include "intel_bufmgr.h" #include "intel_bufmgr.h"
#include "intel_bufmgr_priv.h" #include "intel_bufmgr_priv.h"
#include "intel_chipset.h" #include "intel_chipset.h"
@ -67,7 +68,8 @@
typedef struct _drm_intel_bo_gem drm_intel_bo_gem; typedef struct _drm_intel_bo_gem drm_intel_bo_gem;
struct drm_intel_gem_bo_bucket { struct drm_intel_gem_bo_bucket {
drm_intel_bo_gem *head, **tail; drmMMListHead head;
/** /**
* Limit on the number of entries in this bucket. * Limit on the number of entries in this bucket.
* *
@ -145,8 +147,8 @@ struct _drm_intel_bo_gem {
/** Mapped address for the buffer, saved across map/unmap cycles */ /** Mapped address for the buffer, saved across map/unmap cycles */
void *virtual; void *virtual;
/** free list */ /** BO cache list */
drm_intel_bo_gem *next; drmMMListHead head;
/** /**
* Boolean of whether this BO and its children have been included in * Boolean of whether this BO and its children have been included in
@ -323,8 +325,9 @@ drm_intel_setup_reloc_list(drm_intel_bo *bo)
} }
static drm_intel_bo * static drm_intel_bo *
drm_intel_gem_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name, drm_intel_gem_bo_alloc_internal(drm_intel_bufmgr *bufmgr, const char *name,
unsigned long size, unsigned int alignment) unsigned long size, unsigned int alignment,
int for_render)
{ {
drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr; drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr;
drm_intel_bo_gem *bo_gem; drm_intel_bo_gem *bo_gem;
@ -353,19 +356,35 @@ drm_intel_gem_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name,
/* Get a buffer out of the cache if available */ /* Get a buffer out of the cache if available */
if (bucket != NULL && bucket->num_entries > 0) { if (bucket != NULL && bucket->num_entries > 0) {
struct drm_i915_gem_busy busy; struct drm_i915_gem_busy busy;
bo_gem = bucket->head;
memset(&busy, 0, sizeof(busy));
busy.handle = bo_gem->gem_handle;
ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy); if (for_render) {
alloc_from_cache = (ret == 0 && busy.busy == 0); /* Allocate new render-target BOs from the tail (MRU)
* of the list, as it will likely be hot in the GPU cache
if (alloc_from_cache) { * and in the aperture for us.
bucket->head = bo_gem->next; */
if (bo_gem->next == NULL) bo_gem = DRMLISTENTRY(drm_intel_bo_gem, bucket->head.prev, head);
bucket->tail = &bucket->head; DRMLISTDEL(&bo_gem->head);
bucket->num_entries--; bucket->num_entries--;
alloc_from_cache = 1;
} else {
/* For non-render-target BOs (where we're probably going to map it
* first thing in order to fill it with data), check if the
* last BO in the cache is unbusy, and only reuse in that case.
* Otherwise, allocating a new buffer is probably faster than
* waiting for the GPU to finish.
*/
bo_gem = DRMLISTENTRY(drm_intel_bo_gem, bucket->head.next, head);
memset(&busy, 0, sizeof(busy));
busy.handle = bo_gem->gem_handle;
ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
alloc_from_cache = (ret == 0 && busy.busy == 0);
if (alloc_from_cache) {
DRMLISTDEL(&bo_gem->head);
bucket->num_entries--;
}
} }
} }
pthread_mutex_unlock(&bufmgr_gem->lock); pthread_mutex_unlock(&bufmgr_gem->lock);
@ -406,6 +425,20 @@ drm_intel_gem_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name,
return &bo_gem->bo; return &bo_gem->bo;
} }
static drm_intel_bo *
drm_intel_gem_bo_alloc_for_render(drm_intel_bufmgr *bufmgr, const char *name,
unsigned long size, unsigned int alignment)
{
return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, alignment, 1);
}
static drm_intel_bo *
drm_intel_gem_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name,
unsigned long size, unsigned int alignment)
{
return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, alignment, 0);
}
/** /**
* Returns a drm_intel_bo wrapping the given buffer object handle. * Returns a drm_intel_bo wrapping the given buffer object handle.
* *
@ -545,9 +578,7 @@ drm_intel_gem_bo_unreference_locked(drm_intel_bo *bo)
bo_gem->reloc_target_bo = NULL; bo_gem->reloc_target_bo = NULL;
bo_gem->reloc_count = 0; bo_gem->reloc_count = 0;
bo_gem->next = NULL; DRMLISTADDTAIL(&bo_gem->head, &bucket->head);
*bucket->tail = bo_gem;
bucket->tail = &bo_gem->next;
bucket->num_entries++; bucket->num_entries++;
} else { } else {
drm_intel_gem_bo_free(bo); drm_intel_gem_bo_free(bo);
@ -827,10 +858,9 @@ drm_intel_bufmgr_gem_destroy(drm_intel_bufmgr *bufmgr)
struct drm_intel_gem_bo_bucket *bucket = &bufmgr_gem->cache_bucket[i]; struct drm_intel_gem_bo_bucket *bucket = &bufmgr_gem->cache_bucket[i];
drm_intel_bo_gem *bo_gem; drm_intel_bo_gem *bo_gem;
while ((bo_gem = bucket->head) != NULL) { while (!DRMLISTEMPTY(&bucket->head)) {
bucket->head = bo_gem->next; bo_gem = DRMLISTENTRY(drm_intel_bo_gem, bucket->head.next, head);
if (bo_gem->next == NULL) DRMLISTDEL(&bo_gem->head);
bucket->tail = &bucket->head;
bucket->num_entries--; bucket->num_entries--;
drm_intel_gem_bo_free(&bo_gem->bo); drm_intel_gem_bo_free(&bo_gem->bo);
@ -1348,6 +1378,7 @@ drm_intel_bufmgr_gem_init(int fd, int batch_size)
bufmgr_gem->max_relocs = batch_size / sizeof(uint32_t) / 2 - 2; bufmgr_gem->max_relocs = batch_size / sizeof(uint32_t) / 2 - 2;
bufmgr_gem->bufmgr.bo_alloc = drm_intel_gem_bo_alloc; bufmgr_gem->bufmgr.bo_alloc = drm_intel_gem_bo_alloc;
bufmgr_gem->bufmgr.bo_alloc_for_render = drm_intel_gem_bo_alloc_for_render;
bufmgr_gem->bufmgr.bo_reference = drm_intel_gem_bo_reference; bufmgr_gem->bufmgr.bo_reference = drm_intel_gem_bo_reference;
bufmgr_gem->bufmgr.bo_unreference = drm_intel_gem_bo_unreference; bufmgr_gem->bufmgr.bo_unreference = drm_intel_gem_bo_unreference;
bufmgr_gem->bufmgr.bo_map = drm_intel_gem_bo_map; bufmgr_gem->bufmgr.bo_map = drm_intel_gem_bo_map;
@ -1367,7 +1398,7 @@ drm_intel_bufmgr_gem_init(int fd, int batch_size)
bufmgr_gem->bufmgr.check_aperture_space = drm_intel_gem_check_aperture_space; bufmgr_gem->bufmgr.check_aperture_space = drm_intel_gem_check_aperture_space;
/* Initialize the linked lists for BO reuse cache. */ /* Initialize the linked lists for BO reuse cache. */
for (i = 0; i < DRM_INTEL_GEM_BO_BUCKETS; i++) for (i = 0; i < DRM_INTEL_GEM_BO_BUCKETS; i++)
bufmgr_gem->cache_bucket[i].tail = &bufmgr_gem->cache_bucket[i].head; DRMINITLISTHEAD(&bufmgr_gem->cache_bucket[i].head);
return &bufmgr_gem->bufmgr; return &bufmgr_gem->bufmgr;
} }

View File

@ -51,6 +51,16 @@ struct _drm_intel_bufmgr {
drm_intel_bo *(*bo_alloc)(drm_intel_bufmgr *bufmgr, const char *name, drm_intel_bo *(*bo_alloc)(drm_intel_bufmgr *bufmgr, const char *name,
unsigned long size, unsigned int alignment); unsigned long size, unsigned int alignment);
/**
* Allocate a buffer object, hinting that it will be used as a render target.
*
* This is otherwise the same as bo_alloc.
*/
drm_intel_bo *(*bo_alloc_for_render)(drm_intel_bufmgr *bufmgr,
const char *name,
unsigned long size,
unsigned int alignment);
/** Takes a reference on a buffer object */ /** Takes a reference on a buffer object */
void (*bo_reference)(drm_intel_bo *bo); void (*bo_reference)(drm_intel_bo *bo);

View File

@ -29,6 +29,8 @@
* list handling. No list looping yet. * list handling. No list looping yet.
*/ */
#include <stddef.h>
typedef struct _drmMMListHead typedef struct _drmMMListHead
{ {
struct _drmMMListHead *prev; struct _drmMMListHead *prev;