@@ -781,62 +781,165 @@ drm_intel_gem_bo_alloc_create2(drm_intel_bufmgr *bufmgr,
{
drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr;
drm_intel_bo_gem *bo_gem;
- struct drm_i915_gem_create2 create;
- int ret;
-
- bo_gem = calloc(1, sizeof(*bo_gem));
- if (!bo_gem)
- return NULL;
-
- bo_gem->bo.size = size;
+ unsigned int page_size = getpagesize();
+ struct drm_intel_gem_bo_bucket *bucket;
+ bool alloc_from_cache;
+ unsigned long bo_size;
+ bool for_render = false;
+ int ret, stride;
- VG_CLEAR(create);
- create.size = size;
- if(params->offset & I915_CREATE_OFFSET_VALID) {
- create.offset = params->offset;
- create.context = params->context;
- }
+ if (params->flags & BO_ALLOC_FOR_RENDER)
+ for_render = true;
if (params->tiling_mode == I915_TILING_NONE)
- create.stride = 0;
+ stride = 0;
else
- create.stride = params->stride;
+ stride = params->stride;
- create.placement = params->placement;
- create.domain = params->cache_domain;
- create.caching = params->caching;
- create.tiling_mode = params->tiling_mode;
- create.madvise = params->madvise;
+ if (params->placement == I915_CREATE_PLACEMENT_STOLEN ||
+ params->offset & I915_CREATE_OFFSET_VALID ||
+ params->madvise == I915_MADV_DONTNEED) {
+ bucket = NULL;
+ bo_size = size;
+ } else {
+ /* Round the allocated size up to a power of two
+ * number of pages.
+ */
+ bucket = drm_intel_gem_bo_bucket_for_size(bufmgr_gem, size);
+ /* If we don't have caching at this size, don't actually
+ * round the allocation up.
+ */
+ if (bucket == NULL) {
+ bo_size = size;
+ if (bo_size < page_size)
+ bo_size = page_size;
+ } else {
+ bo_size = bucket->size;
+ }
+ }
+ pthread_mutex_lock(&bufmgr_gem->lock);
+ /* Get a buffer out of the cache if available */
+retry:
+ alloc_from_cache = false;
+ if (bucket != NULL && !DRMLISTEMPTY(&bucket->head)) {
+ if (for_render) {
+ /* Allocate new render-target BOs from the tail (MRU)
+ * of the list, as it will likely be hot in the GPU
+ * cache and in the aperture for us.
+ */
+ bo_gem = DRMLISTENTRY(drm_intel_bo_gem,
+ bucket->head.prev, head);
+ DRMLISTDEL(&bo_gem->head);
+ alloc_from_cache = true;
+ } 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);
+ if (!drm_intel_gem_bo_busy(&bo_gem->bo)) {
+ alloc_from_cache = true;
+ DRMLISTDEL(&bo_gem->head);
+ }
+ }
+ if (alloc_from_cache) {
+ struct drm_i915_gem_caching bo_cache;
+ struct drm_i915_gem_set_domain set_domain;
+ /* We need to call the functions for setcache, domain,
+ * tiling, madvise here, as these parameters may be
+ * different for the bo present in cache.
+ */
+ if (!drm_intel_gem_bo_madvise_internal
+ (bufmgr_gem, bo_gem,
+ I915_MADV_WILLNEED)) {
+ drm_intel_gem_bo_free(&bo_gem->bo);
+ drm_intel_gem_bo_cache_purge_bucket(bufmgr_gem,
+ bucket);
+ goto retry;
+ }
- ret = drmIoctl(bufmgr_gem->fd,
- DRM_IOCTL_I915_GEM_CREATE2,
- &create);
- bo_gem->gem_handle = create.handle;
- bo_gem->bo.handle = bo_gem->gem_handle;
- if (ret != 0) {
- free(bo_gem);
- return NULL;
+ if (drm_intel_gem_bo_set_tiling_internal(&bo_gem->bo,
+ params->tiling_mode,
+ stride)) {
+ drm_intel_gem_bo_free(&bo_gem->bo);
+ goto retry;
+ }
+ VG_CLEAR(bo_cache);
+ bo_cache.handle = bo_gem->gem_handle;
+ bo_cache.caching = params->caching;
+ if (drmIoctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_SET_CACHING,
+ &bo_cache)) {
+ drm_intel_gem_bo_free(&bo_gem->bo);
+ goto retry;
+ }
+ VG_CLEAR(set_domain);
+ set_domain.handle = bo_gem->gem_handle;
+ set_domain.read_domains = params->cache_domain;
+ set_domain.write_domain = params->cache_domain;
+ if (drmIoctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_SET_DOMAIN,
+ &set_domain)) {
+ drm_intel_gem_bo_free(&bo_gem->bo);
+ goto retry;
+ }
+ }
}
- bo_gem->bo.bufmgr = bufmgr;
+ pthread_mutex_unlock(&bufmgr_gem->lock);
- /* We have to call the set_tiling ioctl, as create2 ioctl
- * doesn't return the swizzle mode
- * TODO: Is this required? Can the functionality be put in
- * create2 ioctl?
- */
- bo_gem->tiling_mode = create.tiling_mode;
- bo_gem->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
- bo_gem->stride = create.stride;
+ if (!alloc_from_cache) {
+ struct drm_i915_gem_create2 create;
+ bo_gem = calloc(1, sizeof(*bo_gem));
+ if (!bo_gem)
+ return NULL;
+ bo_gem->bo.size = bo_size;
+ VG_CLEAR(create);
+ create.size = bo_size;
+ if(params->offset & I915_CREATE_OFFSET_VALID) {
+ create.offset = params->offset;
+ create.context = params->context;
+ }
- if (drm_intel_gem_bo_set_tiling_internal(&bo_gem->bo,
- create.tiling_mode,
- create.stride)) {
- drm_intel_gem_bo_free(&bo_gem->bo);
- return NULL;
- }
+ create.stride = stride;
+ create.placement = params->placement;
+ create.domain = params->cache_domain;
+ create.caching = params->caching;
+ create.tiling_mode = params->tiling_mode;
+ create.madvise = params->madvise;
- DRMINITLISTHEAD(&bo_gem->name_list);
- DRMINITLISTHEAD(&bo_gem->vma_list);
+ ret = drmIoctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_CREATE2,
+ &create);
+ bo_gem->gem_handle = create.handle;
+ bo_gem->bo.handle = bo_gem->gem_handle;
+ if (ret != 0) {
+ free(bo_gem);
+ return NULL;
+ }
+ bo_gem->bo.bufmgr = bufmgr;
+
+ /* We have to call the set_tiling ioctl, as create2 ioctl
+ * doesn't return the swizzle mode
+ * TODO: Can create2 achieve this functionality?
+ */
+ bo_gem->tiling_mode = create.tiling_mode;
+ bo_gem->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
+ bo_gem->stride = stride;
+
+ if (drm_intel_gem_bo_set_tiling_internal(&bo_gem->bo,
+ create.tiling_mode,
+ stride)) {
+ drm_intel_gem_bo_free(&bo_gem->bo);
+ return NULL;
+ }
+
+ DRMINITLISTHEAD(&bo_gem->name_list);
+ DRMINITLISTHEAD(&bo_gem->vma_list);
+ }
bo_gem->name = params->name;
atomic_set(&bo_gem->refcount, 1);
@@ -844,8 +947,10 @@ drm_intel_gem_bo_alloc_create2(drm_intel_bufmgr *bufmgr,
bo_gem->reloc_tree_fences = 0;
bo_gem->used_as_reloc_target = false;
bo_gem->has_error = false;
- /* set reusable to false, as caching is not employed currently*/
- bo_gem->reusable = false;
+ if (params->placement == I915_CREATE_PLACEMENT_STOLEN)
+ bo_gem->reusable = false;
+ else
+ bo_gem->reusable = true;
bo_gem->aub_annotations = NULL;
bo_gem->aub_annotation_count = 0;