Merge branch 'mesa_7_5_branch' into mesa_7_6_branch
[mesa.git] / src / mesa / drivers / dri / radeon / radeon_bo_legacy.c
index e378b118e0e85ad88c2a45469126a9b2e8fbf333..3e7547d2f9d26e46b660aabe5cd00197719935b1 100644 (file)
@@ -32,6 +32,7 @@
  *      Jérôme Glisse <glisse@freedesktop.org>
  */
 #include <stdio.h>
+#include <stddef.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "drm.h"
 #include "radeon_drm.h"
-#include "radeon_bo.h"
-#include "radeon_bo_legacy.h"
-#include "common_context.h"
+#include "radeon_common.h"
+#include "radeon_bocs_wrapper.h"
+#include "radeon_macros.h"
+
+/* no seriously texmem.c is this screwed up */
+struct bo_legacy_texture_object {
+    driTextureObject    base;
+    struct bo_legacy *parent;
+};
 
 struct bo_legacy {
     struct radeon_bo    base;
-    driTextureObject    tobj_base;
     int                 map_count;
     uint32_t            pending;
     int                 is_pending;
-    int                 validated;
     int                 static_bo;
-    int                 got_dri_texture_obj;
-    int                 dirty;
     uint32_t            offset;
-    driTextureObject    dri_texture_obj;
+    struct bo_legacy_texture_object *tobj;
+    int                 validated;
+    int                 dirty;
     void                *ptr;
     struct bo_legacy    *next, *prev;
     struct bo_legacy    *pnext, *pprev;
@@ -77,6 +82,7 @@ struct bo_manager_legacy {
     uint32_t                    fb_location;
     uint32_t                    texture_offset;
     unsigned                    dma_alloc_size;
+    uint32_t                    dma_buf_count;
     unsigned                    cpendings;
     driTextureObject            texture_swapped;
     driTexHeap                  *texture_heap;
@@ -86,13 +92,21 @@ struct bo_manager_legacy {
 
 static void bo_legacy_tobj_destroy(void *data, driTextureObject *t)
 {
-    struct bo_legacy *bo_legacy;
-
-    bo_legacy = (struct bo_legacy*)((char*)t)-sizeof(struct radeon_bo);
-    bo_legacy->got_dri_texture_obj = 0;
-    bo_legacy->validated = 0;
+    struct bo_legacy_texture_object *tobj = (struct bo_legacy_texture_object *)t;
+    
+    if (tobj->parent) {
+        tobj->parent->tobj = NULL;
+        tobj->parent->validated = 0;
+    }
 }
 
+static void inline clean_handles(struct bo_manager_legacy *bom)
+{
+  while (bom->cfree_handles > 0 &&
+        !bom->free_handles[bom->cfree_handles - 1])
+    bom->cfree_handles--;
+
+}
 static int legacy_new_handle(struct bo_manager_legacy *bom, uint32_t *handle)
 {
     uint32_t tmp;
@@ -103,12 +117,7 @@ static int legacy_new_handle(struct bo_manager_legacy *bom, uint32_t *handle)
     }
     if (bom->cfree_handles > 0) {
         tmp = bom->free_handles[--bom->cfree_handles];
-        while (!bom->free_handles[bom->cfree_handles - 1]) {
-            bom->cfree_handles--;
-            if (bom->cfree_handles <= 0) {
-                bom->cfree_handles = 0;
-            }
-        }
+       clean_handles(bom);
     } else {
         bom->cfree_handles = 0;
         tmp = bom->nhandle++;
@@ -135,12 +144,7 @@ static int legacy_free_handle(struct bo_manager_legacy *bom, uint32_t handle)
                 bom->free_handles[i] = 0;
             }
         }
-        while (!bom->free_handles[bom->cfree_handles - 1]) {
-            bom->cfree_handles--;
-            if (bom->cfree_handles <= 0) {
-                bom->cfree_handles = 0;
-            }
-        }
+        clean_handles(bom);
         return 0;
     }
     if (bom->cfree_handles < bom->nfree_handles) {
@@ -161,15 +165,25 @@ static int legacy_free_handle(struct bo_manager_legacy *bom, uint32_t handle)
 static void legacy_get_current_age(struct bo_manager_legacy *boml)
 {
     drm_radeon_getparam_t gp;
+    unsigned char *RADEONMMIO = NULL;
     int r;
 
-    gp.param = RADEON_PARAM_LAST_CLEAR;
-    gp.value = (int *)&boml->current_age;
-    r = drmCommandWriteRead(boml->base.fd, DRM_RADEON_GETPARAM,
-                            &gp, sizeof(gp));
-    if (r) {
-        fprintf(stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__, r);
-        exit(1);
+    if (   IS_R300_CLASS(boml->screen) 
+        || IS_R600_CLASS(boml->screen) ) 
+    {
+       gp.param = RADEON_PARAM_LAST_CLEAR;
+       gp.value = (int *)&boml->current_age;
+       r = drmCommandWriteRead(boml->base.fd, DRM_RADEON_GETPARAM,
+                                    &gp, sizeof(gp));
+       if (r) {
+                fprintf(stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__, r);
+         exit(1);
+       }
+    } 
+    else {
+        RADEONMMIO = boml->screen->mmio.map;
+        boml->current_age = boml->screen->scratch[3];
+        boml->current_age = INREG(RADEON_GUI_SCRATCH_REG3);
     }
 }
 
@@ -190,10 +204,14 @@ static int legacy_is_pending(struct radeon_bo *bo)
         if (bo_legacy->pnext) {
             bo_legacy->pnext->pprev = bo_legacy->pprev;
         }
+       assert(bo_legacy->is_pending <= bo->cref);
         while (bo_legacy->is_pending--) {
-            radeon_bo_unref(bo);
+           bo = radeon_bo_unref(bo);
+           if (!bo)
+             break;
         }
-        bo_legacy->is_pending = 0;
+       if (bo)
+         bo_legacy->is_pending = 0;
         boml->cpendings--;
         return 0;
     }
@@ -217,14 +235,18 @@ static int legacy_wait_pending(struct radeon_bo *bo)
     return 0;
 }
 
-static void legacy_track_pending(struct bo_manager_legacy *boml)
+void legacy_track_pending(struct radeon_bo_manager *bom, int debug)
 {
+    struct bo_manager_legacy *boml = (struct bo_manager_legacy*) bom;
     struct bo_legacy *bo_legacy;
     struct bo_legacy *next;
 
     legacy_get_current_age(boml);
     bo_legacy = boml->pending_bos.pnext;
     while (bo_legacy) {
+        if (debug)
+            fprintf(stderr,"pending %p %d %d %d\n", bo_legacy, bo_legacy->base.size,
+                    boml->current_age, bo_legacy->pending);
         next = bo_legacy->pnext;
         if (legacy_is_pending(&(bo_legacy->base))) {
         }
@@ -232,6 +254,35 @@ static void legacy_track_pending(struct bo_manager_legacy *boml)
     } 
 }
 
+static int legacy_wait_any_pending(struct bo_manager_legacy *boml)
+{
+    struct bo_legacy *bo_legacy;
+
+    legacy_get_current_age(boml);
+    bo_legacy = boml->pending_bos.pnext;
+    if (!bo_legacy)
+      return -1;
+    legacy_wait_pending(&bo_legacy->base);
+    return 0;
+}
+
+static void legacy_kick_all_buffers(struct bo_manager_legacy *boml)
+{
+    struct bo_legacy *legacy;
+
+    legacy = boml->bos.next;
+    while (legacy != &boml->bos) {
+       if (legacy->tobj) {
+           if (legacy->validated) {
+               driDestroyTextureObject(&legacy->tobj->base);
+               legacy->tobj = 0;
+               legacy->validated = 0;
+           }
+       }
+       legacy = legacy->next;
+    }
+}
+
 static struct bo_legacy *bo_allocate(struct bo_manager_legacy *boml,
                                      uint32_t size,
                                      uint32_t alignment,
@@ -239,6 +290,12 @@ static struct bo_legacy *bo_allocate(struct bo_manager_legacy *boml,
                                      uint32_t flags)
 {
     struct bo_legacy *bo_legacy;
+    static int pgsize;
+
+    if (pgsize == 0)
+        pgsize = getpagesize() - 1;
+
+    size = (size + pgsize) & ~pgsize;
 
     bo_legacy = (struct bo_legacy*)calloc(1, sizeof(struct bo_legacy));
     if (bo_legacy == NULL) {
@@ -254,7 +311,6 @@ static struct bo_legacy *bo_allocate(struct bo_manager_legacy *boml,
     bo_legacy->map_count = 0;
     bo_legacy->next = NULL;
     bo_legacy->prev = NULL;
-    bo_legacy->got_dri_texture_obj = 0;
     bo_legacy->pnext = NULL;
     bo_legacy->pprev = NULL;
     bo_legacy->next = boml->bos.next;
@@ -263,6 +319,7 @@ static struct bo_legacy *bo_allocate(struct bo_manager_legacy *boml,
     if (bo_legacy->next) {
         bo_legacy->next->prev = bo_legacy;
     }
+
     return bo_legacy;
 }
 
@@ -288,13 +345,13 @@ static int bo_dma_alloc(struct radeon_bo *bo)
     if (r) {
         /* ptr is set to NULL if dma allocation failed */
         bo_legacy->ptr = NULL;
-        exit(0);
         return r;
     }
     bo_legacy->ptr = boml->screen->gartTextures.map + base_offset;
     bo_legacy->offset = boml->screen->gart_texture_offset + base_offset;
     bo->size = size;
     boml->dma_alloc_size += size;
+    boml->dma_buf_count++;
     return 0;
 }
 
@@ -324,6 +381,7 @@ static int bo_dma_free(struct radeon_bo *bo)
         return r;
     }
     boml->dma_alloc_size -= bo_legacy->base.size;
+    boml->dma_buf_count--;
     return 0;
 }
 
@@ -345,6 +403,8 @@ static void bo_free(struct bo_legacy *bo_legacy)
             /* dma buffers */
             bo_dma_free(&bo_legacy->base);
         } else {
+           driDestroyTextureObject(&bo_legacy->tobj->base);
+           bo_legacy->tobj = NULL;
             /* free backing store */
             free(bo_legacy->ptr);
         }
@@ -375,7 +435,6 @@ static struct radeon_bo *bo_open(struct radeon_bo_manager *bom,
         }
         return NULL;
     }
-
     bo_legacy = bo_allocate(boml, size, alignment, domains, flags);
     bo_legacy->static_bo = 0;
     r = legacy_new_handle(boml, &bo_legacy->base.handle);
@@ -383,18 +442,26 @@ static struct radeon_bo *bo_open(struct radeon_bo_manager *bom,
         bo_free(bo_legacy);
         return NULL;
     }
-    if (bo_legacy->base.domains & RADEON_GEM_DOMAIN_GTT) {
-        legacy_track_pending(boml);
+    if (bo_legacy->base.domains & RADEON_GEM_DOMAIN_GTT) 
+    {
+retry:
+        legacy_track_pending(&boml->base, 0);
         /* dma buffers */
+
         r = bo_dma_alloc(&(bo_legacy->base));
-        if (r) {
-            fprintf(stderr, "Ran out of GART memory (for %d)!\n", size);
-            fprintf(stderr, "Please consider adjusting GARTSize option.\n");
-            bo_free(bo_legacy);
-            exit(-1);
-            return NULL;
+        if (r) 
+        {
+                if (legacy_wait_any_pending(boml) == -1) 
+             {
+                  bo_free(bo_legacy);
+                     return NULL;
+             }
+                goto retry;
+                return NULL;
         }
-    } else {
+    } 
+    else 
+    {
         bo_legacy->ptr = malloc(bo_legacy->base.size);
         if (bo_legacy->ptr == NULL) {
             bo_free(bo_legacy);
@@ -402,6 +469,7 @@ static struct radeon_bo *bo_open(struct radeon_bo_manager *bom,
         }
     }
     radeon_bo_ref(&(bo_legacy->base));
+
     return (struct radeon_bo*)bo_legacy;
 }
 
@@ -430,7 +498,7 @@ static int bo_map(struct radeon_bo *bo, int write)
 {
     struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
     struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
-    
+
     legacy_wait_pending(bo);
     bo_legacy->validated = 0;
     bo_legacy->dirty = 1;
@@ -451,7 +519,7 @@ static int bo_map(struct radeon_bo *bo, int write)
      * framebuffer, but I've found this to be unnecessary.
      *  -- Nicolai Hähnle, June 2008
      */
-    {
+    if (!(bo->domains & RADEON_GEM_DOMAIN_GTT)) {
         int p;
         volatile int *buf = (int*)boml->screen->driScreen->pFB;
         p = *buf;
@@ -464,19 +532,46 @@ static int bo_unmap(struct radeon_bo *bo)
 {
     struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
 
-    if (--bo_legacy->map_count > 0) {
+    if (--bo_legacy->map_count > 0) 
+    {
         return 0;
     }
+    
     bo->ptr = NULL;
+
     return 0;
 }
 
+static int bo_is_busy(struct radeon_bo *bo, uint32_t *domain)
+{
+    *domain = 0;
+    if (bo->domains & RADEON_GEM_DOMAIN_GTT)
+        *domain = RADEON_GEM_DOMAIN_GTT;
+    else
+        *domain = RADEON_GEM_DOMAIN_CPU;
+    if (legacy_is_pending(bo))
+        return -EBUSY;
+    else
+        return 0;
+}
+
+static int bo_is_static(struct radeon_bo *bo)
+{
+    struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
+    return bo_legacy->static_bo;
+}
+
 static struct radeon_bo_funcs bo_legacy_funcs = {
     bo_open,
     bo_ref,
     bo_unref,
     bo_map,
-    bo_unmap
+    bo_unmap,
+    NULL,
+    bo_is_static,
+    NULL,
+    NULL,
+    bo_is_busy
 };
 
 static int bo_vram_validate(struct radeon_bo *bo,
@@ -486,71 +581,129 @@ static int bo_vram_validate(struct radeon_bo *bo,
     struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
     struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
     int r;
+    int retry_count = 0, pending_retry = 0;
     
-    if (!bo_legacy->got_dri_texture_obj) {
-        make_empty_list(&bo_legacy->dri_texture_obj);
-        bo_legacy->dri_texture_obj.totalSize = bo->size;
+    if (!bo_legacy->tobj) {
+       bo_legacy->tobj = CALLOC(sizeof(struct bo_legacy_texture_object));
+       bo_legacy->tobj->parent = bo_legacy;
+       make_empty_list(&bo_legacy->tobj->base);
+       bo_legacy->tobj->base.totalSize = bo->size;
+    retry:
         r = driAllocateTexture(&boml->texture_heap, 1,
-                               &bo_legacy->dri_texture_obj);
+                               &bo_legacy->tobj->base);
         if (r) {
-            uint8_t *segfault=NULL;
-            fprintf(stderr, "Ouch! vram_validate failed %d\n", r);
-            *segfault=1;
-            return -1;
-        }
+               pending_retry = 0;
+               while(boml->cpendings && pending_retry++ < 10000) {
+                       legacy_track_pending(&boml->base, 0);
+                       retry_count++;
+                       if (retry_count > 2) {
+                               free(bo_legacy->tobj);
+                               bo_legacy->tobj = NULL;
+                               fprintf(stderr, "Ouch! vram_validate failed %d\n", r);
+                               return -1;
+                       }
+                       goto retry;
+               }
+       }
         bo_legacy->offset = boml->texture_offset +
-                            bo_legacy->dri_texture_obj.memBlock->ofs;
-        bo_legacy->got_dri_texture_obj = 1;
+                            bo_legacy->tobj->base.memBlock->ofs;
         bo_legacy->dirty = 1;
     }
-    if (bo_legacy->dirty) {
-        /* Copy to VRAM using a blit.
-         * All memory is 4K aligned. We're using 1024 pixels wide blits.
-         */
-        drm_radeon_texture_t tex;
-        drm_radeon_tex_image_t tmp;
-        int ret;
-
-        tex.offset = bo_legacy->offset;
-        tex.image = &tmp;
-        assert(!(tex.offset & 1023));
-
-        tmp.x = 0;
-        tmp.y = 0;
-        if (bo->size < 4096) {
-            tmp.width = (bo->size + 3) / 4;
-            tmp.height = 1;
-        } else {
-            tmp.width = 1024;
-            tmp.height = (bo->size + 4095) / 4096;
-        }
-        tmp.data = bo_legacy->ptr;
-        tex.format = RADEON_TXFORMAT_ARGB8888;
-        tex.width = tmp.width;
-        tex.height = tmp.height;
-        tex.pitch = MAX2(tmp.width / 16, 1);
-        do {
-            ret = drmCommandWriteRead(bo->bom->fd,
-                                      DRM_RADEON_TEXTURE,
-                                      &tex,
-                                      sizeof(drm_radeon_texture_t));
-            if (ret) {
-                if (RADEON_DEBUG & DEBUG_IOCTL)
-                    fprintf(stderr, "DRM_RADEON_TEXTURE:  again!\n");
-                usleep(1);
-            }
-        } while (ret == -EAGAIN);
-        bo_legacy->dirty = 0;
+
+    assert(bo_legacy->tobj->base.memBlock);
+
+    if (bo_legacy->tobj)
+       driUpdateTextureLRU(&bo_legacy->tobj->base);
+
+    if (bo_legacy->dirty || bo_legacy->tobj->base.dirty_images[0]) {
+           if (IS_R600_CLASS(boml->screen)) {
+                   drm_radeon_texture_t tex;
+                   drm_radeon_tex_image_t tmp;
+                   int ret;
+
+                   tex.offset = bo_legacy->offset;
+                   tex.image = &tmp;
+                   assert(!(tex.offset & 1023));
+
+                   tmp.x = 0;
+                   tmp.y = 0;
+                   tmp.width = bo->size;
+                   tmp.height = 1;
+                   tmp.data = bo_legacy->ptr;
+                   tex.format = RADEON_TXFORMAT_ARGB8888;
+                   tex.width = tmp.width;
+                   tex.height = tmp.height;
+                   tex.pitch = bo->size;
+                   do {
+                           ret = drmCommandWriteRead(bo->bom->fd,
+                                                     DRM_RADEON_TEXTURE,
+                                                     &tex,
+                                                     sizeof(drm_radeon_texture_t));
+                           if (ret) {
+                                   if (RADEON_DEBUG & RADEON_IOCTL)
+                                           fprintf(stderr, "DRM_RADEON_TEXTURE:  again!\n");
+                                   usleep(1);
+                           }
+                   } while (ret == -EAGAIN);
+           } else {
+                   /* Copy to VRAM using a blit.
+                    * All memory is 4K aligned. We're using 1024 pixels wide blits.
+                    */
+                   drm_radeon_texture_t tex;
+                   drm_radeon_tex_image_t tmp;
+                   int ret;
+
+                   tex.offset = bo_legacy->offset;
+                   tex.image = &tmp;
+                   assert(!(tex.offset & 1023));
+
+                   tmp.x = 0;
+                   tmp.y = 0;
+                   if (bo->size < 4096) {
+                           tmp.width = (bo->size + 3) / 4;
+                           tmp.height = 1;
+                   } else {
+                           tmp.width = 1024;
+                           tmp.height = (bo->size + 4095) / 4096;
+                   }
+                   tmp.data = bo_legacy->ptr;
+                   tex.format = RADEON_TXFORMAT_ARGB8888;
+                   tex.width = tmp.width;
+                   tex.height = tmp.height;
+                   tex.pitch = MAX2(tmp.width / 16, 1);
+                   do {
+                           ret = drmCommandWriteRead(bo->bom->fd,
+                                                     DRM_RADEON_TEXTURE,
+                                                     &tex,
+                                                     sizeof(drm_radeon_texture_t));
+                           if (ret) {
+                                   if (RADEON_DEBUG & RADEON_IOCTL)
+                                           fprintf(stderr, "DRM_RADEON_TEXTURE:  again!\n");
+                                   usleep(1);
+                           }
+                   } while (ret == -EAGAIN);
+           }
+           bo_legacy->dirty = 0;
+           bo_legacy->tobj->base.dirty_images[0] = 0;
     }
     return 0;
 }
 
+/* 
+ *  radeon_bo_legacy_validate -
+ *  returns:
+ *  0 - all good
+ *  -EINVAL - mapped buffer can't be validated
+ *  -EAGAIN - restart validation we've kicked all the buffers out
+ */
 int radeon_bo_legacy_validate(struct radeon_bo *bo,
                               uint32_t *soffset,
                               uint32_t *eoffset)
 {
+    struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
     struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
     int r;
+    int retries = 0;
 
     if (bo_legacy->map_count) {
         fprintf(stderr, "bo(%p, %d) is mapped (%d) can't valide it.\n",
@@ -560,17 +713,28 @@ int radeon_bo_legacy_validate(struct radeon_bo *bo,
     if (bo_legacy->static_bo || bo_legacy->validated) {
         *soffset = bo_legacy->offset;
         *eoffset = bo_legacy->offset + bo->size;
+
         return 0;
     }
     if (!(bo->domains & RADEON_GEM_DOMAIN_GTT)) {
+
         r = bo_vram_validate(bo, soffset, eoffset);
         if (r) {
-            return r;
+           legacy_track_pending(&boml->base, 0);
+           legacy_kick_all_buffers(boml);
+           retries++;
+           if (retries == 2) {
+               fprintf(stderr,"legacy bo: failed to get relocations into aperture\n");
+               assert(0);
+               exit(-1);
+           }
+           return -EAGAIN;
         }
     }
     *soffset = bo_legacy->offset;
     *eoffset = bo_legacy->offset + bo->size;
     bo_legacy->validated = 1;
+
     return 0;
 }
 
@@ -580,7 +744,7 @@ void radeon_bo_legacy_pending(struct radeon_bo *bo, uint32_t pending)
     struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
 
     bo_legacy->pending = pending;
-    bo_legacy->is_pending += 1;
+    bo_legacy->is_pending++;
     /* add to pending list */
     radeon_bo_ref(bo);
     if (bo_legacy->is_pending > 1) {
@@ -609,10 +773,32 @@ void radeon_bo_manager_legacy_dtor(struct radeon_bo_manager *bom)
         bo_free(bo_legacy);
         bo_legacy = next;
     }
+    driDestroyTextureHeap(boml->texture_heap);
     free(boml->free_handles);
     free(boml);
 }
 
+static struct bo_legacy *radeon_legacy_bo_alloc_static(struct bo_manager_legacy *bom,
+                                                      int size,
+                                                      uint32_t offset)
+{
+    struct bo_legacy *bo;
+
+    bo = bo_allocate(bom, size, 0, RADEON_GEM_DOMAIN_VRAM, 0);
+
+    if (bo == NULL)
+       return NULL;
+    bo->static_bo = 1;
+    bo->offset = offset + bom->fb_location;
+    bo->base.handle = bo->offset;
+    bo->ptr = bom->screen->driScreen->pFB + offset;
+    if (bo->base.handle > bom->nhandle) {
+        bom->nhandle = bo->base.handle + 1;
+    }
+    radeon_bo_ref(&(bo->base));
+    return bo;
+}
+
 struct radeon_bo_manager *radeon_bo_manager_legacy_ctor(struct radeon_screen *scrn)
 {
     struct bo_manager_legacy *bom;
@@ -625,6 +811,8 @@ struct radeon_bo_manager *radeon_bo_manager_legacy_ctor(struct radeon_screen *sc
         return NULL;
     }
 
+    make_empty_list(&bom->texture_swapped);
+
     bom->texture_heap = driCreateTextureHeap(0,
                                              bom,
                                              scrn->texSize[0],
@@ -633,7 +821,7 @@ struct radeon_bo_manager *radeon_bo_manager_legacy_ctor(struct radeon_screen *sc
                                              (drmTextureRegionPtr)scrn->sarea->tex_list[0],
                                              &scrn->sarea->tex_age[0],
                                              &bom->texture_swapped,
-                                             sizeof(struct bo_legacy),
+                                             sizeof(struct bo_legacy_texture_object),
                                              &bo_legacy_tobj_destroy);
     bom->texture_offset = scrn->texOffset[0];
 
@@ -656,41 +844,33 @@ struct radeon_bo_manager *radeon_bo_manager_legacy_ctor(struct radeon_screen *sc
 
     /* biggest framebuffer size */
     size = 4096*4096*4; 
+
     /* allocate front */
-    bo = bo_allocate(bom, size, 0, RADEON_GEM_DOMAIN_VRAM, 0);
-    if (bo == NULL) {
+    bo = radeon_legacy_bo_alloc_static(bom, size, bom->screen->frontOffset);
+
+    if (!bo) {
         radeon_bo_manager_legacy_dtor((struct radeon_bo_manager*)bom);
         return NULL;
     }
     if (scrn->sarea->tiling_enabled) {
         bo->base.flags = RADEON_BO_FLAGS_MACRO_TILE;
     }
-    bo->static_bo = 1;
-    bo->offset = bom->screen->frontOffset + bom->fb_location;
-    bo->base.handle = bo->offset;
-    bo->ptr = scrn->driScreen->pFB + bom->screen->frontOffset;
-    if (bo->base.handle > bom->nhandle) {
-        bom->nhandle = bo->base.handle + 1;
-    }
+
     /* allocate back */
-    bo = bo_allocate(bom, size, 0, RADEON_GEM_DOMAIN_VRAM, 0);
-    if (bo == NULL) {
+    bo = radeon_legacy_bo_alloc_static(bom, size, bom->screen->backOffset);
+
+    if (!bo) {
         radeon_bo_manager_legacy_dtor((struct radeon_bo_manager*)bom);
         return NULL;
     }
     if (scrn->sarea->tiling_enabled) {
         bo->base.flags = RADEON_BO_FLAGS_MACRO_TILE;
     }
-    bo->static_bo = 1;
-    bo->offset = bom->screen->backOffset + bom->fb_location;
-    bo->base.handle = bo->offset;
-    bo->ptr = scrn->driScreen->pFB + bom->screen->backOffset;
-    if (bo->base.handle > bom->nhandle) {
-        bom->nhandle = bo->base.handle + 1;
-    }
+
     /* allocate depth */
-    bo = bo_allocate(bom, size, 0, RADEON_GEM_DOMAIN_VRAM, 0);
-    if (bo == NULL) {
+    bo = radeon_legacy_bo_alloc_static(bom, size, bom->screen->depthOffset);
+
+    if (!bo) {
         radeon_bo_manager_legacy_dtor((struct radeon_bo_manager*)bom);
         return NULL;
     }
@@ -699,13 +879,6 @@ struct radeon_bo_manager *radeon_bo_manager_legacy_ctor(struct radeon_screen *sc
         bo->base.flags |= RADEON_BO_FLAGS_MACRO_TILE;
         bo->base.flags |= RADEON_BO_FLAGS_MICRO_TILE;
     }
-    bo->static_bo = 1;
-    bo->offset = bom->screen->depthOffset + bom->fb_location;
-    bo->base.handle = bo->offset;
-    bo->ptr = scrn->driScreen->pFB + bom->screen->depthOffset;
-    if (bo->base.handle > bom->nhandle) {
-        bom->nhandle = bo->base.handle + 1;
-    }
     return (struct radeon_bo_manager*)bom;
 }
 
@@ -724,3 +897,30 @@ unsigned radeon_bo_legacy_relocs_size(struct radeon_bo *bo)
     }
     return bo->size;
 }
+
+/*
+ * Fake up a bo for things like texture image_override.
+ * bo->offset already includes fb_location
+ */
+struct radeon_bo *radeon_legacy_bo_alloc_fake(struct radeon_bo_manager *bom,
+                                             int size,
+                                             uint32_t offset)
+{
+    struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bom;
+    struct bo_legacy *bo;
+
+    bo = bo_allocate(boml, size, 0, RADEON_GEM_DOMAIN_VRAM, 0);
+
+    if (bo == NULL)
+       return NULL;
+    bo->static_bo = 1;
+    bo->offset = offset;
+    bo->base.handle = bo->offset;
+    bo->ptr = boml->screen->driScreen->pFB + (offset - boml->fb_location);
+    if (bo->base.handle > boml->nhandle) {
+        boml->nhandle = bo->base.handle + 1;
+    }
+    radeon_bo_ref(&(bo->base));
+    return &(bo->base);
+}
+