vmware/core: Update for pipebuffer changes.
authorJosé Fonseca <jfonseca@vmware.com>
Fri, 22 Jan 2010 05:18:25 +0000 (21:18 -0800)
committerMichel Dänzer <daenzer@vmware.com>
Fri, 22 Jan 2010 08:41:52 +0000 (09:41 +0100)
In particular, delay patching GMR relocations until the buffers are
validated, since the buffers relative offset can only be established then.

src/gallium/winsys/drm/vmware/core/vmw_context.c
src/gallium/winsys/drm/vmware/core/vmw_screen_pools.c

index 87a3df923fc26896f545e0696f203333c7e180a9..b5fd4f5a6a17aa251e304b231fa8774eb128bb33 100644 (file)
 
 #define VMW_COMMAND_SIZE (64*1024)
 #define VMW_SURFACE_RELOCS (1024)
+#define VMW_REGION_RELOCS (512)
 
 #define VMW_MUST_FLUSH_STACK 8
 
+struct vmw_region_relocation
+{
+   struct SVGAGuestPtr *where;
+   struct pb_buffer *buffer;
+   /* TODO: put offset info inside where */
+   uint32 offset;
+};
+
 struct vmw_svga_winsys_context
 {
    struct svga_winsys_context base;
@@ -69,6 +78,14 @@ struct vmw_svga_winsys_context
       uint32_t staged;
       uint32_t reserved;
    } surface;
+   
+   struct {
+      struct vmw_region_relocation relocs[VMW_REGION_RELOCS];
+      uint32_t size;
+      uint32_t used;
+      uint32_t staged;
+      uint32_t reserved;
+   } region;
 
    struct pb_validate *validate;
 
@@ -109,6 +126,19 @@ vmw_swc_flush(struct svga_winsys_context *swc,
    ret = pb_validate_validate(vswc->validate);
    assert(ret == PIPE_OK);
    if(ret == PIPE_OK) {
+   
+      /* Apply relocations */
+      for(i = 0; i < vswc->region.used; ++i) {
+         struct vmw_region_relocation *reloc = &vswc->region.relocs[i];
+         struct SVGAGuestPtr ptr;
+
+         if(!vmw_gmr_bufmgr_region_ptr(reloc->buffer, &ptr))
+            assert(0);
+
+         ptr.offset += reloc->offset;
+
+         *reloc->where = ptr;
+      }
 
       if (vswc->command.used)
          vmw_ioctl_command(vswc->vws,
@@ -134,6 +164,13 @@ vmw_swc_flush(struct svga_winsys_context *swc,
    vswc->surface.used = 0;
    vswc->surface.reserved = 0;
 
+   for(i = 0; i < vswc->region.used + vswc->region.staged; ++i) {
+      pb_reference(&vswc->region.relocs[i].buffer, NULL);
+   }
+
+   vswc->region.used = 0;
+   vswc->region.reserved = 0;
+
 #ifdef DEBUG
    vswc->must_flush = FALSE;
 #endif
@@ -168,7 +205,8 @@ vmw_swc_reserve(struct svga_winsys_context *swc,
 
    if(vswc->preemptive_flush ||
       vswc->command.used + nr_bytes > vswc->command.size ||
-      vswc->surface.used + nr_relocs > vswc->surface.size) {
+      vswc->surface.used + nr_relocs > vswc->surface.size ||
+      vswc->region.used + nr_relocs > vswc->region.size) {
 #ifdef DEBUG
       vswc->must_flush = TRUE;
       debug_backtrace_capture(vswc->must_flush_stack, 1,
@@ -179,11 +217,14 @@ vmw_swc_reserve(struct svga_winsys_context *swc,
 
    assert(vswc->command.used + nr_bytes <= vswc->command.size);
    assert(vswc->surface.used + nr_relocs <= vswc->surface.size);
-
+   assert(vswc->region.used + nr_relocs <= vswc->region.size);
+   
    vswc->command.reserved = nr_bytes;
    vswc->surface.reserved = nr_relocs;
    vswc->surface.staged = 0;
-
+   vswc->region.reserved = nr_relocs;
+   vswc->region.staged = 0;
+   
    return vswc->command.buffer + vswc->command.used;
 }
 
@@ -222,18 +263,19 @@ vmw_swc_region_relocation(struct svga_winsys_context *swc,
                           unsigned flags)
 {
    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
-   struct SVGAGuestPtr ptr;
-   struct pb_buffer *buf = vmw_pb_buffer(buffer);
+   struct vmw_region_relocation *reloc;
    enum pipe_error ret;
+   
+   assert(vswc->region.staged < vswc->region.reserved);
 
-   if(!vmw_gmr_bufmgr_region_ptr(buf, &ptr))
-      assert(0);
+   reloc = &vswc->region.relocs[vswc->region.used + vswc->region.staged];
+   reloc->where = where;
+   pb_reference(&reloc->buffer, vmw_pb_buffer(buffer));
+   reloc->offset = offset;
 
-   ptr.offset += offset;
+   ++vswc->region.staged;
 
-   *where = ptr;
-
-   ret = pb_validate_add_buffer(vswc->validate, buf, flags);
+   ret = pb_validate_add_buffer(vswc->validate, reloc->buffer, flags);
    /* TODO: Update pipebuffer to reserve buffers and not fail here */
    assert(ret == PIPE_OK);
 
@@ -253,7 +295,7 @@ vmw_swc_region_relocation(struct svga_winsys_context *swc,
     * SVGA virtual device it's not a performance issue since flushing commands
     * to the FIFO won't cause flushing in the host.
     */
-   vswc->seen_regions += buf->base.size;
+   vswc->seen_regions += reloc->buffer->base.size;
    if(vswc->seen_regions >= VMW_GMR_POOL_SIZE/2)
       vswc->preemptive_flush = TRUE;
 }
@@ -274,6 +316,12 @@ vmw_swc_commit(struct svga_winsys_context *swc)
    vswc->surface.used += vswc->surface.staged;
    vswc->surface.staged = 0;
    vswc->surface.reserved = 0;
+
+   assert(vswc->region.staged <= vswc->region.reserved);
+   assert(vswc->region.used + vswc->region.staged <= vswc->region.size);
+   vswc->region.used += vswc->region.staged;
+   vswc->region.staged = 0;
+   vswc->region.reserved = 0;
 }
 
 
@@ -282,6 +330,11 @@ vmw_swc_destroy(struct svga_winsys_context *swc)
 {
    struct vmw_svga_winsys_context *vswc = vmw_svga_winsys_context(swc);
    unsigned i;
+
+   for(i = 0; i < vswc->region.used; ++i) {
+      pb_reference(&vswc->region.relocs[i].buffer, NULL);
+   }
+
    for(i = 0; i < vswc->surface.used; ++i) {
       p_atomic_dec(&vswc->surface.handles[i]->validated);
       vmw_svga_winsys_surface_reference(&vswc->surface.handles[i], NULL);
@@ -315,6 +368,7 @@ vmw_svga_winsys_context_create(struct svga_winsys_screen *sws)
 
    vswc->command.size = VMW_COMMAND_SIZE;
    vswc->surface.size = VMW_SURFACE_RELOCS;
+   vswc->region.size = VMW_REGION_RELOCS;
 
    vswc->validate = pb_validate_create();
    if(!vswc->validate) {
index 78cfa78691396d4426ad32f9750060cb15d289f6..b9823d7857502fb50a3e47093877549955920672 100644 (file)
@@ -58,11 +58,27 @@ vmw_pools_init(struct vmw_winsys_screen *vws)
    if(!vws->pools.gmr_mm)
       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.
+    */
    vws->pools.gmr_fenced = fenced_bufmgr_create(
       vws->pools.gmr_mm,
       vmw_fence_ops_create(vws),
-      0,
-      0);
+      VMW_GMR_POOL_SIZE/2,
+      ~0);
 
 #ifdef DEBUG
    vws->pools.gmr_fenced = pb_debug_manager_create(vws->pools.gmr_fenced,