summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/radeon/radeon_bo_legacy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers/dri/radeon/radeon_bo_legacy.c')
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_bo_legacy.c926
1 files changed, 926 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/radeon/radeon_bo_legacy.c b/src/mesa/drivers/dri/radeon/radeon_bo_legacy.c
new file mode 100644
index 00000000000..3e7547d2f9d
--- /dev/null
+++ b/src/mesa/drivers/dri/radeon/radeon_bo_legacy.c
@@ -0,0 +1,926 @@
+/*
+ * Copyright © 2008 Nicolai Haehnle
+ * Copyright © 2008 Dave Airlie
+ * Copyright © 2008 Jérôme Glisse
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ */
+/*
+ * Authors:
+ * Aapo Tahkola <aet@rasterburn.org>
+ * Nicolai Haehnle <prefect_@gmx.net>
+ * Dave Airlie
+ * Jérôme Glisse <glisse@freedesktop.org>
+ */
+#include <stdio.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include "xf86drm.h"
+#include "texmem.h"
+#include "main/simple_list.h"
+
+#include "drm.h"
+#include "radeon_drm.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;
+ int map_count;
+ uint32_t pending;
+ int is_pending;
+ int static_bo;
+ uint32_t offset;
+ struct bo_legacy_texture_object *tobj;
+ int validated;
+ int dirty;
+ void *ptr;
+ struct bo_legacy *next, *prev;
+ struct bo_legacy *pnext, *pprev;
+};
+
+struct bo_manager_legacy {
+ struct radeon_bo_manager base;
+ unsigned nhandle;
+ unsigned nfree_handles;
+ unsigned cfree_handles;
+ uint32_t current_age;
+ struct bo_legacy bos;
+ struct bo_legacy pending_bos;
+ 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;
+ struct radeon_screen *screen;
+ unsigned *free_handles;
+};
+
+static void bo_legacy_tobj_destroy(void *data, driTextureObject *t)
+{
+ 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;
+
+ *handle = 0;
+ if (bom->nhandle == 0xFFFFFFFF) {
+ return -EINVAL;
+ }
+ if (bom->cfree_handles > 0) {
+ tmp = bom->free_handles[--bom->cfree_handles];
+ clean_handles(bom);
+ } else {
+ bom->cfree_handles = 0;
+ tmp = bom->nhandle++;
+ }
+ assert(tmp);
+ *handle = tmp;
+ return 0;
+}
+
+static int legacy_free_handle(struct bo_manager_legacy *bom, uint32_t handle)
+{
+ uint32_t *handles;
+
+ if (!handle) {
+ return 0;
+ }
+ if (handle == (bom->nhandle - 1)) {
+ int i;
+
+ bom->nhandle--;
+ for (i = bom->cfree_handles - 1; i >= 0; i--) {
+ if (bom->free_handles[i] == (bom->nhandle - 1)) {
+ bom->nhandle--;
+ bom->free_handles[i] = 0;
+ }
+ }
+ clean_handles(bom);
+ return 0;
+ }
+ if (bom->cfree_handles < bom->nfree_handles) {
+ bom->free_handles[bom->cfree_handles++] = handle;
+ return 0;
+ }
+ bom->nfree_handles += 0x100;
+ handles = (uint32_t*)realloc(bom->free_handles, bom->nfree_handles * 4);
+ if (handles == NULL) {
+ bom->nfree_handles -= 0x100;
+ return -ENOMEM;
+ }
+ bom->free_handles = handles;
+ bom->free_handles[bom->cfree_handles++] = handle;
+ return 0;
+}
+
+static void legacy_get_current_age(struct bo_manager_legacy *boml)
+{
+ drm_radeon_getparam_t gp;
+ unsigned char *RADEONMMIO = NULL;
+ int r;
+
+ 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);
+ }
+}
+
+static int legacy_is_pending(struct radeon_bo *bo)
+{
+ struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
+ struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
+
+ if (bo_legacy->is_pending <= 0) {
+ bo_legacy->is_pending = 0;
+ return 0;
+ }
+ if (boml->current_age >= bo_legacy->pending) {
+ if (boml->pending_bos.pprev == bo_legacy) {
+ boml->pending_bos.pprev = bo_legacy->pprev;
+ }
+ bo_legacy->pprev->pnext = bo_legacy->pnext;
+ if (bo_legacy->pnext) {
+ bo_legacy->pnext->pprev = bo_legacy->pprev;
+ }
+ assert(bo_legacy->is_pending <= bo->cref);
+ while (bo_legacy->is_pending--) {
+ bo = radeon_bo_unref(bo);
+ if (!bo)
+ break;
+ }
+ if (bo)
+ bo_legacy->is_pending = 0;
+ boml->cpendings--;
+ return 0;
+ }
+ return 1;
+}
+
+static int legacy_wait_pending(struct radeon_bo *bo)
+{
+ struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
+ struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
+
+ if (!bo_legacy->is_pending) {
+ return 0;
+ }
+ /* FIXME: lockup and userspace busy looping that's all the folks */
+ legacy_get_current_age(boml);
+ while (legacy_is_pending(bo)) {
+ usleep(10);
+ legacy_get_current_age(boml);
+ }
+ return 0;
+}
+
+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))) {
+ }
+ bo_legacy = next;
+ }
+}
+
+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,
+ uint32_t domains,
+ 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) {
+ return NULL;
+ }
+ bo_legacy->base.bom = (struct radeon_bo_manager*)boml;
+ bo_legacy->base.handle = 0;
+ bo_legacy->base.size = size;
+ bo_legacy->base.alignment = alignment;
+ bo_legacy->base.domains = domains;
+ bo_legacy->base.flags = flags;
+ bo_legacy->base.ptr = NULL;
+ bo_legacy->map_count = 0;
+ bo_legacy->next = NULL;
+ bo_legacy->prev = NULL;
+ bo_legacy->pnext = NULL;
+ bo_legacy->pprev = NULL;
+ bo_legacy->next = boml->bos.next;
+ bo_legacy->prev = &boml->bos;
+ boml->bos.next = bo_legacy;
+ if (bo_legacy->next) {
+ bo_legacy->next->prev = bo_legacy;
+ }
+
+ return bo_legacy;
+}
+
+static int bo_dma_alloc(struct radeon_bo *bo)
+{
+ struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
+ struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
+ drm_radeon_mem_alloc_t alloc;
+ unsigned size;
+ int base_offset;
+ int r;
+
+ /* align size on 4Kb */
+ size = (((4 * 1024) - 1) + bo->size) & ~((4 * 1024) - 1);
+ alloc.region = RADEON_MEM_REGION_GART;
+ alloc.alignment = bo_legacy->base.alignment;
+ alloc.size = size;
+ alloc.region_offset = &base_offset;
+ r = drmCommandWriteRead(bo->bom->fd,
+ DRM_RADEON_ALLOC,
+ &alloc,
+ sizeof(alloc));
+ if (r) {
+ /* ptr is set to NULL if dma allocation failed */
+ bo_legacy->ptr = NULL;
+ 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;
+}
+
+static int bo_dma_free(struct radeon_bo *bo)
+{
+ struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
+ struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
+ drm_radeon_mem_free_t memfree;
+ int r;
+
+ if (bo_legacy->ptr == NULL) {
+ /* ptr is set to NULL if dma allocation failed */
+ return 0;
+ }
+ legacy_get_current_age(boml);
+ memfree.region = RADEON_MEM_REGION_GART;
+ memfree.region_offset = bo_legacy->offset;
+ memfree.region_offset -= boml->screen->gart_texture_offset;
+ r = drmCommandWrite(boml->base.fd,
+ DRM_RADEON_FREE,
+ &memfree,
+ sizeof(memfree));
+ if (r) {
+ fprintf(stderr, "Failed to free bo[%p] at %08x\n",
+ &bo_legacy->base, memfree.region_offset);
+ fprintf(stderr, "ret = %s\n", strerror(-r));
+ return r;
+ }
+ boml->dma_alloc_size -= bo_legacy->base.size;
+ boml->dma_buf_count--;
+ return 0;
+}
+
+static void bo_free(struct bo_legacy *bo_legacy)
+{
+ struct bo_manager_legacy *boml;
+
+ if (bo_legacy == NULL) {
+ return;
+ }
+ boml = (struct bo_manager_legacy *)bo_legacy->base.bom;
+ bo_legacy->prev->next = bo_legacy->next;
+ if (bo_legacy->next) {
+ bo_legacy->next->prev = bo_legacy->prev;
+ }
+ if (!bo_legacy->static_bo) {
+ legacy_free_handle(boml, bo_legacy->base.handle);
+ if (bo_legacy->base.domains & RADEON_GEM_DOMAIN_GTT) {
+ /* 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);
+ }
+ }
+ memset(bo_legacy, 0 , sizeof(struct bo_legacy));
+ free(bo_legacy);
+}
+
+static struct radeon_bo *bo_open(struct radeon_bo_manager *bom,
+ uint32_t handle,
+ uint32_t size,
+ uint32_t alignment,
+ uint32_t domains,
+ uint32_t flags)
+{
+ struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bom;
+ struct bo_legacy *bo_legacy;
+ int r;
+
+ if (handle) {
+ bo_legacy = boml->bos.next;
+ while (bo_legacy) {
+ if (bo_legacy->base.handle == handle) {
+ radeon_bo_ref(&(bo_legacy->base));
+ return (struct radeon_bo*)bo_legacy;
+ }
+ bo_legacy = bo_legacy->next;
+ }
+ 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);
+ if (r) {
+ bo_free(bo_legacy);
+ return NULL;
+ }
+ 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)
+ {
+ if (legacy_wait_any_pending(boml) == -1)
+ {
+ bo_free(bo_legacy);
+ return NULL;
+ }
+ goto retry;
+ return NULL;
+ }
+ }
+ else
+ {
+ bo_legacy->ptr = malloc(bo_legacy->base.size);
+ if (bo_legacy->ptr == NULL) {
+ bo_free(bo_legacy);
+ return NULL;
+ }
+ }
+ radeon_bo_ref(&(bo_legacy->base));
+
+ return (struct radeon_bo*)bo_legacy;
+}
+
+static void bo_ref(struct radeon_bo *bo)
+{
+}
+
+static struct radeon_bo *bo_unref(struct radeon_bo *bo)
+{
+ struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
+
+ if (bo->cref <= 0) {
+ bo_legacy->prev->next = bo_legacy->next;
+ if (bo_legacy->next) {
+ bo_legacy->next->prev = bo_legacy->prev;
+ }
+ if (!bo_legacy->is_pending) {
+ bo_free(bo_legacy);
+ }
+ return NULL;
+ }
+ return bo;
+}
+
+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;
+ bo_legacy->map_count++;
+ bo->ptr = bo_legacy->ptr;
+ /* Read the first pixel in the frame buffer. This should
+ * be a noop, right? In fact without this conform fails as reading
+ * from the framebuffer sometimes produces old results -- the
+ * on-card read cache gets mixed up and doesn't notice that the
+ * framebuffer has been updated.
+ *
+ * Note that we should probably be reading some otherwise unused
+ * region of VRAM, otherwise we might get incorrect results when
+ * reading pixels from the top left of the screen.
+ *
+ * I found this problem on an R420 with glean's texCube test.
+ * Note that the R200 span code also *writes* the first pixel in the
+ * 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;
+ }
+
+ return 0;
+}
+
+static int bo_unmap(struct radeon_bo *bo)
+{
+ struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
+
+ 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,
+ NULL,
+ bo_is_static,
+ NULL,
+ NULL,
+ bo_is_busy
+};
+
+static int bo_vram_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 retry_count = 0, pending_retry = 0;
+
+ 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->tobj->base);
+ if (r) {
+ 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->tobj->base.memBlock->ofs;
+ bo_legacy->dirty = 1;
+ }
+
+ 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",
+ bo, bo->size, bo_legacy->map_count);
+ return -EINVAL;
+ }
+ 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) {
+ 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;
+}
+
+void radeon_bo_legacy_pending(struct radeon_bo *bo, uint32_t pending)
+{
+ struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bo->bom;
+ struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
+
+ bo_legacy->pending = pending;
+ bo_legacy->is_pending++;
+ /* add to pending list */
+ radeon_bo_ref(bo);
+ if (bo_legacy->is_pending > 1) {
+ return;
+ }
+ bo_legacy->pprev = boml->pending_bos.pprev;
+ bo_legacy->pnext = NULL;
+ bo_legacy->pprev->pnext = bo_legacy;
+ boml->pending_bos.pprev = bo_legacy;
+ boml->cpendings++;
+}
+
+void radeon_bo_manager_legacy_dtor(struct radeon_bo_manager *bom)
+{
+ struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bom;
+ struct bo_legacy *bo_legacy;
+
+ if (bom == NULL) {
+ return;
+ }
+ bo_legacy = boml->bos.next;
+ while (bo_legacy) {
+ struct bo_legacy *next;
+
+ next = bo_legacy->next;
+ 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;
+ struct bo_legacy *bo;
+ unsigned size;
+
+ bom = (struct bo_manager_legacy*)
+ calloc(1, sizeof(struct bo_manager_legacy));
+ if (bom == NULL) {
+ return NULL;
+ }
+
+ make_empty_list(&bom->texture_swapped);
+
+ bom->texture_heap = driCreateTextureHeap(0,
+ bom,
+ scrn->texSize[0],
+ 12,
+ RADEON_NR_TEX_REGIONS,
+ (drmTextureRegionPtr)scrn->sarea->tex_list[0],
+ &scrn->sarea->tex_age[0],
+ &bom->texture_swapped,
+ sizeof(struct bo_legacy_texture_object),
+ &bo_legacy_tobj_destroy);
+ bom->texture_offset = scrn->texOffset[0];
+
+ bom->base.funcs = &bo_legacy_funcs;
+ bom->base.fd = scrn->driScreen->fd;
+ bom->bos.next = NULL;
+ bom->bos.prev = NULL;
+ bom->pending_bos.pprev = &bom->pending_bos;
+ bom->pending_bos.pnext = NULL;
+ bom->screen = scrn;
+ bom->fb_location = scrn->fbLocation;
+ bom->nhandle = 1;
+ bom->cfree_handles = 0;
+ bom->nfree_handles = 0x400;
+ bom->free_handles = (uint32_t*)malloc(bom->nfree_handles * 4);
+ if (bom->free_handles == NULL) {
+ radeon_bo_manager_legacy_dtor((struct radeon_bo_manager*)bom);
+ return NULL;
+ }
+
+ /* biggest framebuffer size */
+ size = 4096*4096*4;
+
+ /* allocate front */
+ 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;
+ }
+
+ /* allocate back */
+ 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;
+ }
+
+ /* allocate depth */
+ 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;
+ }
+ bo->base.flags = 0;
+ if (scrn->sarea->tiling_enabled) {
+ bo->base.flags |= RADEON_BO_FLAGS_MACRO_TILE;
+ bo->base.flags |= RADEON_BO_FLAGS_MICRO_TILE;
+ }
+ return (struct radeon_bo_manager*)bom;
+}
+
+void radeon_bo_legacy_texture_age(struct radeon_bo_manager *bom)
+{
+ struct bo_manager_legacy *boml = (struct bo_manager_legacy *)bom;
+ DRI_AGE_TEXTURES(boml->texture_heap);
+}
+
+unsigned radeon_bo_legacy_relocs_size(struct radeon_bo *bo)
+{
+ struct bo_legacy *bo_legacy = (struct bo_legacy*)bo;
+
+ if (bo_legacy->static_bo || (bo->domains & RADEON_GEM_DOMAIN_GTT)) {
+ return 0;
+ }
+ 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);
+}
+