From 39970c67b77014caac9a4c3a33765ac7a312b54e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 6 Jul 2009 13:34:24 +1000 Subject: radeon: move cs space checking code to libdrm_radeon. 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 | 1 + libdrm/radeon/radeon_bo.h | 8 ++ libdrm/radeon/radeon_bo_gem.c | 3 +- libdrm/radeon/radeon_cs.h | 55 +++++++--- libdrm/radeon/radeon_cs_gem.c | 95 +--------------- libdrm/radeon/radeon_cs_space.c | 234 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 288 insertions(+), 108 deletions(-) create mode 100644 libdrm/radeon/radeon_cs_space.c (limited to 'libdrm/radeon') diff --git a/libdrm/radeon/Makefile.am b/libdrm/radeon/Makefile.am index bc8a5b87..bec1beb3 100644 --- a/libdrm/radeon/Makefile.am +++ b/libdrm/radeon/Makefile.am @@ -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 diff --git a/libdrm/radeon/radeon_bo.h b/libdrm/radeon/radeon_bo.h index 3cabdfc4..597d0ef6 100644 --- a/libdrm/radeon/radeon_bo.h +++ b/libdrm/radeon/radeon_bo.h @@ -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)\ diff --git a/libdrm/radeon/radeon_bo_gem.c b/libdrm/radeon/radeon_bo_gem.c index 05d4409a..558b93ae 100644 --- a/libdrm/radeon/radeon_bo_gem.c +++ b/libdrm/radeon/radeon_bo_gem.c @@ -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) diff --git a/libdrm/radeon/radeon_cs.h b/libdrm/radeon/radeon_cs.h index d8709619..7efec7e8 100644 --- a/libdrm/radeon/radeon_cs.h +++ b/libdrm/radeon/radeon_cs.h @@ -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 diff --git a/libdrm/radeon/radeon_cs_gem.c b/libdrm/radeon/radeon_cs_gem.c index e06f2222..264b0675 100644 --- a/libdrm/radeon/radeon_cs_gem.c +++ b/libdrm/radeon/radeon_cs_gem.c @@ -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 index 00000000..5d0fe5c1 --- /dev/null +++ b/libdrm/radeon/radeon_cs_space.c @@ -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 +#include +#include +#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; +} + + -- cgit v1.2.3