summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Hellstrom <thellstrom@vmware.com>2011-10-12 15:27:10 +0200
committerThomas Hellstrom <thellstrom@vmware.com>2011-10-14 09:53:19 +0200
commit5dddeb7776c62b6218add3a236551cde876b1cf0 (patch)
tree0b1e4779aa633b397e87f50e465542c8f56d7ea7
parent83d57635bc7b8f837add26322da04e3d93da2c55 (diff)
winsys/svga: Rework buffer allocation to make it more robust v2.
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 <thellstrom@vmware.com> Reviewed-by: José Fonseca <jfonseca@vmware.com> Reviewed-by: Jakob Bornecrantz <jakob@vmware.com>
-rw-r--r--src/gallium/winsys/svga/drm/vmw_screen.h8
-rw-r--r--src/gallium/winsys/svga/drm/vmw_screen_pools.c56
-rw-r--r--src/gallium/winsys/svga/drm/vmw_screen_svga.c10
3 files changed, 57 insertions, 17 deletions
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);