From 4471610749abec1c9b41676fc6df6fb507bbcf68 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20D=C3=B6singer?= <stefan@codeweavers.com>
Date: Fri, 12 Feb 2010 21:32:41 +0100
Subject: [PATCH 07/12] WineD3D: Implement manual buffer fencing

---
 dlls/wined3d/buffer.c          |   65 ++++++++++++++++++++++++++++++++++++---
 dlls/wined3d/device.c          |   10 +++++-
 dlls/wined3d/drawprim.c        |    5 +++
 dlls/wined3d/wined3d_private.h |    3 ++
 4 files changed, 77 insertions(+), 6 deletions(-)

diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c
index aa90fd3..7d20e5c 100644
--- a/dlls/wined3d/buffer.c
+++ b/dlls/wined3d/buffer.c
@@ -108,6 +108,11 @@ static void delete_gl_buffer(struct wined3d_buffer *This)
     LEAVE_GL();
     This->buffer_object = 0;
 
+    if(This->query)
+    {
+        wined3d_event_query_destroy(This->query);
+        This->query = NULL;
+    }
     This->flags &= ~WINED3D_BUFFER_APPLESYNC;
 }
 
@@ -1098,23 +1103,68 @@ static GLbitfield buffer_gl_map_flags(DWORD d3d_flags)
     return ret;
 }
 
-/* The caller provides a context and GL locking and binds the buffer */
-static void buffer_sync_apple(struct wined3d_buffer *This, DWORD flags)
+/* The caller provides a context and binds the buffer */
+static void buffer_sync_apple(struct wined3d_buffer *This, DWORD flags, const struct wined3d_gl_info *gl_info)
 {
+    enum wined3d_event_query_result ret;
+
     /* No fencing needs to be done if the app promises not to overwrite
      * existing data */
     if(flags & WINED3DLOCK_NOOVERWRITE) return;
     if(flags & WINED3DLOCK_DISCARD)
     {
+        ENTER_GL();
         GL_EXTCALL(glBufferDataARB(This->buffer_type_hint, This->resource.size, NULL, This->buffer_object_usage));
         checkGLcall("glBufferDataARB\n");
+        LEAVE_GL();
+        return;
+    }
+
+    if(!This->query)
+    {
+        HRESULT hr;
+        TRACE("Creating event query for buffer %p\n", This);
+
+        hr = wined3d_event_query_init(gl_info, &This->query);
+        if(FAILED(hr))
+        {
+            ERR("Failed to create an event query, dropping async buffer locks\n");
+            goto drop_query;
+        }
+        /* Since we don't know about old draws a glFinish is needed once */
+        wglFinish();
         return;
     }
+    TRACE("Synchronizing buffer %p\n", This);
+    ret = wined3d_event_query_finish(This->query, This->resource.device);
+    switch(ret)
+    {
+        case WINED3D_EVENT_QUERY_NOT_STARTED:
+        case WINED3D_EVENT_QUERY_OK:
+            /* All done */
+            return;
+
+        case WINED3D_EVENT_QUERY_WRONG_THREAD:
+            WARN("Cannot synchronize buffer lock due to a thread conflict\n");
+            goto drop_query;
+
+        default:
+            ERR("wined3d_event_query_finish returned %u, dropping async buffer locks\n", ret);
+            goto drop_query;
+    }
+
+drop_query:
+    if(This->query)
+    {
+        wined3d_event_query_destroy(This->query);
+        This->query = NULL;
+    }
 
-    /* Drop the unserialized updates for now */
-    FIXME("Implement fences for unserialized buffers\n");
+    wglFinish();
+    ENTER_GL();
     GL_EXTCALL(glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_TRUE));
     checkGLcall("glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_TRUE)");
+    LEAVE_GL();
     This->flags &= ~WINED3D_BUFFER_APPLESYNC;
 }
 
@@ -1159,7 +1209,12 @@ static HRESULT STDMETHODCALLTYPE buffer_Map(IWineD3DBuffer *iface, UINT offset,
             }
             else
             {
-                if(This->flags & WINED3D_BUFFER_APPLESYNC) buffer_sync_apple(This, flags);
+                if(This->flags & WINED3D_BUFFER_APPLESYNC)
+                {
+                    LEAVE_GL();
+                    buffer_sync_apple(This, flags, gl_info);
+                    ENTER_GL();
+                }
                 This->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(This->buffer_type_hint, GL_READ_WRITE_ARB));
             }
             LEAVE_GL();
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index f10348c..a1b881e 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -317,7 +317,15 @@ void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
     for (i = 0; i < stream_count; ++i)
     {
         IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
-        if (vb) IWineD3DBuffer_PreLoad(vb);
+        if (vb)
+        {
+            struct wined3d_event_query *query = ((struct wined3d_buffer *) vb)->query;
+            IWineD3DBuffer_PreLoad(vb);
+            if(query)
+            {
+                This->buffer_queries[This->num_buffer_queries++] = query;
+            }
+        }
     }
 }
 
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index b29d012..3a4738c 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -695,6 +695,11 @@ void drawPrimitive(IWineD3DDevice *iface, UINT index_count, UINT StartIdx, UINT
 
     context_release(context);
 
+    for(i = 0; i < This->num_buffer_queries; i++)
+    {
+        wined3d_event_query_issue(This->buffer_queries[i], This);
+    }
+
     TRACE("Done all gl drawing\n");
 
     /* Diagnostics */
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 8bc6cb6..47ea683 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1618,6 +1618,8 @@ struct IWineD3DDeviceImpl
     /* Stream source management */
     struct wined3d_stream_info strided_streams;
     const WineDirect3DVertexStridedData *up_strided;
+    struct wined3d_event_query *buffer_queries[MAX_ATTRIBS];
+    unsigned int num_buffer_queries;
 
     /* Context management */
     struct wined3d_context **contexts;
@@ -2421,6 +2423,7 @@ struct wined3d_buffer
     LONG lock_count;
     struct wined3d_map_range *maps;
     ULONG maps_size, modified_areas;
+    struct wined3d_event_query *query;
 
     /* conversion stuff */
     UINT decl_change_count, full_conversion_count;
-- 
1.6.4.4

