From 1b60efc3227a03c5a25a0b1a3abea37b5690e987 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20D=C3=B6singer?= <stefan@codeweavers.com>
Date: Sun, 16 Mar 2014 14:13:42 +0100
Subject: wined3d: Send getdc and releasedc through the command stream.

As with the palette patch just a cheap workaround for a context
activation bug I just regret that I didn't describe more verbously
earlier. I forgot what it was about exactly and can't be bothered to
investigate atm.
---
 dlls/wined3d/cs.c              | 58 ++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/surface.c         | 56 +++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/texture.c         | 60 +++---------------------------------------
 dlls/wined3d/wined3d_private.h |  4 +++
 4 files changed, 121 insertions(+), 57 deletions(-)

diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 042ffce..6656ce1 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -89,6 +89,8 @@ enum wined3d_cs_op
     WINED3D_CS_OP_CREATE_DUMMY_TEXTURES,
     WINED3D_CS_OP_CREATE_SWAPCHAIN_CONTEXT,
     WINED3D_CS_OP_DELETE_GL_CONTEXTS,
+    WINED3D_CS_OP_GETDC,
+    WINED3D_CS_OP_RELEASEDC,
     WINED3D_CS_OP_STOP,
 };
 
@@ -526,6 +528,18 @@ struct wined3d_cs_delete_gl_contexts
     struct wined3d_swapchain *swapchain;
 };
 
+struct wined3d_cs_getdc
+{
+    enum wined3d_cs_op opcode;
+    struct wined3d_surface *surface;
+};
+
+struct wined3d_cs_releasedc
+{
+    enum wined3d_cs_op opcode;
+    struct wined3d_surface *surface;
+};
+
 static void wined3d_cs_mt_submit(struct wined3d_cs *cs, size_t size)
 {
     LONG new_val = (cs->queue.head + size) & (WINED3D_CS_QUEUE_SIZE - 1);
@@ -2594,6 +2608,48 @@ void wined3d_cs_emit_delete_opengl_contexts(struct wined3d_cs *cs, struct wined3
     cs->ops->finish(cs);
 }
 
+static UINT wined3d_cs_exec_getdc(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_getdc *op = data;
+
+    wined3d_surface_getdc_cs(op->surface);
+
+    return sizeof(*op);
+}
+
+void wined3d_cs_emit_getdc(struct wined3d_cs *cs, struct wined3d_surface *surface)
+{
+    struct wined3d_cs_getdc *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_GETDC;
+    op->surface = surface;
+
+    cs->ops->submit(cs, sizeof(*op));
+    cs->ops->finish(cs);
+}
+
+static UINT wined3d_cs_exec_releasedc(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_releasedc *op = data;
+
+    wined3d_surface_releasedc_cs(op->surface);
+
+    return sizeof(*op);
+}
+
+void wined3d_cs_emit_releasedc(struct wined3d_cs *cs, struct wined3d_surface *surface)
+{
+    struct wined3d_cs_releasedc *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_RELEASEDC;
+    op->surface = surface;
+
+    cs->ops->submit(cs, sizeof(*op));
+    cs->ops->finish(cs);
+}
+
 static UINT (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void *data) =
 {
     /* WINED3D_CS_OP_NOP                        */ wined3d_cs_exec_nop,
@@ -2661,6 +2717,8 @@ static UINT (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void
     /* WINED3D_CS_OP_CREATE_DUMMY_TEXTURES      */ wined3d_cs_exec_create_dummy_textures,
     /* WINED3D_CS_OP_CREATE_SWAPCHAIN_CONTEXT   */ wined3d_cs_exec_create_swapchain_context,
     /* WINED3D_CS_OP_DELETE_GL_CONTEXTS         */ wined3d_cs_exec_delete_gl_contexts,
+    /* WINED3D_CS_OP_GETDC                      */ wined3d_cs_exec_getdc,
+    /* WINED3D_CS_OP_RELEASEDC                  */ wined3d_cs_exec_releasedc,
 };
 
 static inline void *_wined3d_cs_mt_require_space(struct wined3d_cs *cs, size_t size, BOOL prio)
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index fe1670f..9ec4733 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -2349,6 +2349,62 @@ HRESULT wined3d_surface_map(struct wined3d_surface *surface, struct wined3d_map_
     return wined3d_resource_map(&surface->resource, map_desc, box, flags);
 }
 
+void wined3d_surface_getdc_cs(struct wined3d_surface *surface)
+{
+    HRESULT hr;
+    struct wined3d_device *device = surface->resource.device;
+    struct wined3d_context *context = NULL;
+
+    if (device->d3d_initialized)
+        context = context_acquire(device, NULL);
+
+    /* Create a DIB section if there isn't a dc yet. */
+    if (!surface->hDC)
+    {
+        if (FAILED(hr = surface_create_dib_section(surface)))
+        {
+            if (context)
+                context_release(context);
+            return;
+        }
+        if (!(surface->resource.map_binding == WINED3D_LOCATION_USER_MEMORY
+                || surface->container->flags & WINED3D_TEXTURE_PIN_SYSMEM
+                || surface->resource.buffer))
+            surface->resource.map_binding = WINED3D_LOCATION_DIB;
+    }
+
+    wined3d_resource_load_location(&surface->resource, context, WINED3D_LOCATION_DIB);
+    wined3d_resource_invalidate_location(&surface->resource, ~WINED3D_LOCATION_DIB);
+
+    if (context)
+        context_release(context);
+}
+
+void wined3d_surface_releasedc_cs(struct wined3d_surface *surface)
+{
+    if (surface->resource.map_binding == WINED3D_LOCATION_USER_MEMORY || (surface->container->flags & WINED3D_TEXTURE_PIN_SYSMEM
+            && surface->resource.map_binding != WINED3D_LOCATION_DIB))
+    {
+        /* The game Salammbo modifies the surface contents without mapping the surface between
+         * a GetDC/ReleaseDC operation and flipping the surface. If the DIB remains the active
+         * copy and is copied to the screen, this update, which draws the mouse pointer, is lost.
+         * Do not only copy the DIB to the map location, but also make sure the map location is
+         * copied back to the DIB in the next getdc call.
+         *
+         * The same consideration applies to user memory surfaces. */
+        struct wined3d_device *device = surface->resource.device;
+        struct wined3d_context *context = NULL;
+
+        if (device->d3d_initialized)
+            context = context_acquire(device, NULL);
+
+        wined3d_resource_load_location(&surface->resource, context, surface->resource.map_binding);
+        wined3d_resource_invalidate_location(&surface->resource, WINED3D_LOCATION_DIB);
+        if (context)
+            context_release(context);
+    }
+}
+
 static void read_from_framebuffer(struct wined3d_surface *surface,
         struct wined3d_context *old_ctx, DWORD dst_location)
 {
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index 1244c36..965f0d7 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -1606,10 +1606,8 @@ HRESULT CDECL wined3d_texture_create(struct wined3d_device *device, const struct
 HRESULT CDECL wined3d_texture_get_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC *dc)
 {
     struct wined3d_device *device = texture->resource.device;
-    struct wined3d_context *context = NULL;
     struct wined3d_resource *sub_resource;
     struct wined3d_surface *surface;
-    HRESULT hr;
 
     TRACE("texture %p, sub_resource_idx %u, dc %p.\n", texture, sub_resource_idx, dc);
 
@@ -1630,14 +1628,6 @@ HRESULT CDECL wined3d_texture_get_dc(struct wined3d_texture *texture, unsigned i
         return WINED3DERR_INVALIDCALL;
     }
 
-    if (wined3d_settings.cs_multithreaded)
-    {
-        struct wined3d_device *device = surface->resource.device;
-        FIXME("Waiting for cs.\n");
-        wined3d_cs_emit_glfinish(device->cs);
-        device->cs->ops->finish(device->cs);
-    }
-
     /* Give more detailed info for ddraw. */
     if (surface->flags & SFLAG_DCINUSE)
         return WINEDDERR_DCALREADYCREATED;
@@ -1646,43 +1636,18 @@ HRESULT CDECL wined3d_texture_get_dc(struct wined3d_texture *texture, unsigned i
     if (surface->resource.map_count)
         return WINED3DERR_INVALIDCALL;
 
-    if (device->d3d_initialized)
-        context = context_acquire(device, NULL);
-
-    /* Create a DIB section if there isn't a dc yet. */
-    if (!surface->hDC)
-    {
-        if (FAILED(hr = surface_create_dib_section(surface)))
-        {
-            if (context)
-                context_release(context);
-             return WINED3DERR_INVALIDCALL;
-        }
-        if (!(surface->resource.map_binding == WINED3D_LOCATION_USER_MEMORY
-                || surface->container->flags & WINED3D_TEXTURE_PIN_SYSMEM
-                || surface->resource.buffer))
-            surface->resource.map_binding = WINED3D_LOCATION_DIB;
-    }
-
-    wined3d_resource_load_location(&surface->resource, context, WINED3D_LOCATION_DIB);
-    wined3d_resource_invalidate_location(&surface->resource, ~WINED3D_LOCATION_DIB);
-
-    if (context)
-        context_release(context);
-
     surface->flags |= SFLAG_DCINUSE;
     surface->resource.map_count++;
-
+    wined3d_cs_emit_getdc(device->cs, surface);
     *dc = surface->hDC;
     TRACE("Returning dc %p.\n", *dc);
 
-    return WINED3D_OK;
+    return *dc ? WINED3D_OK : WINED3DERR_INVALIDCALL;
 }
 
 HRESULT CDECL wined3d_texture_release_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC dc)
 {
     struct wined3d_device *device = texture->resource.device;
-    struct wined3d_context *context = NULL;
     struct wined3d_resource *sub_resource;
     struct wined3d_surface *surface;
 
@@ -1712,26 +1677,7 @@ HRESULT CDECL wined3d_texture_release_dc(struct wined3d_texture *texture, unsign
     surface->resource.map_count--;
     surface->flags &= ~SFLAG_DCINUSE;
 
-    if (surface->resource.map_binding == WINED3D_LOCATION_USER_MEMORY
-            || (surface->container->flags & WINED3D_TEXTURE_PIN_SYSMEM
-            && surface->resource.map_binding != WINED3D_LOCATION_DIB))
-    {
-        /* The game Salammbo modifies the surface contents without mapping the surface between
-         * a GetDC/ReleaseDC operation and flipping the surface. If the DIB remains the active
-         * copy and is copied to the screen, this update, which draws the mouse pointer, is lost.
-         * Do not only copy the DIB to the map location, but also make sure the map location is
-         * copied back to the DIB in the next getdc call.
-         *
-         * The same consideration applies to user memory surfaces. */
-
-        if (device->d3d_initialized)
-            context = context_acquire(device, NULL);
-
-        wined3d_resource_load_location(&surface->resource, context, surface->resource.map_binding);
-        wined3d_resource_invalidate_location(&surface->resource, WINED3D_LOCATION_DIB);
-        if (context)
-            context_release(context);
-    }
+    wined3d_cs_emit_releasedc(device->cs, surface);
 
     return WINED3D_OK;
 }
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index d7142da..e1988f2 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2666,6 +2666,8 @@ void surface_blt_ugly(struct wined3d_surface *dst_surface, const RECT *dst_rect_
         struct wined3d_surface *src_surface, const RECT *src_rect_in, DWORD flags,
         const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter) DECLSPEC_HIDDEN;
 void wined3d_surface_cleanup_cs(struct wined3d_surface *surface) DECLSPEC_HIDDEN;
+void wined3d_surface_getdc_cs(struct wined3d_surface *surface) DECLSPEC_HIDDEN;
+void wined3d_surface_releasedc_cs(struct wined3d_surface *surface) DECLSPEC_HIDDEN;
 
 void draw_textured_quad(const struct wined3d_surface *src_surface, struct wined3d_context *context,
         const RECT *src_rect, const RECT *dst_rect, enum wined3d_texture_filter_type filter) DECLSPEC_HIDDEN;
@@ -2936,6 +2938,8 @@ HRESULT wined3d_cs_emit_create_swapchain_context(struct wined3d_cs *cs,
         struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_delete_opengl_contexts(struct wined3d_cs *cs,
         struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
+void wined3d_cs_emit_getdc(struct wined3d_cs *cs, struct wined3d_surface *surface) DECLSPEC_HIDDEN;
+void wined3d_cs_emit_releasedc(struct wined3d_cs *cs, struct wined3d_surface *surface) DECLSPEC_HIDDEN;
 
 /* Direct3D terminology with little modifications. We do not have an issued state
  * because only the driver knows about it, but we have a created state because d3d
-- 
2.7.1

