winsys/svga: fix display corruption after surface_init
[mesa.git] / src / gallium / winsys / svga / drm / vmw_surface.c
index 6c0ad3bbf1912ea04e358aef4a5002824ccb2337..25c6d320c7408447ce687afe5265aa071098079f 100644 (file)
 #include "vmw_context.h"
 #include "pipebuffer/pb_bufmgr.h"
 
+void
+vmw_svga_winsys_surface_init(struct svga_winsys_screen *sws,
+                             struct svga_winsys_surface *srf,
+                             unsigned surf_size, SVGA3dSurfaceAllFlags flags)
+{
+   struct vmw_svga_winsys_surface *vsrf = vmw_svga_winsys_surface(srf);
+   void *data = NULL;
+   struct pb_buffer *pb_buf;
+   uint32_t pb_flags;
+   struct vmw_winsys_screen *vws = vsrf->screen;
+   pb_flags = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
+
+   struct pb_manager *provider;
+   struct pb_desc desc;
+
+   mtx_lock(&vsrf->mutex);
+   data = vmw_svga_winsys_buffer_map(&vws->base, vsrf->buf, pb_flags);
+   if (data)
+      goto out_mapped;
+
+   provider = vws->pools.mob_fenced;
+   memset(&desc, 0, sizeof(desc));
+   desc.alignment = 4096;
+   pb_buf = provider->create_buffer(provider, vsrf->size, &desc);
+   if (pb_buf != NULL) {
+      struct svga_winsys_buffer *vbuf =
+         vmw_svga_winsys_buffer_wrap(pb_buf);
+
+      data = vmw_svga_winsys_buffer_map(&vws->base, vbuf, pb_flags);
+      if (data) {
+         vsrf->rebind = TRUE;
+         if (vsrf->buf)
+            vmw_svga_winsys_buffer_destroy(&vws->base, vsrf->buf);
+         vsrf->buf = vbuf;
+         goto out_mapped;
+      } else {
+         vmw_svga_winsys_buffer_destroy(&vws->base, vbuf);
+         goto out_unlock;
+      }
+   }
+   else {
+      /* Cannot create a buffer, just unlock */
+      goto out_unlock;
+   }
+
+out_mapped:
+   mtx_unlock(&vsrf->mutex);
 
+   if (data) {
+      if (flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT) {
+         memset(data, 0, surf_size + sizeof(SVGA3dDXSOState));
+      }
+      else {
+         memset(data, 0, surf_size);
+      }
+   }
+
+   mtx_lock(&vsrf->mutex);
+   vmw_svga_winsys_buffer_unmap(&vsrf->screen->base, vsrf->buf);
+out_unlock:
+   mtx_unlock(&vsrf->mutex);
+}
+
 void *
 vmw_svga_winsys_surface_map(struct svga_winsys_context *swc,
                             struct svga_winsys_surface *srf,
-                            unsigned flags, boolean *retry)
+                            unsigned flags, boolean *retry,
+                            boolean *rebind)
 {
    struct vmw_svga_winsys_surface *vsrf = vmw_svga_winsys_surface(srf);
    void *data = NULL;
    struct pb_buffer *pb_buf;
    uint32_t pb_flags;
    struct vmw_winsys_screen *vws = vsrf->screen;
-   
+
    *retry = FALSE;
+   *rebind = FALSE;
    assert((flags & (PIPE_TRANSFER_READ | PIPE_TRANSFER_WRITE)) != 0);
-   pipe_mutex_lock(vsrf->mutex);
+   mtx_lock(&vsrf->mutex);
 
    if (vsrf->mapcount) {
-      /*
-       * Only allow multiple readers to map.
-       */
-      if ((flags & PIPE_TRANSFER_WRITE) ||
-          (vsrf->map_mode & PIPE_TRANSFER_WRITE))
-         goto out_unlock;
-      
-      data = vsrf->data;
-      goto out_mapped;
+      /* Other mappers will get confused if we discard. */
+      flags &= ~PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
    }
 
    vsrf->rebind = FALSE;
@@ -89,7 +148,8 @@ vmw_svga_winsys_surface_map(struct svga_winsys_context *swc,
       goto out_unlock;
    }
 
-   pb_flags = flags & (PIPE_TRANSFER_READ_WRITE | PIPE_TRANSFER_UNSYNCHRONIZED);
+   pb_flags = flags & (PIPE_TRANSFER_READ_WRITE | PIPE_TRANSFER_UNSYNCHRONIZED |
+      PIPE_TRANSFER_PERSISTENT);
 
    if (flags & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
       struct pb_manager *provider;
@@ -127,6 +187,12 @@ vmw_svga_winsys_surface_map(struct svga_winsys_context *swc,
             if (vsrf->buf)
                vmw_svga_winsys_buffer_destroy(&vws->base, vsrf->buf);
             vsrf->buf = vbuf;
+
+            /* Rebind persistent maps immediately */
+            if (flags & PIPE_TRANSFER_PERSISTENT) {
+               *rebind = TRUE;
+               vsrf->rebind = FALSE;
+            }
             goto out_mapped;
          } else
             vmw_svga_winsys_buffer_destroy(&vws->base, vbuf);
@@ -154,7 +220,7 @@ out_mapped:
    vsrf->data = data;
    vsrf->map_mode = flags & (PIPE_TRANSFER_READ | PIPE_TRANSFER_WRITE);
 out_unlock:
-   pipe_mutex_unlock(vsrf->mutex);
+   mtx_unlock(&vsrf->mutex);
    return data;
 }
 
@@ -165,13 +231,15 @@ vmw_svga_winsys_surface_unmap(struct svga_winsys_context *swc,
                               boolean *rebind)
 {
    struct vmw_svga_winsys_surface *vsrf = vmw_svga_winsys_surface(srf);
-   pipe_mutex_lock(vsrf->mutex);
+   mtx_lock(&vsrf->mutex);
    if (--vsrf->mapcount == 0) {
       *rebind = vsrf->rebind;
       vsrf->rebind = FALSE;
-      vmw_svga_winsys_buffer_unmap(&vsrf->screen->base, vsrf->buf);
+   } else {
+      *rebind = FALSE;
    }
-   pipe_mutex_unlock(vsrf->mutex);
+   vmw_svga_winsys_buffer_unmap(&vsrf->screen->base, vsrf->buf);
+   mtx_unlock(&vsrf->mutex);
 }
 
 void
@@ -199,7 +267,7 @@ vmw_svga_winsys_surface_reference(struct vmw_svga_winsys_surface **pdst,
       assert(p_atomic_read(&dst->validated) == 0);
       dst->sid = SVGA3D_INVALID_ID;
 #endif
-      pipe_mutex_destroy(dst->mutex);
+      mtx_destroy(&dst->mutex);
       FREE(dst);
    }