radeon: move cs space checking code to libdrm_radeon.
authorDave Airlie <airlied@redhat.com>
Mon, 6 Jul 2009 03:34:24 +0000 (13:34 +1000)
committerDave Airlie <airlied@redhat.com>
Mon, 6 Jul 2009 05:10:11 +0000 (15:10 +1000)
This ports a lot of the space checking code into a the common
library, so that the DDX and mesa can use it.

libdrm/radeon/Makefile.am
libdrm/radeon/radeon_bo.h
libdrm/radeon/radeon_bo_gem.c
libdrm/radeon/radeon_cs.h
libdrm/radeon/radeon_cs_gem.c
libdrm/radeon/radeon_cs_space.c [new file with mode: 0644]

index bc8a5b8..bec1beb 100644 (file)
@@ -37,6 +37,7 @@ libdrm_radeon_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@
 libdrm_radeon_la_SOURCES = \
        radeon_bo_gem.c \
        radeon_cs_gem.c \
+       radeon_cs_space.c \
        radeon_track.c
 
 libdrm_radeonincludedir = ${includedir}/drm
index 3cabdfc..597d0ef 100644 (file)
@@ -68,6 +68,7 @@ struct radeon_bo_funcs {
     int (*bo_map)(struct radeon_bo *bo, int write);
     int (*bo_unmap)(struct radeon_bo *bo);
     int (*bo_wait)(struct radeon_bo *bo);
+    int (*bo_is_static)(struct radeon_bo *bo);
 };
 
 struct radeon_bo_manager {
@@ -161,6 +162,13 @@ static inline int _radeon_bo_wait(struct radeon_bo *bo,
     return bo->bom->funcs->bo_wait(bo);
 }
 
+static inline int radeon_bo_is_static(struct radeon_bo *bo)
+{
+    if (bo->bom->funcs->bo_is_static)
+       return bo->bom->funcs->bo_is_static(bo);
+    return 0;
+}
+
 #define radeon_bo_open(bom, h, s, a, d, f)\
     _radeon_bo_open(bom, h, s, a, d, f, __FILE__, __FUNCTION__, __LINE__)
 #define radeon_bo_ref(bo)\
index 05d4409..558b93a 100644 (file)
@@ -204,7 +204,8 @@ static struct radeon_bo_funcs bo_gem_funcs = {
     bo_unref,
     bo_map,
     bo_unmap,
-    bo_wait
+    bo_wait,
+    NULL,
 };
 
 struct radeon_bo_manager *radeon_bo_manager_gem_ctor(int fd)
index d870961..7efec7e 100644 (file)
@@ -57,6 +57,8 @@ struct radeon_cs_space_check {
     uint32_t new_accounted;
 };
 
+#define MAX_SPACE_BOS (32)
+
 struct radeon_cs_manager;
 
 struct radeon_cs {
@@ -73,7 +75,10 @@ struct radeon_cs {
     const char                  *section_file;
     const char                  *section_func;
     int                         section_line;
-
+    struct radeon_cs_space_check bos[MAX_SPACE_BOS];
+    int                         bo_count;
+    void                        (*space_flush_fn)(void *);
+    void                        *space_flush_data;
 };
 
 /* cs functions */
@@ -99,16 +104,14 @@ struct radeon_cs_funcs {
     int (*cs_erase)(struct radeon_cs *cs);
     int (*cs_need_flush)(struct radeon_cs *cs);
     void (*cs_print)(struct radeon_cs *cs, FILE *file);
-    int (*cs_space_check)(struct radeon_cs *cs, struct radeon_cs_space_check *bos,
-                         int num_bo);
 };
 
 struct radeon_cs_manager {
     struct radeon_cs_funcs  *funcs;
     int                     fd;
-    uint32_t vram_limit, gart_limit;
-    uint32_t vram_write_used, gart_write_used;
-    uint32_t read_used;
+    int32_t vram_limit, gart_limit;
+    int32_t vram_write_used, gart_write_used;
+    int32_t read_used;
 };
 
 static inline struct radeon_cs *radeon_cs_create(struct radeon_cs_manager *csm,
@@ -172,13 +175,6 @@ static inline void radeon_cs_print(struct radeon_cs *cs, FILE *file)
     cs->csm->funcs->cs_print(cs, file);
 }
 
-static inline int radeon_cs_space_check(struct radeon_cs *cs,
-                                           struct radeon_cs_space_check *bos,
-                                           int num_bo)
-{
-    return cs->csm->funcs->cs_space_check(cs, bos, num_bo);
-}
-
 static inline void radeon_cs_set_limit(struct radeon_cs *cs, uint32_t domain, uint32_t limit)
 {
     
@@ -205,4 +201,37 @@ static inline void radeon_cs_write_qword(struct radeon_cs *cs, uint64_t qword)
     }
 }
 
+static inline void radeon_cs_space_set_flush(struct radeon_cs *cs, void (*fn)(void *), void *data)
+{
+    cs->space_flush_fn = fn;
+    cs->space_flush_data = data;
+}
+
+
+/*
+ * add a persistent BO to the list
+ * a persistent BO is one that will be referenced across flushes,
+ * i.e. colorbuffer, textures etc.
+ * They get reset when a new "operation" happens, where an operation
+ * is a state emission with a color/textures etc followed by a bunch of vertices.
+ */
+void radeon_cs_space_add_persistent_bo(struct radeon_cs *cs,
+                                      struct radeon_bo *bo,
+                                      uint32_t read_domains,
+                                      uint32_t write_domain);
+
+/* reset the persistent BO list */
+void radeon_cs_space_reset_bos(struct radeon_cs *cs);
+
+/* do a space check with the current persistent BO list */
+int radeon_cs_space_check(struct radeon_cs *cs);
+
+/* do a space check with the current persistent BO list and a temporary BO
+ * a temporary BO is like a DMA buffer, which  gets flushed with the
+ * command buffer */
+int radeon_cs_space_check_with_bo(struct radeon_cs *cs,
+                                 struct radeon_bo *bo,
+                                 uint32_t read_domains,
+                                 uint32_t write_domain);
+
 #endif
index e06f222..264b067 100644 (file)
@@ -423,99 +423,7 @@ static void cs_gem_print(struct radeon_cs *cs, FILE *file)
     }
 }
 
-static int cs_gem_check_space(struct radeon_cs *cs, struct radeon_cs_space_check *bos, int num_bo)
-{
-    struct radeon_cs_manager *csm = cs->csm;
-    int this_op_read = 0, this_op_gart_write = 0, this_op_vram_write = 0;
-    uint32_t read_domains, write_domain;
-    int i;
-    struct radeon_bo *bo;
-
-    /* check the totals for this operation */
-
-    if (num_bo == 0)
-        return 0;
-
-    /* prepare */
-    for (i = 0; i < num_bo; i++) {
-      bo = bos[i].bo;
-
-      bos[i].new_accounted = 0;
-      read_domains = bos[i].read_domains;
-      write_domain = bos[i].write_domain;
-               
-      /* already accounted this bo */
-      if (write_domain && (write_domain == bo->space_accounted)) {
-             bos[i].new_accounted = bo->space_accounted;
-             continue;
-      }
-      if (read_domains && ((read_domains << 16) == bo->space_accounted)) {
-             bos[i].new_accounted = bo->space_accounted;
-             continue;
-      }
-      
-      if (bo->space_accounted == 0) {
-         if (write_domain == RADEON_GEM_DOMAIN_VRAM)
-             this_op_vram_write += bo->size;
-         else if (write_domain == RADEON_GEM_DOMAIN_GTT)
-             this_op_gart_write += bo->size;
-         else
-             this_op_read += bo->size;
-         bos[i].new_accounted = (read_domains << 16) | write_domain;
-      } else {
-         uint16_t old_read, old_write;
-         
-         old_read = bo->space_accounted >> 16;
-         old_write = bo->space_accounted & 0xffff;
-
-         if (write_domain && (old_read & write_domain)) {
-             bos[i].new_accounted = write_domain;
-             /* moving from read to a write domain */
-             if (write_domain == RADEON_GEM_DOMAIN_VRAM) {
-                 this_op_read -= bo->size;
-                 this_op_vram_write += bo->size;
-             } else if (write_domain == RADEON_GEM_DOMAIN_VRAM) {
-                 this_op_read -= bo->size;
-                 this_op_gart_write += bo->size;
-             }
-         } else if (read_domains & old_write) {
-             bos[i].new_accounted = bo->space_accounted & 0xffff;
-         } else {
-             /* rewrite the domains */
-             if (write_domain != old_write)
-                 fprintf(stderr,"WRITE DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, write_domain, old_write);
-             if (read_domains != old_read)
-                 fprintf(stderr,"READ DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, read_domains, old_read);
-             return RADEON_CS_SPACE_FLUSH;
-         }
-      }
-    }
-       
-    if (this_op_read < 0)
-           this_op_read = 0;
-
-    /* check sizes - operation first */
-    if ((this_op_read + this_op_gart_write > csm->gart_limit) ||
-       (this_op_vram_write > csm->vram_limit)) {
-           return RADEON_CS_SPACE_OP_TO_BIG;
-    }
-    
-    if (((csm->vram_write_used + this_op_vram_write) > csm->vram_limit) ||
-       ((csm->read_used + csm->gart_write_used + this_op_gart_write + this_op_read) > csm->gart_limit)) {
-           return RADEON_CS_SPACE_FLUSH;
-    }
-    
-    csm->gart_write_used += this_op_gart_write;
-    csm->vram_write_used += this_op_vram_write;
-    csm->read_used += this_op_read;
-    /* commit */
-    for (i = 0; i < num_bo; i++) {
-           bo = bos[i].bo;
-           bo->space_accounted = bos[i].new_accounted;
-    }
-    
-    return RADEON_CS_SPACE_OK;
-}
+
 
 static struct radeon_cs_funcs radeon_cs_gem_funcs = {
     cs_gem_create,
@@ -527,7 +435,6 @@ static struct radeon_cs_funcs radeon_cs_gem_funcs = {
     cs_gem_erase,
     cs_gem_need_flush,
     cs_gem_print,
-    cs_gem_check_space,
 };
 
 struct radeon_cs_manager *radeon_cs_manager_gem_ctor(int fd)
diff --git a/libdrm/radeon/radeon_cs_space.c b/libdrm/radeon/radeon_cs_space.c
new file mode 100644 (file)
index 0000000..5d0fe5c
--- /dev/null
@@ -0,0 +1,234 @@
+/* 
+ * Copyright © 2009 Red Hat Inc.
+ * 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.
+ */
+/*
+ */
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "radeon_cs.h"
+
+struct rad_sizes {
+    int32_t op_read;
+    int32_t op_gart_write;
+    int32_t op_vram_write;
+};
+
+static inline int radeon_cs_setup_bo(struct radeon_cs_space_check *sc, struct rad_sizes *sizes)
+{
+    uint32_t read_domains, write_domain;
+    struct radeon_bo *bo;
+
+    bo = sc->bo;
+    sc->new_accounted = 0;
+    read_domains = sc->read_domains;
+    write_domain = sc->write_domain;
+
+    /* legacy needs a static check */
+    if (radeon_bo_is_static(bo)) {
+       bo->space_accounted = sc->new_accounted = (read_domains << 16) | write_domain;
+       return 0;
+    }
+
+    /* already accounted this bo */
+    if (write_domain && (write_domain == bo->space_accounted)) {
+       sc->new_accounted = bo->space_accounted;
+       return 0;
+    }
+    if (read_domains && ((read_domains << 16) == bo->space_accounted)) {
+       sc->new_accounted = bo->space_accounted;
+       return 0;
+    }
+
+    if (bo->space_accounted == 0) {
+       if (write_domain == RADEON_GEM_DOMAIN_VRAM)
+           sizes->op_vram_write += bo->size;
+       else if (write_domain == RADEON_GEM_DOMAIN_GTT)
+         sizes->op_gart_write += bo->size;
+       else
+           sizes->op_read += bo->size;
+       sc->new_accounted = (read_domains << 16) | write_domain;
+    } else {
+       uint16_t old_read, old_write;
+       
+       old_read = bo->space_accounted >> 16;
+       old_write = bo->space_accounted & 0xffff;
+       
+       if (write_domain && (old_read & write_domain)) {
+           sc->new_accounted = write_domain;
+           /* moving from read to a write domain */
+           if (write_domain == RADEON_GEM_DOMAIN_VRAM) {
+               sizes->op_read -= bo->size;
+               sizes->op_vram_write += bo->size;
+           } else if (write_domain == RADEON_GEM_DOMAIN_VRAM) {
+               sizes->op_read -= bo->size;
+               sizes->op_gart_write += bo->size;
+           }
+       } else if (read_domains & old_write) {
+           sc->new_accounted = bo->space_accounted & 0xffff;
+       } else {
+           /* rewrite the domains */
+           if (write_domain != old_write)
+               fprintf(stderr,"WRITE DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, write_domain, old_write);
+           if (read_domains != old_read)
+               fprintf(stderr,"READ DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, read_domains, old_read);
+           return RADEON_CS_SPACE_FLUSH;
+       }
+    }
+    return 0;
+}
+
+static int radeon_cs_do_space_check(struct radeon_cs *cs, struct radeon_cs_space_check *new_tmp)
+{
+    struct radeon_cs_manager *csm = cs->csm;
+    int i;
+    struct radeon_bo *bo;
+    struct rad_sizes sizes;
+    int ret;
+
+    /* check the totals for this operation */
+
+    if (cs->bo_count == 0 && !new_tmp)
+       return 0;
+
+    memset(&sizes, 0, sizeof(struct rad_sizes));
+
+    /* prepare */
+    for (i = 0; i < cs->bo_count; i++) {
+       ret = radeon_cs_setup_bo(&cs->bos[i], &sizes);
+       if (ret)
+           return ret;
+    }
+
+    if (new_tmp) {
+       ret = radeon_cs_setup_bo(new_tmp, &sizes);
+       if (ret)
+           return ret;
+    }
+       
+    if (sizes.op_read < 0)
+           sizes.op_read = 0;
+
+    /* check sizes - operation first */
+    if ((sizes.op_read + sizes.op_gart_write > csm->gart_limit) ||
+       (sizes.op_vram_write > csm->vram_limit)) {
+           return RADEON_CS_SPACE_OP_TO_BIG;
+    }
+    
+    if (((csm->vram_write_used + sizes.op_vram_write) > csm->vram_limit) ||
+       ((csm->read_used + csm->gart_write_used + sizes.op_gart_write + sizes.op_read) > csm->gart_limit)) {
+           return RADEON_CS_SPACE_FLUSH;
+    }
+    
+    csm->gart_write_used += sizes.op_gart_write;
+    csm->vram_write_used += sizes.op_vram_write;
+    csm->read_used += sizes.op_read;
+    /* commit */
+    for (i = 0; i < cs->bo_count; i++) {
+           bo = cs->bos[i].bo;
+           bo->space_accounted = cs->bos[i].new_accounted;
+    }
+    if (new_tmp)
+       new_tmp->bo->space_accounted = new_tmp->new_accounted;
+    
+    return RADEON_CS_SPACE_OK;
+}
+
+void radeon_cs_space_add_persistent_bo(struct radeon_cs *cs, struct radeon_bo *bo, uint32_t read_domains, uint32_t write_domain)
+{
+    int i;
+    for (i = 0; i < cs->bo_count; i++) {
+       if (cs->bos[i].bo == bo &&
+           cs->bos[i].read_domains == read_domains &&
+           cs->bos[i].write_domain == write_domain)
+           return;
+    }
+    radeon_bo_ref(bo);
+    i = cs->bo_count;
+    cs->bos[i].bo = bo;
+    cs->bos[i].read_domains = read_domains;
+    cs->bos[i].write_domain = write_domain;
+    cs->bos[i].new_accounted = 0;
+    cs->bo_count++;
+
+    assert(cs->bo_count < MAX_SPACE_BOS);
+}
+
+static int radeon_cs_check_space_internal(struct radeon_cs *cs, struct radeon_cs_space_check *tmp_bo)
+{
+    int ret;
+    int flushed = 0;
+
+again:
+    ret = radeon_cs_do_space_check(cs, tmp_bo);
+    if (ret == RADEON_CS_SPACE_OP_TO_BIG)
+       return -1;
+    if (ret == RADEON_CS_SPACE_FLUSH) {
+       (*cs->space_flush_fn)(cs->space_flush_data);
+       if (flushed)
+           return -1;
+       flushed = 1;
+       goto again;
+    }
+    return 0;
+}
+
+int radeon_cs_space_check_with_bo(struct radeon_cs *cs,
+                                 struct radeon_bo *bo,
+                                 uint32_t read_domains, uint32_t write_domain)
+{                                                                      
+    struct radeon_cs_space_check temp_bo;
+    int ret = 0;
+
+    if (bo) {
+       temp_bo.bo = bo;
+       temp_bo.read_domains = read_domains;
+       temp_bo.write_domain = write_domain;
+       temp_bo.new_accounted = 0;
+    }
+
+    ret = radeon_cs_check_space_internal(cs, bo ? &temp_bo : NULL);
+    return ret;
+}
+
+int radeon_cs_space_check(struct radeon_cs *cs)
+{
+    return radeon_cs_check_space_internal(cs, NULL);
+}
+
+void radeon_cs_space_reset_bos(struct radeon_cs *cs)
+{
+    int i;
+    for (i = 0; i < cs->bo_count; i++) {
+       radeon_bo_unref(cs->bos[i].bo);
+       cs->bos[i].bo = NULL;
+       cs->bos[i].read_domains = 0;
+       cs->bos[i].write_domain = 0;
+       cs->bos[i].new_accounted = 0;
+    }
+    cs->bo_count = 0;
+}
+
+