From 5dddeb7776c62b6218add3a236551cde876b1cf0 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 12 Oct 2011 15:27:10 +0200 Subject: winsys/svga: Rework buffer allocation to make it more robust v2. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't allow any "CPU" buffers to be allocated by the pb_fenced buffer manager, since we can't protect against failures during buffer validation. Also, add an extra slab buffer manager to allocate buffers from the kernel if there is a failure to allocate from our big buffer pool. The reason we use a slab manager for this, is to avoid allocating many very small buffers from the kernel. v2: Increased VMW_MAX_BUFFER_SIZE and fixed some comments. Signed-off-by: Thomas Hellstrom Reviewed-by: José Fonseca Reviewed-by: Jakob Bornecrantz --- src/gallium/winsys/svga/drm/vmw_screen.h | 8 ++++ src/gallium/winsys/svga/drm/vmw_screen_pools.c | 56 ++++++++++++++++++-------- src/gallium/winsys/svga/drm/vmw_screen_svga.c | 10 ++++- 3 files changed, 57 insertions(+), 17 deletions(-) (limited to 'src/gallium/winsys/svga') diff --git a/src/gallium/winsys/svga/drm/vmw_screen.h b/src/gallium/winsys/svga/drm/vmw_screen.h index 37ccc91dc0e..1ddebf208ce 100644 --- a/src/gallium/winsys/svga/drm/vmw_screen.h +++ b/src/gallium/winsys/svga/drm/vmw_screen.h @@ -43,6 +43,12 @@ #define VMW_GMR_POOL_SIZE (16*1024*1024) #define VMW_QUERY_POOL_SIZE (8192) +/* + * Something big, but arbitrary. The kernel reports an error if it can't + * handle this, and the svga driver will resort to multiple partial + * uploads. + */ +#define VMW_MAX_BUFFER_SIZE (512*1024*1024) struct pb_manager; struct vmw_region; @@ -65,6 +71,8 @@ struct vmw_winsys_screen struct pb_manager *gmr; struct pb_manager *gmr_mm; struct pb_manager *gmr_fenced; + struct pb_manager *gmr_slab; + struct pb_manager *gmr_slab_fenced; struct pb_manager *query; struct pb_manager *query_mm; struct pb_manager *query_fenced; diff --git a/src/gallium/winsys/svga/drm/vmw_screen_pools.c b/src/gallium/winsys/svga/drm/vmw_screen_pools.c index 6350ea3cd4f..2525604f952 100644 --- a/src/gallium/winsys/svga/drm/vmw_screen_pools.c +++ b/src/gallium/winsys/svga/drm/vmw_screen_pools.c @@ -54,6 +54,9 @@ vmw_pools_cleanup(struct vmw_winsys_screen *vws) /* gmr_mm pool is already destroyed above */ + if (vws->pools.gmr_slab_fenced) + vws->pools.gmr_slab_fenced->destroy(vws->pools.gmr_slab_fenced); + if(vws->pools.gmr) vws->pools.gmr->destroy(vws->pools.gmr); if(vws->pools.query) @@ -110,6 +113,8 @@ vmw_query_pools_init(struct vmw_winsys_screen *vws) boolean vmw_pools_init(struct vmw_winsys_screen *vws) { + struct pb_desc desc; + vws->pools.gmr = vmw_gmr_bufmgr_create(vws); if(!vws->pools.gmr) goto error; @@ -121,26 +126,18 @@ vmw_pools_init(struct vmw_winsys_screen *vws) goto error; /* - * GMR buffers are typically shortlived, but it's possible that at a given - * instance a buffer is mapped. So to avoid stalling we tell pipebuffer to - * forbid creation of buffers beyond half the GMR pool size, - * - * XXX: It is unclear weather we want to limit the total amount of temporary - * malloc memory used to backup unvalidated GMR buffers. On one hand it is - * preferrable to fail an allocation than exhausting the guest memory with - * temporary data, but on the other hand it is possible that a stupid - * application creates large vertex buffers and does not use them for a long - * time -- since the svga pipe driver only emits the DMA uploads when a - * buffer is used for drawing this would effectively disabling swapping GMR - * buffers to memory. So far, the preemptively flush already seems to keep - * total allocated memory within relatively small numbers, so we don't - * limit. + * We disallow "CPU" buffers to be created by the fenced_bufmgr_create, + * because that defers "GPU" buffer creation to buffer validation, + * and at buffer validation we have no means of handling failures + * due to pools space shortage or fragmentation. Effectively this + * makes sure all failures are reported immediately on buffer allocation, + * and we can revert to allocating directly from the kernel. */ vws->pools.gmr_fenced = fenced_bufmgr_create( vws->pools.gmr_mm, vmw_fence_ops_create(vws), - VMW_GMR_POOL_SIZE/2, - ~0); + VMW_GMR_POOL_SIZE, + 0); #ifdef DEBUG vws->pools.gmr_fenced = pb_debug_manager_create(vws->pools.gmr_fenced, @@ -150,6 +147,33 @@ vmw_pools_init(struct vmw_winsys_screen *vws) if(!vws->pools.gmr_fenced) goto error; + /* + * The slab pool allocates buffers directly from the kernel except + * for very small buffers which are allocated from a slab in order + * not to waste memory, since a kernel buffer is a minimum 4096 bytes. + * + * Here we use it only for emergency in the case our pre-allocated + * buffer pool runs out of memory. + */ + desc.alignment = 64; + desc.usage = ~0; + vws->pools.gmr_slab = pb_slab_range_manager_create(vws->pools.gmr, + 64, + 8192, + 16384, + &desc); + if (!vws->pools.gmr_slab) + goto error; + + vws->pools.gmr_slab_fenced = + fenced_bufmgr_create(vws->pools.gmr_slab, + vmw_fence_ops_create(vws), + VMW_MAX_BUFFER_SIZE, + 0); + + if (!vws->pools.gmr_slab_fenced) + goto error; + vws->pools.query_fenced = NULL; vws->pools.query_mm = NULL; vws->pools.query = NULL; diff --git a/src/gallium/winsys/svga/drm/vmw_screen_svga.c b/src/gallium/winsys/svga/drm/vmw_screen_svga.c index df4a384d3ee..bf817ca88d8 100644 --- a/src/gallium/winsys/svga/drm/vmw_screen_svga.c +++ b/src/gallium/winsys/svga/drm/vmw_screen_svga.c @@ -73,7 +73,15 @@ vmw_svga_winsys_buffer_create(struct svga_winsys_screen *sws, assert(provider); buffer = provider->create_buffer(provider, size, &desc); - if(!buffer) + + if(!buffer && provider == vws->pools.gmr_fenced) { + + assert(provider); + provider = vws->pools.gmr_slab_fenced; + buffer = provider->create_buffer(provider, size, &desc); + } + + if (!buffer) return NULL; return vmw_svga_winsys_buffer(buffer); -- cgit v1.2.3