From: Wine Staging Team <webmaster@fds-team.de>
Subject: Autogenerated #ifdef patch for wined3d-CSMT_Main.

diff --git a/dlls/d3d8/tests/visual.c b/dlls/d3d8/tests/visual.c
--- a/dlls/d3d8/tests/visual.c
+++ b/dlls/d3d8/tests/visual.c
@@ -5480,7 +5480,11 @@
     fill_surface(surface_managed, 0x0000ff00, D3DLOCK_NO_DIRTY_UPDATE);
     add_dirty_rect_test_draw(device);
     color = getPixelColor(device, 320, 240);
+#if defined(STAGING_CSMT)
     todo_wine ok(color_match(color, 0x00ff0000, 1),
+#else  /* STAGING_CSMT */
+    ok(color_match(color, 0x00ff0000, 1),
+#endif /* STAGING_CSMT */
             "Expected color 0x00ff0000, got 0x%08x.\n", color);
     hr = IDirect3DDevice8_Present(device, NULL, NULL, NULL, NULL);
     ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr);
diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
--- a/dlls/d3d9/tests/visual.c
+++ b/dlls/d3d9/tests/visual.c
@@ -1339,7 +1339,11 @@
          * result on Wine.
          * {D3DFMT_YUY2,     "D3DFMT_YUY2",     BLOCKS,                              0},
          * {D3DFMT_UYVY,     "D3DFMT_UYVY",     BLOCKS,                              0}, */
+#if defined(STAGING_CSMT)
         {D3DFMT_DXT1,     "D3DFMT_DXT1",     BLOCKS,                              0},
+#else  /* STAGING_CSMT */
+        {D3DFMT_DXT1,     "D3DFMT_DXT1",     BLOCKS | TODO_FILL_RETURN,           0},
+#endif /* STAGING_CSMT */
         /* Vendor-specific formats like ATI2N are a non-issue here since they're not
          * supported as offscreen plain surfaces and do not support D3DUSAGE_RENDERTARGET
          * when created as texture. */
@@ -17630,7 +17634,11 @@
     fill_surface(surface_managed, 0x0000ff00, D3DLOCK_NO_DIRTY_UPDATE);
     add_dirty_rect_test_draw(device);
     color = getPixelColor(device, 320, 240);
+#if defined(STAGING_CSMT)
     todo_wine ok(color_match(color, 0x00ff0000, 1),
+#else  /* STAGING_CSMT */
+    ok(color_match(color, 0x00ff0000, 1),
+#endif /* STAGING_CSMT */
             "Expected color 0x00ff0000, got 0x%08x.\n", color);
     hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
     ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr);
diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -684,7 +684,11 @@
     {
         const struct wined3d_shader *pshader = state->shader[WINED3D_SHADER_TYPE_PIXEL];
         const struct arb_ps_compiled_shader *gl_shader = priv->compiled_fprog;
+#if defined(STAGING_CSMT)
         UINT rt_height = state->fb.render_targets[0]->height;
+#else  /* STAGING_CSMT */
+        UINT rt_height = state->fb->render_targets[0]->height;
+#endif /* STAGING_CSMT */
 
         /* Load DirectX 9 float constants for pixel shader */
         priv->highest_dirty_ps_const = shader_arb_load_constantsF(pshader, gl_info, GL_FRAGMENT_PROGRAM_ARB,
@@ -4712,7 +4716,11 @@
         }
         else
         {
+#if defined(STAGING_CSMT)
             UINT rt_height = state->fb.render_targets[0]->height;
+#else  /* STAGING_CSMT */
+            UINT rt_height = state->fb->render_targets[0]->height;
+#endif /* STAGING_CSMT */
             shader_arb_ps_local_constants(compiled, context, state, rt_height);
         }
 
@@ -7855,7 +7863,11 @@
 
     /* Now load the surface */
     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
+#if defined(STAGING_CSMT)
             && (src_surface->resource.locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_DRAWABLE))
+#else  /* STAGING_CSMT */
+            && (src_surface->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_DRAWABLE))
+#endif /* STAGING_CSMT */
             == WINED3D_LOCATION_DRAWABLE
             && !wined3d_resource_is_offscreen(&src_surface->container->resource))
     {
@@ -7893,6 +7905,7 @@
     /* Leave the opengl state valid for blitting */
     arbfp_blit_unset(context->gl_info);
 
+#if defined(STAGING_CSMT)
     if (wined3d_settings.cs_multithreaded)
         context->gl_info->gl_ops.gl.p_glFinish();
     else if (wined3d_settings.strict_draw_ordering
@@ -7904,6 +7917,17 @@
 
     wined3d_resource_validate_location(&dst_surface->resource, dst_surface->container->resource.draw_binding);
     wined3d_resource_invalidate_location(&dst_surface->resource, ~dst_surface->container->resource.draw_binding);
+#else  /* STAGING_CSMT */
+    if (wined3d_settings.strict_draw_ordering
+            || (dst_surface->container->swapchain
+            && (dst_surface->container->swapchain->front_buffer == dst_surface->container)))
+        context->gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
+
+    context_release(context);
+
+    surface_validate_location(dst_surface, dst_surface->container->resource.draw_binding);
+    surface_invalidate_location(dst_surface, ~dst_surface->container->resource.draw_binding);
+#endif /* STAGING_CSMT */
 }
 
 static HRESULT arbfp_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c
--- a/dlls/wined3d/buffer.c
+++ b/dlls/wined3d/buffer.c
@@ -32,6 +32,7 @@
 #define WINED3D_BUFFER_HASDESC      0x01    /* A vertex description has been found. */
 #define WINED3D_BUFFER_CREATEBO     0x02    /* Create a buffer object for this buffer. */
 #define WINED3D_BUFFER_DOUBLEBUFFER 0x04    /* Keep both a buffer object and a system memory copy for this buffer. */
+#if defined(STAGING_CSMT)
 #define WINED3D_BUFFER_DISCARD      0x08    /* The next PreLoad may discard the buffer contents. */
 #define WINED3D_BUFFER_SYNC         0x10    /* There has been at least one synchronized map since the last preload. */
 #define WINED3D_BUFFER_APPLESYNC    0x20    /* Using sync as in GL_APPLE_flush_buffer_range. */
@@ -42,6 +43,19 @@
 #define VB_RESETFULLCONVS     20      /* Reset full conversion counts after that number of draws */
 
 void buffer_invalidate_bo_range(struct wined3d_buffer *buffer, UINT offset, UINT size)
+#else  /* STAGING_CSMT */
+#define WINED3D_BUFFER_FLUSH        0x08    /* Manual unmap flushing. */
+#define WINED3D_BUFFER_DISCARD      0x10    /* A DISCARD lock has occurred since the last preload. */
+#define WINED3D_BUFFER_SYNC         0x20    /* There has been at least one synchronized map since the last preload. */
+#define WINED3D_BUFFER_APPLESYNC    0x40    /* Using sync as in GL_APPLE_flush_buffer_range. */
+
+#define VB_MAXDECLCHANGES     100     /* After that number of decl changes we stop converting */
+#define VB_RESETDECLCHANGE    1000    /* Reset the decl changecount after that number of draws */
+#define VB_MAXFULLCONVERSIONS 5       /* Number of full conversions before we stop converting */
+#define VB_RESETFULLCONVS     20      /* Reset full conversion counts after that number of draws */
+
+static void buffer_invalidate_bo_range(struct wined3d_buffer *buffer, UINT offset, UINT size)
+#endif /* STAGING_CSMT */
 {
     if (!offset && !size)
         goto invalidate_all;
@@ -117,7 +131,11 @@
 }
 
 /* Context activation is done by the caller. */
+#if defined(STAGING_CSMT)
 void buffer_create_buffer_object(struct wined3d_buffer *This, struct wined3d_context *context)
+#else  /* STAGING_CSMT */
+static void buffer_create_buffer_object(struct wined3d_buffer *This, struct wined3d_context *context)
+#endif /* STAGING_CSMT */
 {
     GLenum gl_usage = GL_STATIC_DRAW_ARB;
     GLenum error;
@@ -166,6 +184,10 @@
         {
             GL_EXTCALL(glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE));
             checkGLcall("glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE)");
+#if !defined(STAGING_CSMT)
+            This->flags |= WINED3D_BUFFER_FLUSH;
+
+#endif /* STAGING_CSMT */
             GL_EXTCALL(glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE));
             checkGLcall("glBufferParameteriAPPLE(This->buffer_type_hint, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE)");
             This->flags |= WINED3D_BUFFER_APPLESYNC;
@@ -191,10 +213,14 @@
     if (This->flags & WINED3D_BUFFER_DOUBLEBUFFER)
         buffer_invalidate_bo_range(This, 0, 0);
     else
+#if defined(STAGING_CSMT)
     {
         wined3d_resource_free_sysmem(&This->resource);
         This->resource.map_heap_memory = NULL;
     }
+#else  /* STAGING_CSMT */
+        wined3d_resource_free_sysmem(&This->resource);
+#endif /* STAGING_CSMT */
 
     return;
 
@@ -423,6 +449,7 @@
 {
     DWORD src_color = *dst_color;
 
+#if defined(STAGING_CSMT)
     /* Color conversion like in draw_strided_slow. watch out for little endianity
      * If we want that stuff to work on big endian machines too we have to consider more things
      *
@@ -431,6 +458,16 @@
      * 0x0000ff00: Green mask
      * 0x000000ff: Red mask
      */
+#else  /* STAGING_CSMT */
+    /* Color conversion like in drawStridedSlow. watch out for little endianity
+     * If we want that stuff to work on big endian machines too we have to consider more things
+     *
+     * 0xff000000: Alpha mask
+     * 0x00ff0000: Blue mask
+     * 0x0000ff00: Green mask
+     * 0x000000ff: Red mask
+     */
+#endif /* STAGING_CSMT */
     *dst_color = 0;
     *dst_color |= (src_color & 0xff00ff00u);         /* Alpha Green */
     *dst_color |= (src_color & 0x00ff0000u) >> 16;   /* Red */
@@ -457,8 +494,12 @@
     data->buffer_object = buffer->buffer_object;
     if (!buffer->buffer_object)
     {
+#if defined(STAGING_CSMT)
         if ((!buffer->resource.map_count || buffer->flags & WINED3D_BUFFER_DOUBLEBUFFER)
                 && buffer->flags & WINED3D_BUFFER_CREATEBO)
+#else  /* STAGING_CSMT */
+        if ((buffer->flags & WINED3D_BUFFER_CREATEBO) && !buffer->resource.map_count)
+#endif /* STAGING_CSMT */
         {
             buffer_create_buffer_object(buffer, context);
             buffer->flags &= ~WINED3D_BUFFER_CREATEBO;
@@ -497,7 +538,9 @@
 
     if (!wined3d_resource_allocate_sysmem(&This->resource))
         ERR("Failed to allocate system memory.\n");
+#if defined(STAGING_CSMT)
     This->resource.heap_memory = This->resource.map_heap_memory;
+#endif /* STAGING_CSMT */
 
     if (This->buffer_type_hint == GL_ELEMENT_ARRAY_BUFFER_ARB)
         context_invalidate_state(context, STATE_INDEXBUFFER);
@@ -545,6 +588,7 @@
     resource_unload(resource);
 }
 
+#if defined(STAGING_CSMT)
 void wined3d_buffer_cleanup_cs(struct wined3d_buffer *buffer)
 {
     struct wined3d_context *context;
@@ -577,6 +621,30 @@
 
         buffer->resource.parent_ops->wined3d_object_destroyed(buffer->resource.parent);
         wined3d_cs_emit_buffer_cleanup(device->cs, buffer);
+#else  /* STAGING_CSMT */
+ULONG CDECL wined3d_buffer_decref(struct wined3d_buffer *buffer)
+{
+    ULONG refcount = InterlockedDecrement(&buffer->resource.ref);
+    struct wined3d_context *context;
+
+    TRACE("%p decreasing refcount to %u.\n", buffer, refcount);
+
+    if (!refcount)
+    {
+        if (buffer->buffer_object)
+        {
+            context = context_acquire(buffer->resource.device, NULL);
+            delete_gl_buffer(buffer, context->gl_info);
+            context_release(context);
+
+            HeapFree(GetProcessHeap(), 0, buffer->conversion_map);
+        }
+
+        resource_cleanup(&buffer->resource);
+        buffer->resource.parent_ops->wined3d_object_destroyed(buffer->resource.parent);
+        HeapFree(GetProcessHeap(), 0, buffer->maps);
+        HeapFree(GetProcessHeap(), 0, buffer);
+#endif /* STAGING_CSMT */
     }
 
     return refcount;
@@ -661,6 +729,7 @@
 /* The caller provides a GL context */
 static void buffer_direct_upload(struct wined3d_buffer *This, const struct wined3d_gl_info *gl_info, DWORD flags)
 {
+#if defined(STAGING_CSMT)
     UINT start, len;
 
     /* This potentially invalidates the element array buffer binding, but the
@@ -684,6 +753,45 @@
         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)");
         This->flags &= ~WINED3D_BUFFER_APPLESYNC;
+#else  /* STAGING_CSMT */
+    BYTE *map;
+    UINT start, len;
+
+    /* This potentially invalidates the element array buffer binding, but the
+     * caller always takes care of this. */
+    GL_EXTCALL(glBindBuffer(This->buffer_type_hint, This->buffer_object));
+    checkGLcall("glBindBuffer");
+    if (gl_info->supported[ARB_MAP_BUFFER_RANGE])
+    {
+        GLbitfield mapflags;
+        mapflags = GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT;
+        if (flags & WINED3D_BUFFER_DISCARD)
+            mapflags |= GL_MAP_INVALIDATE_BUFFER_BIT;
+        else if (!(flags & WINED3D_BUFFER_SYNC))
+            mapflags |= GL_MAP_UNSYNCHRONIZED_BIT;
+        map = GL_EXTCALL(glMapBufferRange(This->buffer_type_hint, 0,
+                    This->resource.size, mapflags));
+        checkGLcall("glMapBufferRange");
+    }
+    else
+    {
+        if (This->flags & WINED3D_BUFFER_APPLESYNC)
+        {
+            DWORD syncflags = 0;
+            if (flags & WINED3D_BUFFER_DISCARD)
+                syncflags |= WINED3D_MAP_DISCARD;
+            else if (!(flags & WINED3D_BUFFER_SYNC))
+                syncflags |= WINED3D_MAP_NOOVERWRITE;
+            buffer_sync_apple(This, syncflags, gl_info);
+        }
+        map = GL_EXTCALL(glMapBuffer(This->buffer_type_hint, GL_WRITE_ONLY));
+        checkGLcall("glMapBuffer");
+    }
+    if (!map)
+    {
+        ERR("Failed to map opengl buffer\n");
+        return;
+#endif /* STAGING_CSMT */
     }
 
     while (This->modified_areas)
@@ -692,12 +800,33 @@
         start = This->maps[This->modified_areas].offset;
         len = This->maps[This->modified_areas].size;
 
+#if defined(STAGING_CSMT)
         GL_EXTCALL(glBufferSubData(This->buffer_type_hint, start, len, (BYTE *)This->resource.heap_memory + start));
         checkGLcall("glBufferSubData");
     }
 }
 
 static void buffer_mark_used(struct wined3d_buffer *buffer)
+#else  /* STAGING_CSMT */
+        memcpy(map + start, (BYTE *)This->resource.heap_memory + start, len);
+
+        if (gl_info->supported[ARB_MAP_BUFFER_RANGE])
+        {
+            GL_EXTCALL(glFlushMappedBufferRange(This->buffer_type_hint, start, len));
+            checkGLcall("glFlushMappedBufferRange");
+        }
+        else if (This->flags & WINED3D_BUFFER_FLUSH)
+        {
+            GL_EXTCALL(glFlushMappedBufferRangeAPPLE(This->buffer_type_hint, start, len));
+            checkGLcall("glFlushMappedBufferRangeAPPLE");
+        }
+    }
+    GL_EXTCALL(glUnmapBuffer(This->buffer_type_hint));
+    checkGLcall("glUnmapBuffer");
+}
+
+void buffer_mark_used(struct wined3d_buffer *buffer)
+#endif /* STAGING_CSMT */
 {
     buffer->flags &= ~(WINED3D_BUFFER_SYNC | WINED3D_BUFFER_DISCARD);
 }
@@ -716,6 +845,14 @@
 
     TRACE("buffer %p.\n", buffer);
 
+#if !defined(STAGING_CSMT)
+    if (buffer->resource.map_count)
+    {
+        WARN("Buffer is mapped, skipping preload.\n");
+        return;
+    }
+
+#endif /* STAGING_CSMT */
     buffer_mark_used(buffer);
 
     if (!buffer->buffer_object)
@@ -904,6 +1041,7 @@
 
 void CDECL wined3d_buffer_preload(struct wined3d_buffer *buffer)
 {
+#if defined(STAGING_CSMT)
     struct wined3d_device *device = buffer->resource.device;
 
     if (buffer->resource.map_count)
@@ -913,6 +1051,12 @@
     }
 
     wined3d_cs_emit_buffer_preload(device->cs, buffer);
+#else  /* STAGING_CSMT */
+    struct wined3d_context *context;
+    context = context_acquire(buffer->resource.device, NULL);
+    buffer_internal_preload(buffer, context, NULL);
+    context_release(context);
+#endif /* STAGING_CSMT */
 }
 
 struct wined3d_resource * CDECL wined3d_buffer_get_resource(struct wined3d_buffer *buffer)
@@ -926,6 +1070,7 @@
 {
     LONG count;
     BYTE *base;
+#if defined(STAGING_CSMT)
     struct wined3d_device *device = buffer->resource.device;
     struct wined3d_context *context;
 
@@ -950,6 +1095,10 @@
         wined3d_cs_emit_create_vbo(device->cs, buffer);
         buffer->flags &= ~WINED3D_BUFFER_CREATEBO;
     }
+#else  /* STAGING_CSMT */
+
+    TRACE("buffer %p, offset %u, size %u, data %p, flags %#x\n", buffer, offset, size, data, flags);
+#endif /* STAGING_CSMT */
 
     flags = wined3d_resource_sanitize_map_flags(&buffer->resource, flags);
     /* Filter redundant WINED3D_MAP_DISCARD maps. The 3DMark2001 multitexture
@@ -958,7 +1107,11 @@
      * previous contents of the buffer. The r600g driver only does this when
      * the buffer is currently in use, while the proprietary NVIDIA driver
      * appears to do this unconditionally. */
+#if defined(STAGING_CSMT)
     if (buffer->ignore_discard)
+#else  /* STAGING_CSMT */
+    if (buffer->flags & WINED3D_BUFFER_DISCARD)
+#endif /* STAGING_CSMT */
         flags &= ~WINED3D_MAP_DISCARD;
     count = ++buffer->resource.map_count;
 
@@ -969,6 +1122,7 @@
          * being uploaded in that case. Two such applications are Port Royale
          * and Darkstar One. */
         if (flags & WINED3D_MAP_DISCARD)
+#if defined(STAGING_CSMT)
             wined3d_cs_emit_buffer_invalidate_bo_range(device->cs, buffer, 0, 0);
         else if (!(flags & WINED3D_MAP_READONLY))
             wined3d_cs_emit_buffer_invalidate_bo_range(device->cs, buffer, offset, size);
@@ -986,6 +1140,19 @@
                     wined3d_cs_emit_glfinish(device->cs);
                     device->cs->ops->finish(device->cs);
                 }
+#else  /* STAGING_CSMT */
+            buffer_invalidate_bo_range(buffer, 0, 0);
+        else if (!(flags & WINED3D_MAP_READONLY))
+            buffer_invalidate_bo_range(buffer, offset, size);
+
+        if (!(buffer->flags & WINED3D_BUFFER_DOUBLEBUFFER))
+        {
+            if (count == 1)
+            {
+                struct wined3d_device *device = buffer->resource.device;
+                struct wined3d_context *context;
+                const struct wined3d_gl_info *gl_info;
+#endif /* STAGING_CSMT */
 
                 context = context_acquire(device, NULL);
                 gl_info = context->gl_info;
@@ -1036,6 +1203,7 @@
                         buffer_get_sysmem(buffer, context);
                     }
                     TRACE("New pointer is %p.\n", buffer->resource.heap_memory);
+#if defined(STAGING_CSMT)
                 }
                 context_release(context);
             }
@@ -1075,6 +1243,21 @@
     }
 
     base = buffer->map_ptr ? buffer->map_ptr : buffer->resource.map_heap_memory;
+#else  /* STAGING_CSMT */
+                    buffer->map_ptr = NULL;
+                }
+                context_release(context);
+            }
+        }
+
+        if (flags & WINED3D_MAP_DISCARD)
+            buffer->flags |= WINED3D_BUFFER_DISCARD;
+        else if (!(flags & WINED3D_MAP_NOOVERWRITE))
+            buffer->flags |= WINED3D_BUFFER_SYNC;
+    }
+
+    base = buffer->map_ptr ? buffer->map_ptr : buffer->resource.heap_memory;
+#endif /* STAGING_CSMT */
     *data = base + offset;
 
     TRACE("Returning memory at %p (base %p, offset %u).\n", *data, base, offset);
@@ -1128,7 +1311,11 @@
                 checkGLcall("glFlushMappedBufferRange");
             }
         }
+#if defined(STAGING_CSMT)
         else if (buffer->flags & WINED3D_BUFFER_APPLESYNC)
+#else  /* STAGING_CSMT */
+        else if (buffer->flags & WINED3D_BUFFER_FLUSH)
+#endif /* STAGING_CSMT */
         {
             for (i = 0; i < buffer->modified_areas; ++i)
             {
@@ -1139,6 +1326,7 @@
         }
 
         GL_EXTCALL(glUnmapBuffer(buffer->buffer_type_hint));
+#if defined(STAGING_CSMT)
         if (wined3d_settings.cs_multithreaded)
             gl_info->gl_ops.gl.p_glFinish();
         else if (wined3d_settings.strict_draw_ordering)
@@ -1147,6 +1335,18 @@
 
         buffer_clear_dirty_areas(buffer);
         buffer->map_ptr = NULL;
+#else  /* STAGING_CSMT */
+        if (wined3d_settings.strict_draw_ordering)
+            gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
+        context_release(context);
+
+        buffer_clear_dirty_areas(buffer);
+        buffer->map_ptr = NULL;
+    }
+    else if (buffer->flags & WINED3D_BUFFER_HASDESC)
+    {
+        wined3d_buffer_preload(buffer);
+#endif /* STAGING_CSMT */
     }
 }
 
@@ -1225,6 +1425,7 @@
     return WINED3D_OK;
 }
 
+#if defined(STAGING_CSMT)
 static void wined3d_buffer_location_invalidated(struct wined3d_resource *resource, DWORD location)
 {
     ERR("Not yet implemented.\n");
@@ -1237,6 +1438,7 @@
     ERR("Not yet implemented.\n");
 }
 
+#endif /* STAGING_CSMT */
 static const struct wined3d_resource_ops buffer_resource_ops =
 {
     buffer_resource_incref,
@@ -1244,8 +1446,10 @@
     buffer_unload,
     buffer_resource_sub_resource_map,
     buffer_resource_sub_resource_unmap,
+#if defined(STAGING_CSMT)
     wined3d_buffer_location_invalidated,
     wined3d_buffer_load_location,
+#endif /* STAGING_CSMT */
 };
 
 static HRESULT buffer_init(struct wined3d_buffer *buffer, struct wined3d_device *device,
@@ -1277,7 +1481,9 @@
         return hr;
     }
     buffer->buffer_type_hint = bind_hint;
+#if defined(STAGING_CSMT)
     buffer->ignore_discard = TRUE;
+#endif /* STAGING_CSMT */
 
     TRACE("size %#x, usage %#x, format %s, memory @ %p, iface @ %p.\n", buffer->resource.size, buffer->resource.usage,
             debug_d3dformat(buffer->resource.format->id), buffer->resource.heap_memory, buffer);
@@ -1293,6 +1499,7 @@
 
     dynamic_buffer_ok = gl_info->supported[APPLE_FLUSH_BUFFER_RANGE] || gl_info->supported[ARB_MAP_BUFFER_RANGE];
 
+#if defined(STAGING_CSMT)
     /* Observations show that draw_strided_slow is faster on dynamic VBs than converting +
      * drawStridedFast (half-life 2 and others).
      *
@@ -1300,6 +1507,15 @@
      * show that draw_strided_slow is faster than converting + uploading + drawStridedFast.
      * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
      */
+#else  /* STAGING_CSMT */
+    /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
+     * drawStridedFast (half-life 2 and others).
+     *
+     * Basically converting the vertices in the buffer is quite expensive, and observations
+     * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
+     * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
+     */
+#endif /* STAGING_CSMT */
     if (!gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
     {
         TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
@@ -1317,6 +1533,7 @@
         buffer->flags |= WINED3D_BUFFER_CREATEBO;
     }
 
+#if defined(STAGING_CSMT)
     buffer->maps = HeapAlloc(GetProcessHeap(), 0, sizeof(*buffer->maps));
     if (!buffer->maps)
     {
@@ -1341,6 +1558,28 @@
 
     if (wined3d_settings.cs_multithreaded)
         buffer->flags |= WINED3D_BUFFER_DOUBLEBUFFER;
+#else  /* STAGING_CSMT */
+    if (data)
+    {
+        if (FAILED(hr = wined3d_buffer_upload_data(buffer, NULL, data->data)))
+        {
+            ERR("Failed to upload data, hr %#x.\n", hr);
+            buffer_unload(&buffer->resource);
+            resource_cleanup(&buffer->resource);
+            return hr;
+        }
+    }
+
+    buffer->maps = HeapAlloc(GetProcessHeap(), 0, sizeof(*buffer->maps));
+    if (!buffer->maps)
+    {
+        ERR("Out of memory\n");
+        buffer_unload(&buffer->resource);
+        resource_cleanup(&buffer->resource);
+        return E_OUTOFMEMORY;
+    }
+    buffer->maps_size = 1;
+#endif /* STAGING_CSMT */
 
     return WINED3D_OK;
 }
@@ -1449,6 +1688,7 @@
 
     return WINED3D_OK;
 }
+#if defined(STAGING_CSMT)
 
 void buffer_swap_mem(struct wined3d_buffer *buffer, BYTE *mem)
 {
@@ -1456,3 +1696,4 @@
     buffer->resource.heap_memory = mem;
     buffer->flags |= WINED3D_BUFFER_DISCARD;
 }
+#endif /* STAGING_CSMT */
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -1453,6 +1453,7 @@
         goto out;
     }
 
+#if defined(STAGING_CSMT)
     ret->current_fb.render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
             sizeof(*ret->current_fb.render_targets) * gl_info->limits.buffers);
     ret->current_fb.rt_size = gl_info->limits.buffers;
@@ -1461,6 +1462,7 @@
     if (device->context_count)
         ret->offscreenBuffer = device->contexts[0]->offscreenBuffer;
 
+#endif /* STAGING_CSMT */
     /* Initialize the texture unit mapping to a 1:1 mapping */
     for (s = 0; s < MAX_COMBINED_SAMPLERS; ++s)
     {
@@ -1784,7 +1786,9 @@
 out:
     device->shader_backend->shader_free_context_data(ret);
     device->adapter->fragment_pipe->free_context_data(ret);
+#if defined(STAGING_CSMT)
     HeapFree(GetProcessHeap(), 0, ret->current_fb.render_targets);
+#endif /* STAGING_CSMT */
     HeapFree(GetProcessHeap(), 0, ret->free_event_queries);
     HeapFree(GetProcessHeap(), 0, ret->free_occlusion_queries);
     HeapFree(GetProcessHeap(), 0, ret->free_timestamp_queries);
@@ -1819,7 +1823,9 @@
 
     device->shader_backend->shader_free_context_data(context);
     device->adapter->fragment_pipe->free_context_data(context);
+#if defined(STAGING_CSMT)
     HeapFree(GetProcessHeap(), 0, context->current_fb.render_targets);
+#endif /* STAGING_CSMT */
     HeapFree(GetProcessHeap(), 0, context->draw_buffers);
     HeapFree(GetProcessHeap(), 0, context->blit_targets);
     device_context_remove(device, context);
@@ -2239,6 +2245,7 @@
     WARN("Depth stencil format is not supported by WGL, rendering the backbuffer in an FBO\n");
 
     /* The currently active context is the necessary context to access the swapchain's onscreen buffers */
+#if defined(STAGING_CSMT)
     wined3d_resource_load_location(&context->current_rt->resource, context, WINED3D_LOCATION_TEXTURE_RGB);
     swapchain->render_to_fbo = TRUE;
     swapchain_update_draw_bindings(swapchain);
@@ -2253,6 +2260,22 @@
         return context_generate_rt_mask_from_surface(rt);
     else
         return context_generate_rt_mask(context->offscreenBuffer);
+#else  /* STAGING_CSMT */
+    surface_load_location(context->current_rt, context, WINED3D_LOCATION_TEXTURE_RGB);
+    swapchain->render_to_fbo = TRUE;
+    swapchain_update_draw_bindings(swapchain);
+    context_set_render_offscreen(context, TRUE);
+}
+
+static DWORD context_generate_rt_mask_no_fbo(const struct wined3d_device *device, const struct wined3d_surface *rt)
+{
+    if (!rt || rt->resource.format->id == WINED3DFMT_NULL)
+        return 0;
+    else if (rt->container->swapchain)
+        return context_generate_rt_mask_from_surface(rt);
+    else
+        return context_generate_rt_mask(device->offscreenBuffer);
+#endif /* STAGING_CSMT */
 }
 
 /* Context activation is done by the caller. */
@@ -2284,7 +2307,11 @@
     }
     else
     {
+#if defined(STAGING_CSMT)
         rt_mask = context_generate_rt_mask_no_fbo(context, rt);
+#else  /* STAGING_CSMT */
+        rt_mask = context_generate_rt_mask_no_fbo(device, rt);
+#endif /* STAGING_CSMT */
     }
 
     cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
@@ -2331,7 +2358,11 @@
     DWORD rt_mask = 0, *cur_mask;
     UINT i;
 
+#if defined(STAGING_CSMT)
     if (isStateDirty(context, STATE_FRAMEBUFFER) || !wined3d_fb_equal(fb, &context->current_fb)
+#else  /* STAGING_CSMT */
+    if (isStateDirty(context, STATE_FRAMEBUFFER) || fb != &device->fb
+#endif /* STAGING_CSMT */
             || rt_count != context->gl_info->limits.buffers)
     {
         if (!context_validate_rt_config(rt_count, rts, dsv))
@@ -2373,11 +2404,17 @@
         }
         else
         {
+#if defined(STAGING_CSMT)
             rt_mask = context_generate_rt_mask_no_fbo(context,
                     rt_count ? wined3d_rendertarget_view_get_surface(rts[0]) : NULL);
         }
 
         wined3d_fb_copy(&context->current_fb, fb);
+#else  /* STAGING_CSMT */
+            rt_mask = context_generate_rt_mask_no_fbo(device,
+                    rt_count ? wined3d_rendertarget_view_get_surface(rts[0]) : NULL);
+        }
+#endif /* STAGING_CSMT */
     }
     else if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
             && (!rt_count || wined3d_resource_is_offscreen(rts[0]->resource)))
@@ -2390,7 +2427,11 @@
     }
     else
     {
+#if defined(STAGING_CSMT)
         rt_mask = context_generate_rt_mask_no_fbo(context,
+#else  /* STAGING_CSMT */
+        rt_mask = context_generate_rt_mask_no_fbo(device,
+#endif /* STAGING_CSMT */
                 rt_count ? wined3d_rendertarget_view_get_surface(rts[0]) : NULL);
     }
 
@@ -2433,6 +2474,7 @@
     return TRUE;
 }
 
+#if defined(STAGING_CSMT)
 static DWORD find_draw_buffers_mask(const struct wined3d_context *context, const struct wined3d_state *state)
 {
     struct wined3d_rendertarget_view **rts = state->fb.render_targets;
@@ -2442,6 +2484,18 @@
 
     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO)
         return context_generate_rt_mask_no_fbo(context, wined3d_rendertarget_view_get_surface(rts[0]));
+#else  /* STAGING_CSMT */
+static DWORD find_draw_buffers_mask(const struct wined3d_context *context, const struct wined3d_device *device)
+{
+    const struct wined3d_state *state = &device->state;
+    struct wined3d_rendertarget_view **rts = state->fb->render_targets;
+    struct wined3d_shader *ps = state->shader[WINED3D_SHADER_TYPE_PIXEL];
+    DWORD rt_mask, rt_mask_bits;
+    unsigned int i;
+
+    if (wined3d_settings.offscreen_rendering_mode != ORM_FBO)
+        return context_generate_rt_mask_no_fbo(device, wined3d_rendertarget_view_get_surface(rts[0]));
+#endif /* STAGING_CSMT */
     else if (!context->render_offscreen)
         return context_generate_rt_mask_from_surface(wined3d_rendertarget_view_get_surface(rts[0]));
 
@@ -2464,8 +2518,14 @@
 /* Context activation is done by the caller. */
 void context_state_fb(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
 {
+#if defined(STAGING_CSMT)
     const struct wined3d_fb_state *fb = &state->fb;
     DWORD rt_mask = find_draw_buffers_mask(context, state);
+#else  /* STAGING_CSMT */
+    const struct wined3d_device *device = context->swapchain->device;
+    const struct wined3d_fb_state *fb = state->fb;
+    DWORD rt_mask = find_draw_buffers_mask(context, device);
+#endif /* STAGING_CSMT */
     DWORD *cur_mask;
 
     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
@@ -2496,8 +2556,10 @@
         context_apply_draw_buffers(context, rt_mask);
         *cur_mask = rt_mask;
     }
+#if defined(STAGING_CSMT)
 
     wined3d_fb_copy(&context->current_fb, &state->fb);
+#endif /* STAGING_CSMT */
 }
 
 static void context_map_stage(struct wined3d_context *context, DWORD stage, DWORD unit)
@@ -2744,12 +2806,22 @@
 /* Context activation is done by the caller. */
 void context_state_drawbuf(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
 {
+#if defined(STAGING_CSMT)
     DWORD rt_mask, *cur_mask;
 
     if (isStateDirty(context, STATE_FRAMEBUFFER)) return;
 
     cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
     rt_mask = find_draw_buffers_mask(context, state);
+#else  /* STAGING_CSMT */
+    const struct wined3d_device *device = context->swapchain->device;
+    DWORD rt_mask, *cur_mask;
+
+    if (isStateDirty(context, STATE_FRAMEBUFFER)) return;
+
+    cur_mask = context->current_fbo ? &context->current_fbo->rt_mask : &context->draw_buffers_mask;
+    rt_mask = find_draw_buffers_mask(context, device);
+#endif /* STAGING_CSMT */
     if (rt_mask != *cur_mask)
     {
         context_apply_draw_buffers(context, rt_mask);
@@ -2951,7 +3023,11 @@
     {
         if (state->vertex_declaration->half_float_conv_needed && !stream_info->all_vbo)
         {
+#if defined(STAGING_CSMT)
             TRACE("Using draw_strided_slow with vertex shaders for FLOAT16 conversion.\n");
+#else  /* STAGING_CSMT */
+            TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
+#endif /* STAGING_CSMT */
             context->use_immediate_mode_draw = TRUE;
         }
         else
@@ -3136,11 +3212,19 @@
 }
 
 /* Context activation is done by the caller. */
+#if defined(STAGING_CSMT)
 BOOL context_apply_draw_state(struct wined3d_context *context, const struct wined3d_device *device,
         const struct wined3d_state *state)
 {
     const struct StateEntry *state_table = context->state_table;
     const struct wined3d_fb_state *fb = &state->fb;
+#else  /* STAGING_CSMT */
+BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_device *device)
+{
+    const struct wined3d_state *state = &device->state;
+    const struct StateEntry *state_table = context->state_table;
+    const struct wined3d_fb_state *fb = state->fb;
+#endif /* STAGING_CSMT */
     unsigned int i;
     WORD map;
 
@@ -3173,12 +3257,17 @@
         for (i = 0, map = context->stream_info.use_map; map; map >>= 1, ++i)
         {
             if (map & 1)
+#if defined(STAGING_CSMT)
                 buffer_internal_preload(state->streams[context->stream_info.elements[i].stream_idx].buffer,
                         context, state);
         }
         /* PreLoad may kick buffers out of vram. */
         if (isStateDirty(context, STATE_STREAMSRC))
             context_update_stream_info(context, state);
+#else  /* STAGING_CSMT */
+                buffer_mark_used(state->streams[context->stream_info.elements[i].stream_idx].buffer);
+        }
+#endif /* STAGING_CSMT */
     }
     if (state->index_buffer)
     {
@@ -3273,7 +3362,11 @@
             if (texture->texture_srgb.name)
                 wined3d_texture_load(texture, context, TRUE);
             wined3d_texture_load(texture, context, FALSE);
+#if defined(STAGING_CSMT)
             wined3d_resource_invalidate_location(&context->current_rt->resource, WINED3D_LOCATION_DRAWABLE);
+#else  /* STAGING_CSMT */
+            surface_invalidate_location(context->current_rt, WINED3D_LOCATION_DRAWABLE);
+#endif /* STAGING_CSMT */
         }
     }
 
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -22,11 +22,18 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
 
+#if defined(STAGING_CSMT)
 enum wined3d_cs_op
 {
     WINED3D_CS_OP_NOP,
     WINED3D_CS_OP_SKIP,
     WINED3D_CS_OP_FENCE,
+#else  /* STAGING_CSMT */
+#define WINED3D_INITIAL_CS_SIZE 4096
+
+enum wined3d_cs_op
+{
+#endif /* STAGING_CSMT */
     WINED3D_CS_OP_PRESENT,
     WINED3D_CS_OP_CLEAR,
     WINED3D_CS_OP_DRAW,
@@ -53,6 +60,7 @@
     WINED3D_CS_OP_SET_COLOR_KEY,
     WINED3D_CS_OP_SET_MATERIAL,
     WINED3D_CS_OP_RESET_STATE,
+#if defined(STAGING_CSMT)
     WINED3D_CS_OP_SET_VS_CONSTS_F,
     WINED3D_CS_OP_SET_VS_CONSTS_B,
     WINED3D_CS_OP_SET_VS_CONSTS_I,
@@ -133,6 +141,30 @@
     float depth;
     DWORD stencil;
     RECT rects[1];
+#else  /* STAGING_CSMT */
+};
+
+struct wined3d_cs_present
+{
+    enum wined3d_cs_op opcode;
+    HWND dst_window_override;
+    struct wined3d_swapchain *swapchain;
+    const RECT *src_rect;
+    const RECT *dst_rect;
+    const RGNDATA *dirty_region;
+    DWORD flags;
+};
+
+struct wined3d_cs_clear
+{
+    enum wined3d_cs_op opcode;
+    DWORD rect_count;
+    const RECT *rects;
+    DWORD flags;
+    const struct wined3d_color *color;
+    float depth;
+    DWORD stencil;
+#endif /* STAGING_CSMT */
 };
 
 struct wined3d_cs_draw
@@ -155,6 +187,7 @@
 struct wined3d_cs_set_viewport
 {
     enum wined3d_cs_op opcode;
+#if defined(STAGING_CSMT)
     struct wined3d_viewport viewport;
 };
 
@@ -162,6 +195,15 @@
 {
     enum wined3d_cs_op opcode;
     RECT rect;
+#else  /* STAGING_CSMT */
+    const struct wined3d_viewport *viewport;
+};
+
+struct wined3d_cs_set_scissor_rect
+{
+    enum wined3d_cs_op opcode;
+    const RECT *rect;
+#endif /* STAGING_CSMT */
 };
 
 struct wined3d_cs_set_rendertarget_view
@@ -289,6 +331,7 @@
 {
     enum wined3d_cs_op opcode;
     enum wined3d_transform_state state;
+#if defined(STAGING_CSMT)
     struct wined3d_matrix matrix;
 };
 
@@ -303,6 +346,22 @@
 {
     enum wined3d_cs_op opcode;
     struct wined3d_material material;
+#else  /* STAGING_CSMT */
+    const struct wined3d_matrix *matrix;
+};
+
+struct wined3d_cs_set_clip_plane
+{
+    enum wined3d_cs_op opcode;
+    UINT plane_idx;
+    const struct wined3d_vec4 *plane;
+};
+
+struct wined3d_cs_set_material
+{
+    enum wined3d_cs_op opcode;
+    const struct wined3d_material *material;
+#endif /* STAGING_CSMT */
 };
 
 struct wined3d_cs_reset_state
@@ -310,6 +369,7 @@
     enum wined3d_cs_op opcode;
 };
 
+#if defined(STAGING_CSMT)
 struct wined3d_cs_set_consts_f
 {
     enum wined3d_cs_op opcode;
@@ -2881,197 +2941,971 @@
     /* WINED3D_CS_OP_NOP                        */ wined3d_cs_exec_nop,
     /* WINED3D_CS_OP_SKIP                       */ wined3d_cs_exec_skip,
     /* WINED3D_CS_OP_FENCE                      */ wined3d_cs_exec_fence,
-    /* WINED3D_CS_OP_PRESENT                    */ wined3d_cs_exec_present,
-    /* WINED3D_CS_OP_CLEAR                      */ wined3d_cs_exec_clear,
-    /* WINED3D_CS_OP_DRAW                       */ wined3d_cs_exec_draw,
-    /* WINED3D_CS_OP_SET_PREDICATION            */ wined3d_cs_exec_set_predication,
-    /* WINED3D_CS_OP_SET_VIEWPORT               */ wined3d_cs_exec_set_viewport,
-    /* WINED3D_CS_OP_SET_SCISSOR_RECT           */ wined3d_cs_exec_set_scissor_rect,
-    /* WINED3D_CS_OP_SET_RENDERTARGET_VIEW      */ wined3d_cs_exec_set_rendertarget_view,
-    /* WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW     */ wined3d_cs_exec_set_depth_stencil_view,
-    /* WINED3D_CS_OP_SET_VERTEX_DECLARATION     */ wined3d_cs_exec_set_vertex_declaration,
-    /* WINED3D_CS_OP_SET_STREAM_SOURCE          */ wined3d_cs_exec_set_stream_source,
-    /* WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ     */ wined3d_cs_exec_set_stream_source_freq,
-    /* WINED3D_CS_OP_SET_STREAM_OUTPUT          */ wined3d_cs_exec_set_stream_output,
-    /* WINED3D_CS_OP_SET_INDEX_BUFFER           */ wined3d_cs_exec_set_index_buffer,
-    /* WINED3D_CS_OP_SET_CONSTANT_BUFFER        */ wined3d_cs_exec_set_constant_buffer,
-    /* WINED3D_CS_OP_SET_TEXTURE                */ wined3d_cs_exec_set_texture,
-    /* WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEW   */ wined3d_cs_exec_set_shader_resource_view,
-    /* WINED3D_CS_OP_SET_SAMPLER                */ wined3d_cs_exec_set_sampler,
-    /* WINED3D_CS_OP_SET_SHADER                 */ wined3d_cs_exec_set_shader,
-    /* WINED3D_CS_OP_SET_RENDER_STATE           */ wined3d_cs_exec_set_render_state,
-    /* WINED3D_CS_OP_SET_TEXTURE_STATE          */ wined3d_cs_exec_set_texture_state,
-    /* WINED3D_CS_OP_SET_SAMPLER_STATE          */ wined3d_cs_exec_set_sampler_state,
-    /* WINED3D_CS_OP_SET_TRANSFORM              */ wined3d_cs_exec_set_transform,
-    /* WINED3D_CS_OP_SET_CLIP_PLANE             */ wined3d_cs_exec_set_clip_plane,
-    /* WINED3D_CS_OP_SET_COLOR_KEY              */ wined3d_cs_exec_set_color_key,
-    /* WINED3D_CS_OP_SET_MATERIAL               */ wined3d_cs_exec_set_material,
-    /* WINED3D_CS_OP_RESET_STATE                */ wined3d_cs_exec_reset_state,
-    /* WINED3D_CS_OP_SET_VS_CONSTS_F            */ wined3d_cs_exec_set_vs_consts_f,
-    /* WINED3D_CS_OP_SET_VS_CONSTS_B            */ wined3d_cs_exec_set_vs_consts_b,
-    /* WINED3D_CS_OP_SET_VS_CONSTS_I            */ wined3d_cs_exec_set_vs_consts_i,
-    /* WINED3D_CS_OP_SET_PS_CONSTS_F            */ wined3d_cs_exec_set_ps_consts_f,
-    /* WINED3D_CS_OP_SET_PS_CONSTS_B            */ wined3d_cs_exec_set_ps_consts_b,
-    /* WINED3D_CS_OP_SET_PS_CONSTS_I            */ wined3d_cs_exec_set_ps_consts_i,
-    /* WINED3D_CS_OP_GLFINISH                   */ wined3d_cs_exec_glfinish,
-    /* WINED3D_CS_OP_SET_BASE_VERTEX_INDEX      */ wined3d_cs_exec_set_base_vertex_index,
-    /* WINED3D_CS_OP_SET_PRIMITIVE_TYPE         */ wined3d_cs_exec_set_primitive_type,
-    /* WINED3D_CS_OP_SET_LIGHT                  */ wined3d_cs_exec_set_light,
-    /* WINED3D_CS_OP_SET_LIGHT_ENABLE           */ wined3d_cs_exec_set_light_enable,
-    /* WINED3D_CS_OP_BLT                        */ wined3d_cs_exec_blt,
-    /* WINED3D_CS_OP_CLEAR_RTV                  */ wined3d_cs_exec_clear_rtv,
-    /* WINED3D_CS_OP_RESOURCE_CHANGED           */ wined3d_cs_exec_resource_changed,
-    /* WINED3D_CS_OP_RESOURCE_MAP               */ wined3d_cs_exec_resource_map,
-    /* WINED3D_CS_OP_RESOURCE_UNMAP             */ wined3d_cs_exec_resource_unmap,
-    /* WINED3D_CS_OP_BUFFER_SWAP_MEM            */ wined3d_cs_exec_buffer_swap_mem,
-    /* WINED3D_CS_OP_BUFFER_INVALIDATE_RANGE    */ wined3d_cs_exec_buffer_invalidate_bo_range,
-    /* WINED3D_CS_OP_BUFFER_PRELOAD             */ wined3d_cs_exec_buffer_preload,
-    /* WINED3D_CS_OP_QUERY_ISSUE                */ wined3d_cs_exec_query_issue,
-    /* WINED3D_CS_OP_QUERY_DESTROY              */ wined3d_cs_exec_query_destroy,
-    /* WINED3D_CS_OP_UPDATE_SURFACE             */ wined3d_cs_exec_update_surface,
-    /* WINED3D_CS_OP_TEXTURE_PRELOAD            */ wined3d_cs_exec_texture_preload,
-    /* WINED3D_CS_OP_SURFACE_PRELOAD            */ wined3d_cs_exec_surface_preload,
-    /* WINED3D_CS_OP_UPDATE_TEXTURE             */ wined3d_cs_exec_update_texture,
-    /* WINED3D_CS_OP_EVICT_RESOURCE             */ wined3d_cs_exec_evict_resource,
-    /* WINED3D_CS_OP_VIEW_DESTROY               */ wined3d_cs_exec_view_destroy,
-    /* WINED3D_CS_OP_VDECL_DESTROY              */ wined3d_cs_exec_vertex_declaration_destroy,
-    /* WINED3D_CS_OP_SHADER_CLEANUP             */ wined3d_cs_exec_shader_cleanup,
-    /* WINED3D_CS_OP_CREATE_VBO                 */ wined3d_cs_exec_create_vbo,
-    /* WINED3D_CS_OP_RESOURCE_CLEANUP           */ wined3d_cs_exec_resource_cleanup,
-    /* WINED3D_CS_OP_BUFFER_CLEANUP             */ wined3d_cs_exec_buffer_cleanup,
-    /* WINED3D_CS_OP_VOLUME_CLEANUP             */ wined3d_cs_exec_volume_cleanup,
-    /* WINED3D_CS_OP_SURFACE_CLEANUP            */ wined3d_cs_exec_surface_cleanup,
-    /* WINED3D_CS_OP_TEXTURE_CLEANUP            */ wined3d_cs_exec_texture_cleanup,
-    /* 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,
-    /* WINED3D_CS_OP_SAMPLER_DESTROY            */ wined3d_cs_exec_sampler_destroy,
-    /* WINED3D_CS_OP_UPDATE_SUB_RESOURCE        */ wined3d_cs_exec_update_sub_resource,
-};
-
-static inline void *_wined3d_cs_mt_require_space(struct wined3d_cs *cs, size_t size, BOOL prio)
+#else  /* STAGING_CSMT */
+static void wined3d_cs_exec_present(struct wined3d_cs *cs, const void *data)
 {
-    struct wined3d_cs_queue *queue = prio ? &cs->prio_queue : &cs->queue;
-    size_t queue_size = sizeof(queue->data) / sizeof(*queue->data);
+    const struct wined3d_cs_present *op = data;
+    struct wined3d_swapchain *swapchain;
 
-    if (queue_size - size < queue->head)
-    {
-        struct wined3d_cs_skip *skip;
-        size_t nop_size = queue_size - queue->head;
+    swapchain = op->swapchain;
+    wined3d_swapchain_set_window(swapchain, op->dst_window_override);
 
-        skip = _wined3d_cs_mt_require_space(cs, nop_size, prio);
-        if (nop_size < sizeof(*skip))
-        {
-            skip->opcode = WINED3D_CS_OP_NOP;
-        }
-        else
-        {
-            skip->opcode = WINED3D_CS_OP_SKIP;
-            skip->size = nop_size;
-        }
+    swapchain->swapchain_ops->swapchain_present(swapchain,
+            op->src_rect, op->dst_rect, op->dirty_region, op->flags);
+}
 
-        if (prio)
-            cs->ops->submit_prio(cs, nop_size);
-        else
-            cs->ops->submit(cs, nop_size);
+void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *swapchain,
+        const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override,
+        const RGNDATA *dirty_region, DWORD flags)
+{
+    struct wined3d_cs_present *op;
 
-        assert(!queue->head);
-    }
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_PRESENT;
+    op->dst_window_override = dst_window_override;
+    op->swapchain = swapchain;
+    op->src_rect = src_rect;
+    op->dst_rect = dst_rect;
+    op->dirty_region = dirty_region;
+    op->flags = flags;
 
-    while(1)
-    {
-        LONG head = queue->head;
-        LONG tail = *((volatile LONG *)&queue->tail);
-        LONG new_pos;
-        /* Empty */
-        if (head == tail)
-            break;
-        /* Head ahead of tail, take care of wrap-around */
-        new_pos = (head + size) & (WINED3D_CS_QUEUE_SIZE - 1);
-        if (head > tail && (new_pos || tail))
-            break;
-        /* Tail ahead of head, but still enough space */
-        if (new_pos < tail && new_pos)
-            break;
+    cs->ops->submit(cs);
+}
 
-        TRACE("Waiting for free space. Head %u, tail %u, want %u\n", head, tail,
-                (unsigned int) size);
-    }
+static void wined3d_cs_exec_clear(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_clear *op = data;
+    struct wined3d_device *device;
+    RECT draw_rect;
 
-    return &queue->data[queue->head];
+    device = cs->device;
+    wined3d_get_draw_rect(&device->state, &draw_rect);
+    device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
+            &device->fb, op->rect_count, op->rects, &draw_rect, op->flags,
+            op->color, op->depth, op->stencil);
 }
 
-static inline void *wined3d_cs_mt_require_space(struct wined3d_cs *cs, size_t size)
+void wined3d_cs_emit_clear(struct wined3d_cs *cs, DWORD rect_count, const RECT *rects,
+        DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil)
 {
-    return _wined3d_cs_mt_require_space(cs, size, FALSE);
+    struct wined3d_cs_clear *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_CLEAR;
+    op->rect_count = rect_count;
+    op->rects = rects;
+    op->flags = flags;
+    op->color = color;
+    op->depth = depth;
+    op->stencil = stencil;
+
+    cs->ops->submit(cs);
 }
 
-static inline void *wined3d_cs_mt_require_space_prio(struct wined3d_cs *cs, size_t size)
+static void wined3d_cs_exec_draw(struct wined3d_cs *cs, const void *data)
 {
-    return _wined3d_cs_mt_require_space(cs, size, TRUE);
+    const struct wined3d_cs_draw *op = data;
+
+    draw_primitive(cs->device, op->start_idx, op->index_count,
+            op->start_instance, op->instance_count, op->indexed);
 }
 
-/* FIXME: wined3d_device_uninit_3d() should either flush and wait, or be an
- * OP itself. */
-static void wined3d_cs_emit_stop(struct wined3d_cs *cs)
+void wined3d_cs_emit_draw(struct wined3d_cs *cs, UINT start_idx, UINT index_count,
+        UINT start_instance, UINT instance_count, BOOL indexed)
 {
-    struct wined3d_cs_stop *op;
+    struct wined3d_cs_draw *op;
 
-    op = wined3d_cs_mt_require_space(cs, sizeof(*op));
-    op->opcode = WINED3D_CS_OP_STOP;
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_DRAW;
+    op->start_idx = start_idx;
+    op->index_count = index_count;
+    op->start_instance = start_instance;
+    op->instance_count = instance_count;
+    op->indexed = indexed;
 
-    wined3d_cs_mt_submit(cs, sizeof(*op));
+    cs->ops->submit(cs);
 }
 
-static void wined3d_cs_mt_finish(struct wined3d_cs *cs)
+static void wined3d_cs_exec_set_predication(struct wined3d_cs *cs, const void *data)
 {
-    BOOL fence;
-
-    if (cs->thread_id == GetCurrentThreadId())
-    {
-        static BOOL once;
-        if (!once)
-        {
-            FIXME("flush_and_wait called from cs thread\n");
-            once = TRUE;
-        }
-        return;
-    }
-
-    wined3d_cs_emit_fence(cs, &fence);
+    const struct wined3d_cs_set_predication *op = data;
 
-    /* A busy wait should be fine, we're not supposed to have to wait very
-     * long. */
-    while (!InterlockedCompareExchange(&fence, TRUE, TRUE));
+    cs->state.predicate = op->predicate;
+    cs->state.predicate_value = op->value;
 }
 
-static void wined3d_cs_mt_finish_prio(struct wined3d_cs *cs)
+void wined3d_cs_emit_set_predication(struct wined3d_cs *cs, struct wined3d_query *predicate, BOOL value)
 {
-    BOOL fence;
+    struct wined3d_cs_set_predication *op;
 
-    if (cs->thread_id == GetCurrentThreadId())
-    {
-        static BOOL once;
-        if (!once)
-        {
-            FIXME("flush_and_wait called from cs thread\n");
-            once = TRUE;
-        }
-        return;
-    }
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_PREDICATION;
+    op->predicate = predicate;
+    op->value = value;
 
-    wined3d_cs_emit_fence_prio(cs, &fence);
+    cs->ops->submit(cs);
+}
 
-    /* A busy wait should be fine, we're not supposed to have to wait very
-     * long. */
-    while (!InterlockedCompareExchange(&fence, TRUE, TRUE));
+static void wined3d_cs_exec_set_viewport(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_viewport *op = data;
+
+    cs->state.viewport = *op->viewport;
+    device_invalidate_state(cs->device, STATE_VIEWPORT);
 }
 
-static const struct wined3d_cs_ops wined3d_cs_mt_ops =
+void wined3d_cs_emit_set_viewport(struct wined3d_cs *cs, const struct wined3d_viewport *viewport)
 {
-    wined3d_cs_mt_require_space,
+    struct wined3d_cs_set_viewport *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_VIEWPORT;
+    op->viewport = viewport;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_scissor_rect(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_scissor_rect *op = data;
+
+    cs->state.scissor_rect = *op->rect;
+    device_invalidate_state(cs->device, STATE_SCISSORRECT);
+}
+
+void wined3d_cs_emit_set_scissor_rect(struct wined3d_cs *cs, const RECT *rect)
+{
+    struct wined3d_cs_set_scissor_rect *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_SCISSOR_RECT;
+    op->rect = rect;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_rendertarget_view(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_rendertarget_view *op = data;
+
+    cs->state.fb->render_targets[op->view_idx] = op->view;
+    device_invalidate_state(cs->device, STATE_FRAMEBUFFER);
+}
+
+void wined3d_cs_emit_set_rendertarget_view(struct wined3d_cs *cs, unsigned int view_idx,
+        struct wined3d_rendertarget_view *view)
+{
+    struct wined3d_cs_set_rendertarget_view *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_RENDERTARGET_VIEW;
+    op->view_idx = view_idx;
+    op->view = view;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_depth_stencil_view(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_depth_stencil_view *op = data;
+    struct wined3d_device *device = cs->device;
+    struct wined3d_rendertarget_view *prev;
+
+    if ((prev = cs->state.fb->depth_stencil))
+    {
+        struct wined3d_surface *prev_surface = wined3d_rendertarget_view_get_surface(prev);
+
+        if (prev_surface && (device->swapchains[0]->desc.flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
+                || prev_surface->flags & SFLAG_DISCARD))
+        {
+            surface_modify_ds_location(prev_surface, WINED3D_LOCATION_DISCARDED, prev->width, prev->height);
+            if (prev_surface == device->onscreen_depth_stencil)
+            {
+                wined3d_texture_decref(device->onscreen_depth_stencil->container);
+                device->onscreen_depth_stencil = NULL;
+            }
+        }
+    }
+
+    cs->fb.depth_stencil = op->view;
+
+    if (!prev != !op->view)
+    {
+        /* Swapping NULL / non NULL depth stencil affects the depth and tests */
+        device_invalidate_state(device, STATE_RENDER(WINED3D_RS_ZENABLE));
+        device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILENABLE));
+        device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
+        device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
+    }
+    else if (prev && (prev->format_flags & WINED3DFMT_FLAG_FLOAT)
+            != (op->view->format_flags & WINED3DFMT_FLAG_FLOAT))
+    {
+        device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
+    }
+
+    device_invalidate_state(device, STATE_FRAMEBUFFER);
+}
+
+void wined3d_cs_emit_set_depth_stencil_view(struct wined3d_cs *cs, struct wined3d_rendertarget_view *view)
+{
+    struct wined3d_cs_set_depth_stencil_view *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW;
+    op->view = view;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_vertex_declaration(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_vertex_declaration *op = data;
+
+    cs->state.vertex_declaration = op->declaration;
+    device_invalidate_state(cs->device, STATE_VDECL);
+}
+
+void wined3d_cs_emit_set_vertex_declaration(struct wined3d_cs *cs, struct wined3d_vertex_declaration *declaration)
+{
+    struct wined3d_cs_set_vertex_declaration *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_VERTEX_DECLARATION;
+    op->declaration = declaration;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_stream_source(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_stream_source *op = data;
+    struct wined3d_stream_state *stream;
+    struct wined3d_buffer *prev;
+
+    stream = &cs->state.streams[op->stream_idx];
+    prev = stream->buffer;
+    stream->buffer = op->buffer;
+    stream->offset = op->offset;
+    stream->stride = op->stride;
+
+    if (op->buffer)
+        InterlockedIncrement(&op->buffer->resource.bind_count);
+    if (prev)
+        InterlockedDecrement(&prev->resource.bind_count);
+
+    device_invalidate_state(cs->device, STATE_STREAMSRC);
+}
+
+void wined3d_cs_emit_set_stream_source(struct wined3d_cs *cs, UINT stream_idx,
+        struct wined3d_buffer *buffer, UINT offset, UINT stride)
+{
+    struct wined3d_cs_set_stream_source *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_STREAM_SOURCE;
+    op->stream_idx = stream_idx;
+    op->buffer = buffer;
+    op->offset = offset;
+    op->stride = stride;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_stream_source_freq(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_stream_source_freq *op = data;
+    struct wined3d_stream_state *stream;
+
+    stream = &cs->state.streams[op->stream_idx];
+    stream->frequency = op->frequency;
+    stream->flags = op->flags;
+
+    device_invalidate_state(cs->device, STATE_STREAMSRC);
+}
+
+void wined3d_cs_emit_set_stream_source_freq(struct wined3d_cs *cs, UINT stream_idx, UINT frequency, UINT flags)
+{
+    struct wined3d_cs_set_stream_source_freq *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ;
+    op->stream_idx = stream_idx;
+    op->frequency = frequency;
+    op->flags = flags;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_stream_output(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_stream_output *op = data;
+    struct wined3d_stream_output *stream;
+    struct wined3d_buffer *prev;
+
+    stream = &cs->state.stream_output[op->stream_idx];
+    prev = stream->buffer;
+    stream->buffer = op->buffer;
+    stream->offset = op->offset;
+
+    if (op->buffer)
+        InterlockedIncrement(&op->buffer->resource.bind_count);
+    if (prev)
+        InterlockedDecrement(&prev->resource.bind_count);
+}
+
+void wined3d_cs_emit_set_stream_output(struct wined3d_cs *cs, UINT stream_idx,
+        struct wined3d_buffer *buffer, UINT offset)
+{
+    struct wined3d_cs_set_stream_output *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_STREAM_OUTPUT;
+    op->stream_idx = stream_idx;
+    op->buffer = buffer;
+    op->offset = offset;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_index_buffer(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_index_buffer *op = data;
+    struct wined3d_buffer *prev;
+
+    prev = cs->state.index_buffer;
+    cs->state.index_buffer = op->buffer;
+    cs->state.index_format = op->format_id;
+
+    if (op->buffer)
+        InterlockedIncrement(&op->buffer->resource.bind_count);
+    if (prev)
+        InterlockedDecrement(&prev->resource.bind_count);
+
+    device_invalidate_state(cs->device, STATE_INDEXBUFFER);
+}
+
+void wined3d_cs_emit_set_index_buffer(struct wined3d_cs *cs, struct wined3d_buffer *buffer,
+        enum wined3d_format_id format_id)
+{
+    struct wined3d_cs_set_index_buffer *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_INDEX_BUFFER;
+    op->buffer = buffer;
+    op->format_id = format_id;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_constant_buffer(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_constant_buffer *op = data;
+    struct wined3d_buffer *prev;
+
+    prev = cs->state.cb[op->type][op->cb_idx];
+    cs->state.cb[op->type][op->cb_idx] = op->buffer;
+
+    if (op->buffer)
+        InterlockedIncrement(&op->buffer->resource.bind_count);
+    if (prev)
+        InterlockedDecrement(&prev->resource.bind_count);
+
+    device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(op->type));
+}
+
+void wined3d_cs_emit_set_constant_buffer(struct wined3d_cs *cs, enum wined3d_shader_type type,
+        UINT cb_idx, struct wined3d_buffer *buffer)
+{
+    struct wined3d_cs_set_constant_buffer *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_CONSTANT_BUFFER;
+    op->type = type;
+    op->cb_idx = cb_idx;
+    op->buffer = buffer;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_texture(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_d3d_info *d3d_info = &cs->device->adapter->d3d_info;
+    const struct wined3d_cs_set_texture *op = data;
+    struct wined3d_texture *prev;
+    BOOL old_use_color_key = FALSE, new_use_color_key = FALSE;
+
+    prev = cs->state.textures[op->stage];
+    cs->state.textures[op->stage] = op->texture;
+
+    if (op->texture)
+    {
+        const struct wined3d_format *new_format = op->texture->resource.format;
+        const struct wined3d_format *old_format = prev ? prev->resource.format : NULL;
+        unsigned int old_fmt_flags = prev ? prev->resource.format_flags : 0;
+        unsigned int new_fmt_flags = op->texture->resource.format_flags;
+
+        if (InterlockedIncrement(&op->texture->resource.bind_count) == 1)
+            op->texture->sampler = op->stage;
+
+        if (!prev || op->texture->target != prev->target
+                || !is_same_fixup(new_format->color_fixup, old_format->color_fixup)
+                || (new_fmt_flags & WINED3DFMT_FLAG_SHADOW) != (old_fmt_flags & WINED3DFMT_FLAG_SHADOW))
+            device_invalidate_state(cs->device, STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL));
+
+        if (!prev && op->stage < d3d_info->limits.ffp_blend_stages)
+        {
+            /* The source arguments for color and alpha ops have different
+             * meanings when a NULL texture is bound, so the COLOR_OP and
+             * ALPHA_OP have to be dirtified. */
+            device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_COLOR_OP));
+            device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_ALPHA_OP));
+        }
+
+        if (!op->stage && op->texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
+            new_use_color_key = TRUE;
+    }
+
+    if (prev)
+    {
+        if (InterlockedDecrement(&prev->resource.bind_count) && prev->sampler == op->stage)
+        {
+            unsigned int i;
+
+            /* Search for other stages the texture is bound to. Shouldn't
+             * happen if applications bind textures to a single stage only. */
+            TRACE("Searching for other stages the texture is bound to.\n");
+            for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
+            {
+                if (cs->state.textures[i] == prev)
+                {
+                    TRACE("Texture is also bound to stage %u.\n", i);
+                    prev->sampler = i;
+                    break;
+                }
+            }
+        }
+
+        if (!op->texture && op->stage < d3d_info->limits.ffp_blend_stages)
+        {
+            device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_COLOR_OP));
+            device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, WINED3D_TSS_ALPHA_OP));
+        }
+
+        if (!op->stage && prev->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
+            old_use_color_key = TRUE;
+    }
+
+    device_invalidate_state(cs->device, STATE_SAMPLER(op->stage));
+
+    if (new_use_color_key != old_use_color_key)
+        device_invalidate_state(cs->device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
+
+    if (new_use_color_key)
+        device_invalidate_state(cs->device, STATE_COLOR_KEY);
+}
+
+void wined3d_cs_emit_set_texture(struct wined3d_cs *cs, UINT stage, struct wined3d_texture *texture)
+{
+    struct wined3d_cs_set_texture *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_TEXTURE;
+    op->stage = stage;
+    op->texture = texture;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_shader_resource_view(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_shader_resource_view *op = data;
+
+    cs->state.shader_resource_view[op->type][op->view_idx] = op->view;
+    device_invalidate_state(cs->device, STATE_SHADER_RESOURCE_BINDING);
+}
+
+void wined3d_cs_emit_set_shader_resource_view(struct wined3d_cs *cs, enum wined3d_shader_type type,
+        UINT view_idx, struct wined3d_shader_resource_view *view)
+{
+    struct wined3d_cs_set_shader_resource_view *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEW;
+    op->type = type;
+    op->view_idx = view_idx;
+    op->view = view;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_sampler(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_sampler *op = data;
+
+    cs->state.sampler[op->type][op->sampler_idx] = op->sampler;
+    device_invalidate_state(cs->device, STATE_SHADER_RESOURCE_BINDING);
+}
+
+void wined3d_cs_emit_set_sampler(struct wined3d_cs *cs, enum wined3d_shader_type type,
+        UINT sampler_idx, struct wined3d_sampler *sampler)
+{
+    struct wined3d_cs_set_sampler *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_SAMPLER;
+    op->type = type;
+    op->sampler_idx = sampler_idx;
+    op->sampler = sampler;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_shader(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_shader *op = data;
+
+    cs->state.shader[op->type] = op->shader;
+    device_invalidate_state(cs->device, STATE_SHADER(op->type));
+    device_invalidate_state(cs->device, STATE_SHADER_RESOURCE_BINDING);
+}
+
+void wined3d_cs_emit_set_shader(struct wined3d_cs *cs, enum wined3d_shader_type type, struct wined3d_shader *shader)
+{
+    struct wined3d_cs_set_shader *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_SHADER;
+    op->type = type;
+    op->shader = shader;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_render_state(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_render_state *op = data;
+
+    cs->state.render_states[op->state] = op->value;
+    device_invalidate_state(cs->device, STATE_RENDER(op->state));
+}
+
+void wined3d_cs_emit_set_render_state(struct wined3d_cs *cs, enum wined3d_render_state state, DWORD value)
+{
+    struct wined3d_cs_set_render_state *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_RENDER_STATE;
+    op->state = state;
+    op->value = value;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_texture_state(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_texture_state *op = data;
+
+    cs->state.texture_states[op->stage][op->state] = op->value;
+    device_invalidate_state(cs->device, STATE_TEXTURESTAGE(op->stage, op->state));
+}
+
+void wined3d_cs_emit_set_texture_state(struct wined3d_cs *cs, UINT stage,
+        enum wined3d_texture_stage_state state, DWORD value)
+{
+    struct wined3d_cs_set_texture_state *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_TEXTURE_STATE;
+    op->stage = stage;
+    op->state = state;
+    op->value = value;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_sampler_state(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_sampler_state *op = data;
+
+    cs->state.sampler_states[op->sampler_idx][op->state] = op->value;
+    device_invalidate_state(cs->device, STATE_SAMPLER(op->sampler_idx));
+}
+
+void wined3d_cs_emit_set_sampler_state(struct wined3d_cs *cs, UINT sampler_idx,
+        enum wined3d_sampler_state state, DWORD value)
+{
+    struct wined3d_cs_set_sampler_state *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_SAMPLER_STATE;
+    op->sampler_idx = sampler_idx;
+    op->state = state;
+    op->value = value;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_transform(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_transform *op = data;
+
+    cs->state.transforms[op->state] = *op->matrix;
+    if (op->state < WINED3D_TS_WORLD_MATRIX(cs->device->adapter->d3d_info.limits.ffp_vertex_blend_matrices))
+        device_invalidate_state(cs->device, STATE_TRANSFORM(op->state));
+}
+
+void wined3d_cs_emit_set_transform(struct wined3d_cs *cs, enum wined3d_transform_state state,
+        const struct wined3d_matrix *matrix)
+{
+    struct wined3d_cs_set_transform *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_TRANSFORM;
+    op->state = state;
+    op->matrix = matrix;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_clip_plane(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_clip_plane *op = data;
+
+    cs->state.clip_planes[op->plane_idx] = *op->plane;
+    device_invalidate_state(cs->device, STATE_CLIPPLANE(op->plane_idx));
+}
+
+void wined3d_cs_emit_set_clip_plane(struct wined3d_cs *cs, UINT plane_idx, const struct wined3d_vec4 *plane)
+{
+    struct wined3d_cs_set_clip_plane *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_CLIP_PLANE;
+    op->plane_idx = plane_idx;
+    op->plane = plane;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_color_key(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_color_key *op = data;
+    struct wined3d_texture *texture = op->texture;
+
+    if (op->set)
+    {
+        switch (op->flags)
+        {
+            case WINED3D_CKEY_DST_BLT:
+                texture->async.dst_blt_color_key = op->color_key;
+                texture->async.color_key_flags |= WINED3D_CKEY_DST_BLT;
+                break;
+
+            case WINED3D_CKEY_DST_OVERLAY:
+                texture->async.dst_overlay_color_key = op->color_key;
+                texture->async.color_key_flags |= WINED3D_CKEY_DST_OVERLAY;
+                break;
+
+            case WINED3D_CKEY_SRC_BLT:
+                if (texture == cs->state.textures[0])
+                {
+                    device_invalidate_state(cs->device, STATE_COLOR_KEY);
+                    if (!(texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT))
+                        device_invalidate_state(cs->device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
+                }
+
+                texture->async.src_blt_color_key = op->color_key;
+                texture->async.color_key_flags |= WINED3D_CKEY_SRC_BLT;
+                break;
+
+            case WINED3D_CKEY_SRC_OVERLAY:
+                texture->async.src_overlay_color_key = op->color_key;
+                texture->async.color_key_flags |= WINED3D_CKEY_SRC_OVERLAY;
+                break;
+        }
+    }
+    else
+    {
+        switch (op->flags)
+        {
+            case WINED3D_CKEY_DST_BLT:
+                texture->async.color_key_flags &= ~WINED3D_CKEY_DST_BLT;
+                break;
+
+            case WINED3D_CKEY_DST_OVERLAY:
+                texture->async.color_key_flags &= ~WINED3D_CKEY_DST_OVERLAY;
+                break;
+
+            case WINED3D_CKEY_SRC_BLT:
+                if (texture == cs->state.textures[0] && texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
+                    device_invalidate_state(cs->device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
+
+                texture->async.color_key_flags &= ~WINED3D_CKEY_SRC_BLT;
+                break;
+
+            case WINED3D_CKEY_SRC_OVERLAY:
+                texture->async.color_key_flags &= ~WINED3D_CKEY_SRC_OVERLAY;
+                break;
+        }
+    }
+}
+
+void wined3d_cs_emit_set_color_key(struct wined3d_cs *cs, struct wined3d_texture *texture,
+        WORD flags, const struct wined3d_color_key *color_key)
+{
+    struct wined3d_cs_set_color_key *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_COLOR_KEY;
+    op->texture = texture;
+    op->flags = flags;
+    if (color_key)
+    {
+        op->color_key = *color_key;
+        op->set = 1;
+    }
+    else
+        op->set = 0;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_set_material(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_set_material *op = data;
+
+    cs->state.material = *op->material;
+    device_invalidate_state(cs->device, STATE_MATERIAL);
+}
+
+void wined3d_cs_emit_set_material(struct wined3d_cs *cs, const struct wined3d_material *material)
+{
+    struct wined3d_cs_set_material *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_SET_MATERIAL;
+    op->material = material;
+
+    cs->ops->submit(cs);
+}
+
+static void wined3d_cs_exec_reset_state(struct wined3d_cs *cs, const void *data)
+{
+    struct wined3d_adapter *adapter = cs->device->adapter;
+    HRESULT hr;
+
+    state_cleanup(&cs->state);
+    memset(&cs->state, 0, sizeof(cs->state));
+    if (FAILED(hr = state_init(&cs->state, &cs->fb, &adapter->gl_info, &adapter->d3d_info,
+            WINED3D_STATE_NO_REF | WINED3D_STATE_INIT_DEFAULT)))
+        ERR("Failed to initialize CS state, hr %#x.\n", hr);
+}
+
+void wined3d_cs_emit_reset_state(struct wined3d_cs *cs)
+{
+    struct wined3d_cs_reset_state *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_RESET_STATE;
+
+    cs->ops->submit(cs);
+}
+
+static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void *data) =
+{
+#endif /* STAGING_CSMT */
+    /* WINED3D_CS_OP_PRESENT                    */ wined3d_cs_exec_present,
+    /* WINED3D_CS_OP_CLEAR                      */ wined3d_cs_exec_clear,
+    /* WINED3D_CS_OP_DRAW                       */ wined3d_cs_exec_draw,
+    /* WINED3D_CS_OP_SET_PREDICATION            */ wined3d_cs_exec_set_predication,
+    /* WINED3D_CS_OP_SET_VIEWPORT               */ wined3d_cs_exec_set_viewport,
+    /* WINED3D_CS_OP_SET_SCISSOR_RECT           */ wined3d_cs_exec_set_scissor_rect,
+    /* WINED3D_CS_OP_SET_RENDERTARGET_VIEW      */ wined3d_cs_exec_set_rendertarget_view,
+    /* WINED3D_CS_OP_SET_DEPTH_STENCIL_VIEW     */ wined3d_cs_exec_set_depth_stencil_view,
+    /* WINED3D_CS_OP_SET_VERTEX_DECLARATION     */ wined3d_cs_exec_set_vertex_declaration,
+    /* WINED3D_CS_OP_SET_STREAM_SOURCE          */ wined3d_cs_exec_set_stream_source,
+    /* WINED3D_CS_OP_SET_STREAM_SOURCE_FREQ     */ wined3d_cs_exec_set_stream_source_freq,
+    /* WINED3D_CS_OP_SET_STREAM_OUTPUT          */ wined3d_cs_exec_set_stream_output,
+    /* WINED3D_CS_OP_SET_INDEX_BUFFER           */ wined3d_cs_exec_set_index_buffer,
+    /* WINED3D_CS_OP_SET_CONSTANT_BUFFER        */ wined3d_cs_exec_set_constant_buffer,
+    /* WINED3D_CS_OP_SET_TEXTURE                */ wined3d_cs_exec_set_texture,
+    /* WINED3D_CS_OP_SET_SHADER_RESOURCE_VIEW   */ wined3d_cs_exec_set_shader_resource_view,
+    /* WINED3D_CS_OP_SET_SAMPLER                */ wined3d_cs_exec_set_sampler,
+    /* WINED3D_CS_OP_SET_SHADER                 */ wined3d_cs_exec_set_shader,
+    /* WINED3D_CS_OP_SET_RENDER_STATE           */ wined3d_cs_exec_set_render_state,
+    /* WINED3D_CS_OP_SET_TEXTURE_STATE          */ wined3d_cs_exec_set_texture_state,
+    /* WINED3D_CS_OP_SET_SAMPLER_STATE          */ wined3d_cs_exec_set_sampler_state,
+    /* WINED3D_CS_OP_SET_TRANSFORM              */ wined3d_cs_exec_set_transform,
+    /* WINED3D_CS_OP_SET_CLIP_PLANE             */ wined3d_cs_exec_set_clip_plane,
+    /* WINED3D_CS_OP_SET_COLOR_KEY              */ wined3d_cs_exec_set_color_key,
+    /* WINED3D_CS_OP_SET_MATERIAL               */ wined3d_cs_exec_set_material,
+    /* WINED3D_CS_OP_RESET_STATE                */ wined3d_cs_exec_reset_state,
+#if defined(STAGING_CSMT)
+    /* WINED3D_CS_OP_SET_VS_CONSTS_F            */ wined3d_cs_exec_set_vs_consts_f,
+    /* WINED3D_CS_OP_SET_VS_CONSTS_B            */ wined3d_cs_exec_set_vs_consts_b,
+    /* WINED3D_CS_OP_SET_VS_CONSTS_I            */ wined3d_cs_exec_set_vs_consts_i,
+    /* WINED3D_CS_OP_SET_PS_CONSTS_F            */ wined3d_cs_exec_set_ps_consts_f,
+    /* WINED3D_CS_OP_SET_PS_CONSTS_B            */ wined3d_cs_exec_set_ps_consts_b,
+    /* WINED3D_CS_OP_SET_PS_CONSTS_I            */ wined3d_cs_exec_set_ps_consts_i,
+    /* WINED3D_CS_OP_GLFINISH                   */ wined3d_cs_exec_glfinish,
+    /* WINED3D_CS_OP_SET_BASE_VERTEX_INDEX      */ wined3d_cs_exec_set_base_vertex_index,
+    /* WINED3D_CS_OP_SET_PRIMITIVE_TYPE         */ wined3d_cs_exec_set_primitive_type,
+    /* WINED3D_CS_OP_SET_LIGHT                  */ wined3d_cs_exec_set_light,
+    /* WINED3D_CS_OP_SET_LIGHT_ENABLE           */ wined3d_cs_exec_set_light_enable,
+    /* WINED3D_CS_OP_BLT                        */ wined3d_cs_exec_blt,
+    /* WINED3D_CS_OP_CLEAR_RTV                  */ wined3d_cs_exec_clear_rtv,
+    /* WINED3D_CS_OP_RESOURCE_CHANGED           */ wined3d_cs_exec_resource_changed,
+    /* WINED3D_CS_OP_RESOURCE_MAP               */ wined3d_cs_exec_resource_map,
+    /* WINED3D_CS_OP_RESOURCE_UNMAP             */ wined3d_cs_exec_resource_unmap,
+    /* WINED3D_CS_OP_BUFFER_SWAP_MEM            */ wined3d_cs_exec_buffer_swap_mem,
+    /* WINED3D_CS_OP_BUFFER_INVALIDATE_RANGE    */ wined3d_cs_exec_buffer_invalidate_bo_range,
+    /* WINED3D_CS_OP_BUFFER_PRELOAD             */ wined3d_cs_exec_buffer_preload,
+    /* WINED3D_CS_OP_QUERY_ISSUE                */ wined3d_cs_exec_query_issue,
+    /* WINED3D_CS_OP_QUERY_DESTROY              */ wined3d_cs_exec_query_destroy,
+    /* WINED3D_CS_OP_UPDATE_SURFACE             */ wined3d_cs_exec_update_surface,
+    /* WINED3D_CS_OP_TEXTURE_PRELOAD            */ wined3d_cs_exec_texture_preload,
+    /* WINED3D_CS_OP_SURFACE_PRELOAD            */ wined3d_cs_exec_surface_preload,
+    /* WINED3D_CS_OP_UPDATE_TEXTURE             */ wined3d_cs_exec_update_texture,
+    /* WINED3D_CS_OP_EVICT_RESOURCE             */ wined3d_cs_exec_evict_resource,
+    /* WINED3D_CS_OP_VIEW_DESTROY               */ wined3d_cs_exec_view_destroy,
+    /* WINED3D_CS_OP_VDECL_DESTROY              */ wined3d_cs_exec_vertex_declaration_destroy,
+    /* WINED3D_CS_OP_SHADER_CLEANUP             */ wined3d_cs_exec_shader_cleanup,
+    /* WINED3D_CS_OP_CREATE_VBO                 */ wined3d_cs_exec_create_vbo,
+    /* WINED3D_CS_OP_RESOURCE_CLEANUP           */ wined3d_cs_exec_resource_cleanup,
+    /* WINED3D_CS_OP_BUFFER_CLEANUP             */ wined3d_cs_exec_buffer_cleanup,
+    /* WINED3D_CS_OP_VOLUME_CLEANUP             */ wined3d_cs_exec_volume_cleanup,
+    /* WINED3D_CS_OP_SURFACE_CLEANUP            */ wined3d_cs_exec_surface_cleanup,
+    /* WINED3D_CS_OP_TEXTURE_CLEANUP            */ wined3d_cs_exec_texture_cleanup,
+    /* 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,
+    /* WINED3D_CS_OP_SAMPLER_DESTROY            */ wined3d_cs_exec_sampler_destroy,
+    /* WINED3D_CS_OP_UPDATE_SUB_RESOURCE        */ wined3d_cs_exec_update_sub_resource,
+};
+
+static inline void *_wined3d_cs_mt_require_space(struct wined3d_cs *cs, size_t size, BOOL prio)
+{
+    struct wined3d_cs_queue *queue = prio ? &cs->prio_queue : &cs->queue;
+    size_t queue_size = sizeof(queue->data) / sizeof(*queue->data);
+
+    if (queue_size - size < queue->head)
+    {
+        struct wined3d_cs_skip *skip;
+        size_t nop_size = queue_size - queue->head;
+
+        skip = _wined3d_cs_mt_require_space(cs, nop_size, prio);
+        if (nop_size < sizeof(*skip))
+        {
+            skip->opcode = WINED3D_CS_OP_NOP;
+        }
+        else
+        {
+            skip->opcode = WINED3D_CS_OP_SKIP;
+            skip->size = nop_size;
+        }
+
+        if (prio)
+            cs->ops->submit_prio(cs, nop_size);
+        else
+            cs->ops->submit(cs, nop_size);
+
+        assert(!queue->head);
+    }
+
+    while(1)
+    {
+        LONG head = queue->head;
+        LONG tail = *((volatile LONG *)&queue->tail);
+        LONG new_pos;
+        /* Empty */
+        if (head == tail)
+            break;
+        /* Head ahead of tail, take care of wrap-around */
+        new_pos = (head + size) & (WINED3D_CS_QUEUE_SIZE - 1);
+        if (head > tail && (new_pos || tail))
+            break;
+        /* Tail ahead of head, but still enough space */
+        if (new_pos < tail && new_pos)
+            break;
+
+        TRACE("Waiting for free space. Head %u, tail %u, want %u\n", head, tail,
+                (unsigned int) size);
+    }
+
+    return &queue->data[queue->head];
+}
+
+static inline void *wined3d_cs_mt_require_space(struct wined3d_cs *cs, size_t size)
+{
+    return _wined3d_cs_mt_require_space(cs, size, FALSE);
+}
+
+static inline void *wined3d_cs_mt_require_space_prio(struct wined3d_cs *cs, size_t size)
+{
+    return _wined3d_cs_mt_require_space(cs, size, TRUE);
+}
+
+/* FIXME: wined3d_device_uninit_3d() should either flush and wait, or be an
+ * OP itself. */
+static void wined3d_cs_emit_stop(struct wined3d_cs *cs)
+{
+    struct wined3d_cs_stop *op;
+
+    op = wined3d_cs_mt_require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_STOP;
+
+    wined3d_cs_mt_submit(cs, sizeof(*op));
+}
+
+static void wined3d_cs_mt_finish(struct wined3d_cs *cs)
+{
+    BOOL fence;
+
+    if (cs->thread_id == GetCurrentThreadId())
+    {
+        static BOOL once;
+        if (!once)
+        {
+            FIXME("flush_and_wait called from cs thread\n");
+            once = TRUE;
+        }
+        return;
+    }
+
+    wined3d_cs_emit_fence(cs, &fence);
+
+    /* A busy wait should be fine, we're not supposed to have to wait very
+     * long. */
+    while (!InterlockedCompareExchange(&fence, TRUE, TRUE));
+}
+
+static void wined3d_cs_mt_finish_prio(struct wined3d_cs *cs)
+{
+    BOOL fence;
+
+    if (cs->thread_id == GetCurrentThreadId())
+    {
+        static BOOL once;
+        if (!once)
+        {
+            FIXME("flush_and_wait called from cs thread\n");
+            once = TRUE;
+        }
+        return;
+    }
+
+    wined3d_cs_emit_fence_prio(cs, &fence);
+
+    /* A busy wait should be fine, we're not supposed to have to wait very
+     * long. */
+    while (!InterlockedCompareExchange(&fence, TRUE, TRUE));
+}
+
+static const struct wined3d_cs_ops wined3d_cs_mt_ops =
+{
+    wined3d_cs_mt_require_space,
     wined3d_cs_mt_require_space_prio,
     wined3d_cs_mt_submit,
     wined3d_cs_mt_submit_prio,
@@ -3294,5 +4128,80 @@
             ERR("Closing event failed.\n");
     }
 
+#else  /* STAGING_CSMT */
+};
+
+static void *wined3d_cs_st_require_space(struct wined3d_cs *cs, size_t size)
+{
+    if (size > cs->data_size)
+    {
+        void *new_data;
+
+        size = max( size, cs->data_size * 2 );
+        if (!(new_data = HeapReAlloc(GetProcessHeap(), 0, cs->data, size)))
+            return NULL;
+
+        cs->data_size = size;
+        cs->data = new_data;
+    }
+
+    return cs->data;
+}
+
+static void wined3d_cs_st_submit(struct wined3d_cs *cs)
+{
+    enum wined3d_cs_op opcode = *(const enum wined3d_cs_op *)cs->data;
+
+    wined3d_cs_op_handlers[opcode](cs, cs->data);
+}
+
+static const struct wined3d_cs_ops wined3d_cs_st_ops =
+{
+    wined3d_cs_st_require_space,
+    wined3d_cs_st_submit,
+};
+
+struct wined3d_cs *wined3d_cs_create(struct wined3d_device *device)
+{
+    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
+    struct wined3d_cs *cs;
+
+    if (!(cs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*cs))))
+        return NULL;
+
+    if (!(cs->fb.render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+            sizeof(*cs->fb.render_targets) * gl_info->limits.buffers)))
+    {
+        HeapFree(GetProcessHeap(), 0, cs);
+        return NULL;
+    }
+
+    if (FAILED(state_init(&cs->state, &cs->fb, gl_info, &device->adapter->d3d_info,
+            WINED3D_STATE_NO_REF | WINED3D_STATE_INIT_DEFAULT)))
+    {
+        HeapFree(GetProcessHeap(), 0, cs->fb.render_targets);
+        HeapFree(GetProcessHeap(), 0, cs);
+        return NULL;
+    }
+
+    cs->ops = &wined3d_cs_st_ops;
+    cs->device = device;
+
+    cs->data_size = WINED3D_INITIAL_CS_SIZE;
+    if (!(cs->data = HeapAlloc(GetProcessHeap(), 0, cs->data_size)))
+    {
+        HeapFree(GetProcessHeap(), 0, cs);
+        return NULL;
+    }
+
+    return cs;
+}
+
+void wined3d_cs_destroy(struct wined3d_cs *cs)
+{
+    state_cleanup(&cs->state);
+    HeapFree(GetProcessHeap(), 0, cs->fb.render_targets);
+    HeapFree(GetProcessHeap(), 0, cs->data);
+#endif /* STAGING_CSMT */
     HeapFree(GetProcessHeap(), 0, cs);
 }
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -198,6 +198,24 @@
     device->contexts = new_array;
 }
 
+#if !defined(STAGING_CSMT)
+void device_switch_onscreen_ds(struct wined3d_device *device,
+        struct wined3d_context *context, struct wined3d_surface *depth_stencil)
+{
+    if (device->onscreen_depth_stencil)
+    {
+        surface_load_ds_location(device->onscreen_depth_stencil, context, WINED3D_LOCATION_TEXTURE_RGB);
+
+        surface_modify_ds_location(device->onscreen_depth_stencil, WINED3D_LOCATION_TEXTURE_RGB,
+                device->onscreen_depth_stencil->ds_current_size.cx,
+                device->onscreen_depth_stencil->ds_current_size.cy);
+        wined3d_texture_decref(device->onscreen_depth_stencil->container);
+    }
+    device->onscreen_depth_stencil = depth_stencil;
+    wined3d_texture_incref(device->onscreen_depth_stencil->container);
+}
+
+#endif /* STAGING_CSMT */
 static BOOL is_full_clear(const struct wined3d_surface *target, const RECT *draw_rect, const RECT *clear_rect)
 {
     /* partial draw rect */
@@ -220,7 +238,11 @@
 {
     RECT current_rect, r;
 
+#if defined(STAGING_CSMT)
     if (ds->resource.locations & WINED3D_LOCATION_DISCARDED)
+#else  /* STAGING_CSMT */
+    if (ds->locations & WINED3D_LOCATION_DISCARDED)
+#endif /* STAGING_CSMT */
     {
         /* Depth buffer was discarded, make it entirely current in its new location since
          * there is no other place where we would get data anyway. */
@@ -228,7 +250,11 @@
         return;
     }
 
+#if defined(STAGING_CSMT)
     if (ds->resource.locations & location)
+#else  /* STAGING_CSMT */
+    if (ds->locations & location)
+#endif /* STAGING_CSMT */
         SetRect(&current_rect, 0, 0,
                 ds->ds_current_size.cx,
                 ds->ds_current_size.cy);
@@ -308,7 +334,11 @@
         if (rt && rt->resource.format->id != WINED3DFMT_NULL)
         {
             if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
+#if defined(STAGING_CSMT)
                 wined3d_resource_load_location(&rt->resource, context, rt->container->resource.draw_binding);
+#else  /* STAGING_CSMT */
+                surface_load_location(rt, context, rt->container->resource.draw_binding);
+#endif /* STAGING_CSMT */
             else
                 wined3d_surface_prepare(rt, context, rt->container->resource.draw_binding);
         }
@@ -333,8 +363,13 @@
     {
         DWORD location = render_offscreen ? fb->depth_stencil->resource->draw_binding : WINED3D_LOCATION_DRAWABLE;
 
+#if defined(STAGING_CSMT)
         if (!render_offscreen && depth_stencil != device->cs->onscreen_depth_stencil)
             wined3d_cs_switch_onscreen_ds(device->cs, context, depth_stencil);
+#else  /* STAGING_CSMT */
+        if (!render_offscreen && depth_stencil != device->onscreen_depth_stencil)
+            device_switch_onscreen_ds(device, context, depth_stencil);
+#endif /* STAGING_CSMT */
         prepare_ds_clear(depth_stencil, context, location,
                 draw_rect, rect_count, clear_rect, &ds_rect);
     }
@@ -382,8 +417,13 @@
 
             if (rt)
             {
+#if defined(STAGING_CSMT)
                 wined3d_resource_validate_location(&rt->resource, rt->container->resource.draw_binding);
                 wined3d_resource_invalidate_location(&rt->resource, ~rt->container->resource.draw_binding);
+#else  /* STAGING_CSMT */
+                surface_validate_location(rt, rt->container->resource.draw_binding);
+                surface_invalidate_location(rt, ~rt->container->resource.draw_binding);
+#endif /* STAGING_CSMT */
             }
         }
 
@@ -651,7 +691,11 @@
 }
 
 /* Context activation is done by the caller. */
+#if defined(STAGING_CSMT)
 void device_create_dummy_textures(struct wined3d_device *device, struct wined3d_context *context)
+#else  /* STAGING_CSMT */
+static void create_dummy_textures(struct wined3d_device *device, struct wined3d_context *context)
+#endif /* STAGING_CSMT */
 {
     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
     unsigned int i, j, count;
@@ -758,7 +802,11 @@
 }
 
 /* Context activation is done by the caller. */
+#if defined(STAGING_CSMT)
 void device_create_default_sampler(struct wined3d_device *device)
+#else  /* STAGING_CSMT */
+static void create_default_sampler(struct wined3d_device *device)
+#endif /* STAGING_CSMT */
 {
     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
 
@@ -923,7 +971,11 @@
     BOOL ds_enable = !!swapchain->desc.enable_auto_depth_stencil;
     unsigned int i;
 
+#if defined(STAGING_CSMT)
     if (device->state.fb.render_targets)
+#else  /* STAGING_CSMT */
+    if (device->fb.render_targets)
+#endif /* STAGING_CSMT */
     {
         for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
         {
@@ -941,7 +993,13 @@
         struct wined3d_swapchain_desc *swapchain_desc)
 {
     static const struct wined3d_color black = {0.0f, 0.0f, 0.0f, 0.0f};
+#if defined(STAGING_CSMT)
     struct wined3d_swapchain *swapchain = NULL;
+#else  /* STAGING_CSMT */
+    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
+    struct wined3d_swapchain *swapchain = NULL;
+    struct wined3d_context *context;
+#endif /* STAGING_CSMT */
     DWORD clear_flags = 0;
     HRESULT hr;
 
@@ -952,6 +1010,11 @@
     if (device->wined3d->flags & WINED3D_NO3D)
         return WINED3DERR_INVALIDCALL;
 
+#if !defined(STAGING_CSMT)
+    device->fb.render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+            sizeof(*device->fb.render_targets) * gl_info->limits.buffers);
+
+#endif /* STAGING_CSMT */
     if (FAILED(hr = device->shader_backend->shader_alloc_private(device,
             device->adapter->vertex_pipe, device->adapter->fragment_pipe)))
     {
@@ -992,8 +1055,16 @@
     device->swapchains[0] = swapchain;
     device_init_swapchain_state(device, swapchain);
 
+#if defined(STAGING_CSMT)
     /* also calls create_default_sampler */
     wined3d_cs_emit_create_dummy_textures(device->cs);
+#else  /* STAGING_CSMT */
+    context = context_acquire(device,
+            surface_from_resource(wined3d_texture_get_sub_resource(swapchain->front_buffer, 0)));
+
+    create_dummy_textures(device, context);
+    create_default_sampler(device);
+#endif /* STAGING_CSMT */
 
     device->contexts[0]->last_was_rhw = 0;
 
@@ -1005,7 +1076,11 @@
 
         case ORM_BACKBUFFER:
         {
+#if defined(STAGING_CSMT)
             if (device->contexts[0]->aux_buffers > 0)
+#else  /* STAGING_CSMT */
+            if (context_get_current()->aux_buffers > 0)
+#endif /* STAGING_CSMT */
             {
                 TRACE("Using auxiliary buffer for offscreen rendering\n");
                 device->offscreenBuffer = GL_AUX0;
@@ -1017,9 +1092,16 @@
             }
         }
     }
+#if defined(STAGING_CSMT)
     device->contexts[0]->offscreenBuffer = device->offscreenBuffer;
 
     TRACE("All defaults now set up, leaving 3D init.\n");
+#else  /* STAGING_CSMT */
+
+    TRACE("All defaults now set up, leaving 3D init.\n");
+
+    context_release(context);
+#endif /* STAGING_CSMT */
 
     /* Clear the screen */
     if (swapchain->back_buffers && swapchain->back_buffers[0])
@@ -1036,6 +1118,9 @@
     return WINED3D_OK;
 
 err_out:
+#if !defined(STAGING_CSMT)
+    HeapFree(GetProcessHeap(), 0, device->fb.render_targets);
+#endif /* STAGING_CSMT */
     HeapFree(GetProcessHeap(), 0, device->swapchains);
     device->swapchain_count = 0;
     if (device->back_buffer_view)
@@ -1093,6 +1178,10 @@
 HRESULT CDECL wined3d_device_uninit_3d(struct wined3d_device *device)
 {
     struct wined3d_resource *resource, *cursor;
+#if !defined(STAGING_CSMT)
+    const struct wined3d_gl_info *gl_info;
+    struct wined3d_context *context;
+#endif /* STAGING_CSMT */
     struct wined3d_surface *surface;
     UINT i;
 
@@ -1101,6 +1190,7 @@
     if (!device->d3d_initialized)
         return WINED3DERR_INVALIDCALL;
 
+#if defined(STAGING_CSMT)
     if (wined3d_settings.cs_multithreaded)
         device->cs->ops->finish(device->cs);
 
@@ -1139,6 +1229,83 @@
     /* FIXME: Is this in the right place??? */
     wined3d_cs_emit_delete_opengl_contexts(device->cs, device->swapchains[0]);
 
+#else  /* STAGING_CSMT */
+    /* I don't think that the interface guarantees that the device is destroyed from the same thread
+     * it was created. Thus make sure a context is active for the glDelete* calls
+     */
+    context = context_acquire(device, NULL);
+    gl_info = context->gl_info;
+
+    if (device->logo_texture)
+        wined3d_texture_decref(device->logo_texture);
+    if (device->cursor_texture)
+        wined3d_texture_decref(device->cursor_texture);
+
+    state_unbind_resources(&device->state);
+
+    /* Unload resources */
+    LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
+    {
+        TRACE("Unloading resource %p.\n", resource);
+
+        resource->resource_ops->resource_unload(resource);
+    }
+
+    wine_rb_clear(&device->samplers, device_free_sampler, NULL);
+
+    /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
+     * private data, it might contain opengl pointers
+     */
+    if (device->depth_blt_texture)
+    {
+        gl_info->gl_ops.gl.p_glDeleteTextures(1, &device->depth_blt_texture);
+        device->depth_blt_texture = 0;
+    }
+
+    /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
+    device->blitter->free_private(device);
+    device->shader_backend->shader_free_private(device);
+    destroy_dummy_textures(device, gl_info);
+    destroy_default_sampler(device);
+
+    /* Release the context again as soon as possible. In particular,
+     * releasing the render target views below may release the last reference
+     * to the swapchain associated with this context, which in turn will
+     * destroy the context. */
+    context_release(context);
+
+    /* Release the buffers (with sanity checks)*/
+    if (device->onscreen_depth_stencil)
+    {
+        surface = device->onscreen_depth_stencil;
+        device->onscreen_depth_stencil = NULL;
+        wined3d_texture_decref(surface->container);
+    }
+
+    if (device->fb.depth_stencil)
+    {
+        struct wined3d_rendertarget_view *view = device->fb.depth_stencil;
+
+        TRACE("Releasing depth/stencil view %p.\n", view);
+
+        device->fb.depth_stencil = NULL;
+        wined3d_rendertarget_view_decref(view);
+    }
+
+    if (device->auto_depth_stencil_view)
+    {
+        struct wined3d_rendertarget_view *view = device->auto_depth_stencil_view;
+
+        device->auto_depth_stencil_view = NULL;
+        if (wined3d_rendertarget_view_decref(view))
+            ERR("Something's still holding the auto depth/stencil view (%p).\n", view);
+    }
+
+    for (i = 0; i < gl_info->limits.buffers; ++i)
+    {
+        wined3d_device_set_rendertarget_view(device, i, NULL, FALSE);
+    }
+#endif /* STAGING_CSMT */
     if (device->back_buffer_view)
     {
         wined3d_rendertarget_view_decref(device->back_buffer_view);
@@ -1156,6 +1323,11 @@
     device->swapchains = NULL;
     device->swapchain_count = 0;
 
+#if !defined(STAGING_CSMT)
+    HeapFree(GetProcessHeap(), 0, device->fb.render_targets);
+    device->fb.render_targets = NULL;
+
+#endif /* STAGING_CSMT */
     device->d3d_initialized = FALSE;
 
     return WINED3D_OK;
@@ -1542,6 +1714,16 @@
     TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n",
             light->range, light->falloff, light->theta, light->phi);
 
+#if !defined(STAGING_CSMT)
+    /* Update the live definitions if the light is currently assigned a glIndex. */
+    if (object->glIndex != -1 && !device->recording)
+    {
+        if (object->OriginalParms.type != light->type)
+            device_invalidate_state(device, STATE_LIGHT_TYPE);
+        device_invalidate_state(device, STATE_ACTIVELIGHT(object->glIndex));
+    }
+
+#endif /* STAGING_CSMT */
     /* Save away the information. */
     object->OriginalParms = *light;
 
@@ -1621,9 +1803,11 @@
             FIXME("Unrecognized light type %#x.\n", light->type);
     }
 
+#if defined(STAGING_CSMT)
     if (!device->recording)
         wined3d_cs_emit_set_light(device->cs, object);
 
+#endif /* STAGING_CSMT */
     return WINED3D_OK;
 }
 
@@ -1696,6 +1880,14 @@
     {
         if (light_info->glIndex != -1)
         {
+#if !defined(STAGING_CSMT)
+            if (!device->recording)
+            {
+                device_invalidate_state(device, STATE_LIGHT_TYPE);
+                device_invalidate_state(device, STATE_ACTIVELIGHT(light_info->glIndex));
+            }
+
+#endif /* STAGING_CSMT */
             device->update_state->lights[light_info->glIndex] = NULL;
             light_info->glIndex = -1;
         }
@@ -1737,11 +1929,23 @@
                 WARN("Too many concurrently active lights\n");
                 return WINED3D_OK;
             }
+#if defined(STAGING_CSMT)
         }
     }
 
     if (!device->recording)
         wined3d_cs_emit_set_light_enable(device->cs, light_idx, enable);
+#else  /* STAGING_CSMT */
+
+            /* i == light_info->glIndex */
+            if (!device->recording)
+            {
+                device_invalidate_state(device, STATE_LIGHT_TYPE);
+                device_invalidate_state(device, STATE_ACTIVELIGHT(i));
+            }
+        }
+    }
+#endif /* STAGING_CSMT */
 
     return WINED3D_OK;
 }
@@ -1916,9 +2120,11 @@
     TRACE("device %p, base_index %d.\n", device, base_index);
 
     device->update_state->base_vertex_index = base_index;
+#if defined(STAGING_CSMT)
 
     if (!device->recording)
         wined3d_cs_emit_set_base_vertex_index(device->cs, base_index);
+#endif /* STAGING_CSMT */
 }
 
 INT CDECL wined3d_device_get_base_vertex_index(const struct wined3d_device *device)
@@ -1963,7 +2169,11 @@
             || !(texture->resource.format_flags & WINED3DFMT_FLAG_DEPTH))
         return;
     surface = surface_from_resource(texture->sub_resources[0]);
+#if defined(STAGING_CSMT)
     if (!(depth_stencil = wined3d_rendertarget_view_get_surface(state->fb.depth_stencil)))
+#else  /* STAGING_CSMT */
+    if (!(depth_stencil = wined3d_rendertarget_view_get_surface(state->fb->depth_stencil)))
+#endif /* STAGING_CSMT */
         return;
 
     wined3d_surface_blt(surface, NULL, depth_stencil, NULL, 0, NULL, WINED3D_TEXF_POINT);
@@ -2290,7 +2500,11 @@
     return device->state.sampler[WINED3D_SHADER_TYPE_VERTEX][idx];
 }
 
+#if defined(STAGING_CSMT)
 void device_invalidate_shader_constants(const struct wined3d_device *device, DWORD mask)
+#else  /* STAGING_CSMT */
+static void device_invalidate_shader_constants(const struct wined3d_device *device, DWORD mask)
+#endif /* STAGING_CSMT */
 {
     UINT i;
 
@@ -2323,8 +2537,12 @@
     }
     else
     {
+#if defined(STAGING_CSMT)
         wined3d_cs_emit_set_consts_b(device->cs, start_register, constants,
                 bool_count, WINED3D_SHADER_TYPE_VERTEX);
+#else  /* STAGING_CSMT */
+        device_invalidate_shader_constants(device, WINED3D_SHADER_CONST_VS_B);
+#endif /* STAGING_CSMT */
     }
 
     return WINED3D_OK;
@@ -2371,8 +2589,12 @@
     }
     else
     {
+#if defined(STAGING_CSMT)
         wined3d_cs_emit_set_consts_i(device->cs, start_register, constants,
                 vector4i_count, WINED3D_SHADER_TYPE_VERTEX);
+#else  /* STAGING_CSMT */
+        device_invalidate_shader_constants(device, WINED3D_SHADER_CONST_VS_I);
+#endif /* STAGING_CSMT */
     }
 
     return WINED3D_OK;
@@ -2423,8 +2645,13 @@
         memset(device->recording->changed.vertexShaderConstantsF + start_register, 1,
                 sizeof(*device->recording->changed.vertexShaderConstantsF) * vector4f_count);
     else
+#if defined(STAGING_CSMT)
         wined3d_cs_emit_set_consts_f(device->cs, start_register, constants, vector4f_count,
                 WINED3D_SHADER_TYPE_VERTEX);
+#else  /* STAGING_CSMT */
+        device->shader_backend->shader_update_float_vertex_constants(device, start_register, vector4f_count);
+
+#endif /* STAGING_CSMT */
 
     return WINED3D_OK;
 }
@@ -2559,8 +2786,12 @@
     }
     else
     {
+#if defined(STAGING_CSMT)
         wined3d_cs_emit_set_consts_b(device->cs, start_register, constants,
                 bool_count, WINED3D_SHADER_TYPE_PIXEL);
+#else  /* STAGING_CSMT */
+        device_invalidate_shader_constants(device, WINED3D_SHADER_CONST_PS_B);
+#endif /* STAGING_CSMT */
     }
 
     return WINED3D_OK;
@@ -2607,8 +2838,12 @@
     }
     else
     {
+#if defined(STAGING_CSMT)
         wined3d_cs_emit_set_consts_i(device->cs, start_register, constants,
                 vector4i_count, WINED3D_SHADER_TYPE_PIXEL);
+#else  /* STAGING_CSMT */
+        device_invalidate_shader_constants(device, WINED3D_SHADER_CONST_PS_I);
+#endif /* STAGING_CSMT */
     }
 
     return WINED3D_OK;
@@ -2660,8 +2895,12 @@
         memset(device->recording->changed.pixelShaderConstantsF + start_register, 1,
                 sizeof(*device->recording->changed.pixelShaderConstantsF) * vector4f_count);
     else
+#if defined(STAGING_CSMT)
         wined3d_cs_emit_set_consts_f(device->cs, start_register, constants, vector4f_count,
                 WINED3D_SHADER_TYPE_PIXEL);
+#else  /* STAGING_CSMT */
+        device->shader_backend->shader_update_float_pixel_constants(device, start_register, vector4f_count);
+#endif /* STAGING_CSMT */
 
     return WINED3D_OK;
 }
@@ -2821,6 +3060,7 @@
         return hr;
     }
 
+#if defined(STAGING_CSMT)
     if (wined3d_settings.cs_multithreaded)
     {
         FIXME("Waiting for cs.\n");
@@ -2828,6 +3068,7 @@
         device->cs->ops->finish(device->cs);
     }
 
+#endif /* STAGING_CSMT */
     wined3d_device_get_transform(device, WINED3D_TS_VIEW, &view_mat);
     wined3d_device_get_transform(device, WINED3D_TS_PROJECTION, &proj_mat);
     wined3d_device_get_transform(device, WINED3D_TS_WORLD_MATRIX(0), &world_mat);
@@ -3313,6 +3554,10 @@
 
 HRESULT CDECL wined3d_device_end_scene(struct wined3d_device *device)
 {
+#if !defined(STAGING_CSMT)
+    struct wined3d_context *context;
+
+#endif /* STAGING_CSMT */
     TRACE("device %p.\n", device);
 
     if (!device->inScene)
@@ -3321,6 +3566,15 @@
         return WINED3DERR_INVALIDCALL;
     }
 
+#if !defined(STAGING_CSMT)
+    context = context_acquire(device, NULL);
+    /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
+    context->gl_info->gl_ops.gl.p_glFlush();
+    /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
+     * fails. */
+    context_release(context);
+
+#endif /* STAGING_CSMT */
     device->inScene = FALSE;
     return WINED3D_OK;
 }
@@ -3328,8 +3582,10 @@
 HRESULT CDECL wined3d_device_clear(struct wined3d_device *device, DWORD rect_count,
         const RECT *rects, DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil)
 {
+#if defined(STAGING_CSMT)
     const struct wined3d_fb_state *fb = &device->state.fb;
 
+#endif /* STAGING_CSMT */
     TRACE("device %p, rect_count %u, rects %p, flags %#x, color {%.8e, %.8e, %.8e, %.8e}, depth %.8e, stencil %u.\n",
             device, rect_count, rects, flags, color->r, color->g, color->b, color->a, depth, stencil);
 
@@ -3338,12 +3594,19 @@
         WARN("Rects is %p, but rect_count is 0, ignoring clear\n", rects);
         return WINED3D_OK;
     }
+#if defined(STAGING_CSMT)
     if (rect_count && !rects)
         rect_count = 0;
 
     if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
     {
         struct wined3d_rendertarget_view *ds = fb->depth_stencil;
+#else  /* STAGING_CSMT */
+
+    if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
+    {
+        struct wined3d_rendertarget_view *ds = device->fb.depth_stencil;
+#endif /* STAGING_CSMT */
         if (!ds)
         {
             WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
@@ -3352,8 +3615,13 @@
         }
         else if (flags & WINED3DCLEAR_TARGET)
         {
+#if defined(STAGING_CSMT)
             if (ds->width < fb->render_targets[0]->width
                     || ds->height < fb->render_targets[0]->height)
+#else  /* STAGING_CSMT */
+            if (ds->width < device->fb.render_targets[0]->width
+                    || ds->height < device->fb.render_targets[0]->height)
+#endif /* STAGING_CSMT */
             {
                 WARN("Silently ignoring depth and target clear with mismatching sizes\n");
                 return WINED3D_OK;
@@ -3399,6 +3667,9 @@
         enum wined3d_primitive_type primitive_type)
 {
     GLenum gl_primitive_type, prev;
+#if !defined(STAGING_CSMT)
+
+#endif /* STAGING_CSMT */
     TRACE("device %p, primitive_type %s\n", device, debug_d3dprimitivetype(primitive_type));
 
     gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
@@ -3406,8 +3677,13 @@
     device->update_state->gl_primitive_type = gl_primitive_type;
     if (device->recording)
         device->recording->changed.primitive_type = TRUE;
+#if defined(STAGING_CSMT)
     else if (gl_primitive_type != prev)
         wined3d_cs_emit_set_primitive_type(device->cs, gl_primitive_type);
+#else  /* STAGING_CSMT */
+    else if (gl_primitive_type != prev && (gl_primitive_type == GL_POINTS || prev == GL_POINTS))
+        device_invalidate_state(device, STATE_POINT_ENABLE);
+#endif /* STAGING_CSMT */
 }
 
 void CDECL wined3d_device_get_primitive_type(const struct wined3d_device *device,
@@ -3430,6 +3706,14 @@
         return WINED3DERR_INVALIDCALL;
     }
 
+#if !defined(STAGING_CSMT)
+    if (device->state.load_base_vertex_index)
+    {
+        device->state.load_base_vertex_index = 0;
+        device_invalidate_state(device, STATE_BASEVERTEXINDEX);
+    }
+
+#endif /* STAGING_CSMT */
     wined3d_cs_emit_draw(device->cs, start_vertex, vertex_count, 0, 0, FALSE);
 
     return WINED3D_OK;
@@ -3446,6 +3730,10 @@
 
 HRESULT CDECL wined3d_device_draw_indexed_primitive(struct wined3d_device *device, UINT start_idx, UINT index_count)
 {
+#if !defined(STAGING_CSMT)
+    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
+
+#endif /* STAGING_CSMT */
     TRACE("device %p, start_idx %u, index_count %u.\n", device, start_idx, index_count);
 
     if (!device->state.index_buffer)
@@ -3464,6 +3752,15 @@
         return WINED3DERR_INVALIDCALL;
     }
 
+#if !defined(STAGING_CSMT)
+    if (!gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX] &&
+        device->state.load_base_vertex_index != device->state.base_vertex_index)
+    {
+        device->state.load_base_vertex_index = device->state.base_vertex_index;
+        device_invalidate_state(device, STATE_BASEVERTEXINDEX);
+    }
+
+#endif /* STAGING_CSMT */
     wined3d_cs_emit_draw(device->cs, start_idx, index_count, 0, 0, TRUE);
 
     return WINED3D_OK;
@@ -3479,6 +3776,7 @@
 }
 
 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
+#if defined(STAGING_CSMT)
 static void device_update_volume(struct wined3d_context *context,
         struct wined3d_volume *src_volume, struct wined3d_volume *dst_volume)
 {
@@ -3515,6 +3813,88 @@
 {
     enum wined3d_resource_type type = src_texture->resource.type;
     unsigned int level_count, i, j, src_size, dst_size, src_skip_levels = 0;
+#else  /* STAGING_CSMT */
+static HRESULT device_update_volume(struct wined3d_device *device,
+        struct wined3d_volume *src_volume, struct wined3d_volume *dst_volume)
+{
+    struct wined3d_const_bo_address data;
+    struct wined3d_map_desc src;
+    HRESULT hr;
+    struct wined3d_context *context;
+
+    TRACE("device %p, src_volume %p, dst_volume %p.\n",
+            device, src_volume, dst_volume);
+
+    if (src_volume->resource.format != dst_volume->resource.format)
+    {
+        FIXME("Source and destination formats do not match.\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+    if (src_volume->resource.width != dst_volume->resource.width
+            || src_volume->resource.height != dst_volume->resource.height
+            || src_volume->resource.depth != dst_volume->resource.depth)
+    {
+        FIXME("Source and destination sizes do not match.\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+
+    if (FAILED(hr = wined3d_volume_map(src_volume, &src, NULL, WINED3D_MAP_READONLY)))
+        return hr;
+
+    context = context_acquire(device, NULL);
+
+    /* Only a prepare, since we're uploading the entire volume. */
+    wined3d_texture_prepare_texture(dst_volume->container, context, FALSE);
+    wined3d_texture_bind_and_dirtify(dst_volume->container, context, FALSE);
+
+    data.buffer_object = 0;
+    data.addr = src.data;
+    wined3d_volume_upload_data(dst_volume, context, &data);
+    wined3d_volume_invalidate_location(dst_volume, ~WINED3D_LOCATION_TEXTURE_RGB);
+
+    context_release(context);
+
+    hr = wined3d_volume_unmap(src_volume);
+
+    return hr;
+}
+
+HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
+        struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture)
+{
+    enum wined3d_resource_type type;
+    unsigned int level_count, i, j, src_size, dst_size, src_skip_levels = 0;
+    HRESULT hr;
+    struct wined3d_context *context;
+
+    TRACE("device %p, src_texture %p, dst_texture %p.\n", device, src_texture, dst_texture);
+
+    /* Verify that the source and destination textures are non-NULL. */
+    if (!src_texture || !dst_texture)
+    {
+        WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+
+    if (src_texture->resource.pool != WINED3D_POOL_SYSTEM_MEM)
+    {
+        WARN("Source texture not in WINED3D_POOL_SYSTEM_MEM, returning WINED3DERR_INVALIDCALL.\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+    if (dst_texture->resource.pool != WINED3D_POOL_DEFAULT)
+    {
+        WARN("Destination texture not in WINED3D_POOL_DEFAULT, returning WINED3DERR_INVALIDCALL.\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+
+    /* Verify that the source and destination textures are the same type. */
+    type = src_texture->resource.type;
+    if (dst_texture->resource.type != type)
+    {
+        WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+#endif /* STAGING_CSMT */
 
     level_count = min(wined3d_texture_get_level_count(src_texture),
             wined3d_texture_get_level_count(dst_texture));
@@ -3533,7 +3913,13 @@
     }
 
     /* Make sure that the destination texture is loaded. */
+#if defined(STAGING_CSMT)
+    wined3d_texture_load(dst_texture, context, FALSE);
+#else  /* STAGING_CSMT */
+    context = context_acquire(device, NULL);
     wined3d_texture_load(dst_texture, context, FALSE);
+    context_release(context);
+#endif /* STAGING_CSMT */
 
     /* Update every surface level of the texture. */
     switch (type)
@@ -3548,7 +3934,16 @@
                 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture,
                         i + src_skip_levels));
                 dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
+#if defined(STAGING_CSMT)
                 surface_upload_from_surface(dst_surface, NULL, src_surface, NULL);
+#else  /* STAGING_CSMT */
+                hr = wined3d_device_update_surface(device, src_surface, NULL, dst_surface, NULL);
+                if (FAILED(hr))
+                {
+                    WARN("Failed to update surface, hr %#x.\n", hr);
+                    return hr;
+                }
+#endif /* STAGING_CSMT */
             }
             break;
         }
@@ -3568,7 +3963,16 @@
                             i * src_levels + j + src_skip_levels));
                     dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture,
                             i * dst_levels + j));
+#if defined(STAGING_CSMT)
                     surface_upload_from_surface(dst_surface, NULL, src_surface, NULL);
+#else  /* STAGING_CSMT */
+                    hr = wined3d_device_update_surface(device, src_surface, NULL, dst_surface, NULL);
+                    if (FAILED(hr))
+                    {
+                        WARN("Failed to update surface, hr %#x.\n", hr);
+                        return hr;
+                    }
+#endif /* STAGING_CSMT */
                 }
             }
             break;
@@ -3578,6 +3982,7 @@
         {
             for (i = 0; i < level_count; ++i)
             {
+#if defined(STAGING_CSMT)
                 device_update_volume(context,
                         volume_from_resource(wined3d_texture_get_sub_resource(src_texture,
                                 i + src_skip_levels)),
@@ -3631,6 +4036,25 @@
     }
 
     wined3d_cs_emit_update_texture(device->cs, src_texture, dst_texture);
+#else  /* STAGING_CSMT */
+                hr = device_update_volume(device,
+                        volume_from_resource(wined3d_texture_get_sub_resource(src_texture,
+                                i + src_skip_levels)),
+                        volume_from_resource(wined3d_texture_get_sub_resource(dst_texture, i)));
+                if (FAILED(hr))
+                {
+                    WARN("Failed to update volume, hr %#x.\n", hr);
+                    return hr;
+                }
+            }
+            break;
+        }
+
+        default:
+            FIXME("Unsupported texture type %#x.\n", type);
+            return WINED3DERR_INVALIDCALL;
+    }
+#endif /* STAGING_CSMT */
 
     return WINED3D_OK;
 }
@@ -3680,8 +4104,13 @@
     if (state->render_states[WINED3D_RS_ZENABLE] || state->render_states[WINED3D_RS_ZWRITEENABLE]
             || state->render_states[WINED3D_RS_STENCILENABLE])
     {
+#if defined(STAGING_CSMT)
         struct wined3d_rendertarget_view *rt = state->fb.render_targets[0];
         struct wined3d_rendertarget_view *ds = state->fb.depth_stencil;
+#else  /* STAGING_CSMT */
+        struct wined3d_rendertarget_view *rt = device->fb.render_targets[0];
+        struct wined3d_rendertarget_view *ds = device->fb.depth_stencil;
+#endif /* STAGING_CSMT */
 
         if (ds && rt && (ds->width < rt->width || ds->height < rt->height))
         {
@@ -3780,6 +4209,7 @@
         struct wined3d_surface *src_surface, const RECT *src_rect,
         struct wined3d_surface *dst_surface, const POINT *dst_point)
 {
+#if defined(STAGING_CSMT)
     const struct wined3d_format *src_format = src_surface->resource.format;
     const struct wined3d_format *dst_format = dst_surface->resource.format;
     UINT update_w, update_h;
@@ -3787,6 +4217,7 @@
     RECT r, dst_rect;
     POINT p;
 
+#endif /* STAGING_CSMT */
     TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
             device, src_surface, wine_dbgstr_rect(src_rect),
             dst_surface, wine_dbgstr_point(dst_point));
@@ -3798,6 +4229,7 @@
         return WINED3DERR_INVALIDCALL;
     }
 
+#if defined(STAGING_CSMT)
     if (src_format->id != dst_format->id)
     {
         WARN("Source and destination surfaces should have the same format.\n");
@@ -3862,6 +4294,9 @@
     wined3d_cs_emit_update_surface(device->cs, src_surface, src_rect, dst_surface, dst_point);
 
     return WINED3D_OK;
+#else  /* STAGING_CSMT */
+    return surface_upload_from_surface(dst_surface, dst_point, src_surface, src_rect);
+#endif /* STAGING_CSMT */
 }
 
 void CDECL wined3d_device_copy_resource(struct wined3d_device *device,
@@ -4034,7 +4469,17 @@
         unsigned int depth_pitch)
 {
     struct wined3d_resource *sub_resource;
+#if defined(STAGING_CSMT)
+    struct wined3d_texture *texture;
+#else  /* STAGING_CSMT */
+    const struct wined3d_gl_info *gl_info;
+    struct wined3d_const_bo_address addr;
+    struct wined3d_context *context;
     struct wined3d_texture *texture;
+    struct wined3d_surface *surface;
+    POINT dst_point;
+    RECT src_rect;
+#endif /* STAGING_CSMT */
 
     TRACE("device %p, resource %p, sub_resource_idx %u, box %p, data %p, row_pitch %u, depth_pitch %u.\n",
             device, resource, sub_resource_idx, box, data, row_pitch, depth_pitch);
@@ -4068,7 +4513,14 @@
         WARN("Invalid sub_resource_idx %u.\n", sub_resource_idx);
         return;
     }
+#if defined(STAGING_CSMT)
+
+#else  /* STAGING_CSMT */
+    surface = surface_from_resource(sub_resource);
 
+    src_rect.left = 0;
+    src_rect.top = 0;
+#endif /* STAGING_CSMT */
     if (box)
     {
         if (box->left >= box->right || box->right > sub_resource->width
@@ -4079,9 +4531,47 @@
                     box->left, box->top, box->front, box->right, box->bottom, box->back);
             return;
         }
+#if defined(STAGING_CSMT)
     }
 
     wined3d_cs_emit_update_sub_resource(device->cs, resource, sub_resource_idx, box, data, row_pitch, depth_pitch);
+#else  /* STAGING_CSMT */
+
+        src_rect.right = box->right - box->left;
+        src_rect.bottom = box->bottom - box->top;
+        dst_point.x = box->left;
+        dst_point.y = box->top;
+    }
+    else
+    {
+        src_rect.right = sub_resource->width;
+        src_rect.bottom = sub_resource->height;
+        dst_point.x = 0;
+        dst_point.y = 0;
+    }
+
+    addr.buffer_object = 0;
+    addr.addr = data;
+
+    context = context_acquire(resource->device, NULL);
+    gl_info = context->gl_info;
+
+    /* Only load the surface for partial updates. */
+    if (!dst_point.x && !dst_point.y && src_rect.right == sub_resource->width
+            && src_rect.bottom == sub_resource->height)
+        wined3d_texture_prepare_texture(texture, context, FALSE);
+    else
+        surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
+    wined3d_texture_bind_and_dirtify(texture, context, FALSE);
+
+    wined3d_surface_upload_data(surface, gl_info, resource->format,
+            &src_rect, row_pitch, &dst_point, FALSE, &addr);
+
+    context_release(context);
+
+    surface_validate_location(surface, WINED3D_LOCATION_TEXTURE_RGB);
+    surface_invalidate_location(surface, ~WINED3D_LOCATION_TEXTURE_RGB);
+#endif /* STAGING_CSMT */
 }
 
 HRESULT CDECL wined3d_device_clear_rendertarget_view(struct wined3d_device *device,
@@ -4112,8 +4602,14 @@
         rect = &r;
     }
 
+#if defined(STAGING_CSMT)
     wined3d_cs_emit_clear_rtv(device->cs, view, rect, color);
     return WINED3D_OK;
+#else  /* STAGING_CSMT */
+    resource = wined3d_texture_get_sub_resource(wined3d_texture_from_resource(resource), view->sub_resource_idx);
+
+    return surface_color_fill(surface_from_resource(resource), rect, color);
+#endif /* STAGING_CSMT */
 }
 
 struct wined3d_rendertarget_view * CDECL wined3d_device_get_rendertarget_view(const struct wined3d_device *device,
@@ -4127,6 +4623,7 @@
         return NULL;
     }
 
+#if defined(STAGING_CSMT)
     return device->state.fb.render_targets[view_idx];
 }
 
@@ -4142,6 +4639,22 @@
 {
     struct wined3d_rendertarget_view *prev;
     struct wined3d_fb_state *fb = &device->state.fb;
+#else  /* STAGING_CSMT */
+    return device->fb.render_targets[view_idx];
+}
+
+struct wined3d_rendertarget_view * CDECL wined3d_device_get_depth_stencil_view(const struct wined3d_device *device)
+{
+    TRACE("device %p.\n", device);
+
+    return device->fb.depth_stencil;
+}
+
+HRESULT CDECL wined3d_device_set_rendertarget_view(struct wined3d_device *device,
+        unsigned int view_idx, struct wined3d_rendertarget_view *view, BOOL set_viewport)
+{
+    struct wined3d_rendertarget_view *prev;
+#endif /* STAGING_CSMT */
 
     TRACE("device %p, view_idx %u, view %p, set_viewport %#x.\n",
             device, view_idx, view, set_viewport);
@@ -4181,6 +4694,7 @@
     }
 
 
+#if defined(STAGING_CSMT)
     prev = fb->render_targets[view_idx];
     if (view == prev)
         return WINED3D_OK;
@@ -4188,6 +4702,15 @@
     if (view)
         wined3d_rendertarget_view_incref(view);
     fb->render_targets[view_idx] = view;
+#else  /* STAGING_CSMT */
+    prev = device->fb.render_targets[view_idx];
+    if (view == prev)
+        return WINED3D_OK;
+
+    if (view)
+        wined3d_rendertarget_view_incref(view);
+    device->fb.render_targets[view_idx] = view;
+#endif /* STAGING_CSMT */
     wined3d_cs_emit_set_rendertarget_view(device->cs, view_idx, view);
     /* Release after the assignment, to prevent device_resource_released()
      * from seeing the surface as still in use. */
@@ -4199,6 +4722,7 @@
 
 void CDECL wined3d_device_set_depth_stencil_view(struct wined3d_device *device, struct wined3d_rendertarget_view *view)
 {
+#if defined(STAGING_CSMT)
     struct wined3d_fb_state *fb = &device->state.fb;
     struct wined3d_rendertarget_view *prev;
 
@@ -4216,6 +4740,66 @@
     wined3d_cs_emit_set_depth_stencil_view(device->cs, view);
     if (prev)
         wined3d_rendertarget_view_decref(prev);
+#else  /* STAGING_CSMT */
+    struct wined3d_rendertarget_view *prev;
+
+    TRACE("device %p, view %p.\n", device, view);
+
+    prev = device->fb.depth_stencil;
+    if (prev == view)
+    {
+        TRACE("Trying to do a NOP SetRenderTarget operation.\n");
+        return;
+    }
+
+    if ((device->fb.depth_stencil = view))
+        wined3d_rendertarget_view_incref(view);
+    wined3d_cs_emit_set_depth_stencil_view(device->cs, view);
+    if (prev)
+        wined3d_rendertarget_view_decref(prev);
+}
+
+static struct wined3d_texture *wined3d_device_create_cursor_texture(struct wined3d_device *device,
+        struct wined3d_surface *cursor_image)
+{
+    struct wined3d_sub_resource_data data;
+    struct wined3d_resource_desc desc;
+    struct wined3d_map_desc map_desc;
+    struct wined3d_texture *texture;
+    HRESULT hr;
+
+    if (FAILED(wined3d_surface_map(cursor_image, &map_desc, NULL, WINED3D_MAP_READONLY)))
+    {
+        ERR("Failed to map source surface.\n");
+        return NULL;
+    }
+
+    data.data = map_desc.data;
+    data.row_pitch = map_desc.row_pitch;
+    data.slice_pitch = map_desc.slice_pitch;
+
+    desc.resource_type = WINED3D_RTYPE_TEXTURE;
+    desc.format = WINED3DFMT_B8G8R8A8_UNORM;
+    desc.multisample_type = WINED3D_MULTISAMPLE_NONE;
+    desc.multisample_quality = 0;
+    desc.usage = WINED3DUSAGE_DYNAMIC;
+    desc.pool = WINED3D_POOL_DEFAULT;
+    desc.width = cursor_image->resource.width;
+    desc.height = cursor_image->resource.height;
+    desc.depth = 1;
+    desc.size = 0;
+
+    hr = wined3d_texture_create(device, &desc, 1, WINED3D_SURFACE_MAPPABLE,
+            &data, NULL, &wined3d_null_parent_ops, &texture);
+    wined3d_surface_unmap(cursor_image);
+    if (FAILED(hr))
+    {
+        ERR("Failed to create cursor texture.\n");
+        return NULL;
+    }
+
+    return texture;
+#endif /* STAGING_CSMT */
 }
 
 HRESULT CDECL wined3d_device_set_cursor_properties(struct wined3d_device *device,
@@ -4236,6 +4820,14 @@
 
     cursor_image = surface_from_resource(sub_resource);
 
+#if !defined(STAGING_CSMT)
+    if (device->cursor_texture)
+    {
+        wined3d_texture_decref(device->cursor_texture);
+        device->cursor_texture = NULL;
+    }
+
+#endif /* STAGING_CSMT */
     if (cursor_image->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
     {
         WARN("Surface %p has an invalid format %s.\n",
@@ -4263,6 +4855,13 @@
      * release it after setting the cursor image. Windows doesn't
      * addref the set surface, so we can't do this either without
      * creating circular refcount dependencies. */
+#if !defined(STAGING_CSMT)
+    if (!(device->cursor_texture = wined3d_device_create_cursor_texture(device, cursor_image)))
+    {
+        ERR("Failed to create cursor texture.\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+#endif /* STAGING_CSMT */
 
     if (cursor_image->resource.width == 32 && cursor_image->resource.height == 32)
     {
@@ -4367,6 +4966,12 @@
         else
             SetCursor(NULL);
     }
+#if !defined(STAGING_CSMT)
+    else if (device->cursor_texture)
+    {
+        device->bCursorVisible = show;
+    }
+#endif /* STAGING_CSMT */
 
     return oldVisible;
 }
@@ -4377,8 +4982,10 @@
 
     TRACE("device %p.\n", device);
 
+#if defined(STAGING_CSMT)
     /* The resource list is manged by the main thread, iterate here and emit commands for
      * each resource */
+#endif /* STAGING_CSMT */
     LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
     {
         TRACE("Checking resource %p for eviction.\n", resource);
@@ -4386,6 +4993,7 @@
         if (resource->pool == WINED3D_POOL_MANAGED && !resource->map_count)
         {
             TRACE("Evicting %p.\n", resource);
+#if defined(STAGING_CSMT)
             wined3d_cs_emit_evict_resource(device->cs, resource);
         }
     }
@@ -4404,6 +5012,37 @@
 
     context = context_acquire(device, NULL);
     gl_info = context->gl_info;
+#else  /* STAGING_CSMT */
+            resource->resource_ops->resource_unload(resource);
+        }
+    }
+
+    /* Invalidate stream sources, the buffer(s) may have been evicted. */
+    device_invalidate_state(device, STATE_STREAMSRC);
+}
+
+static void delete_opengl_contexts(struct wined3d_device *device, struct wined3d_swapchain *swapchain)
+{
+    struct wined3d_resource *resource, *cursor;
+    const struct wined3d_gl_info *gl_info;
+    struct wined3d_context *context;
+    struct wined3d_shader *shader;
+
+    context = context_acquire(device, NULL);
+    gl_info = context->gl_info;
+
+    LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
+    {
+        TRACE("Unloading resource %p.\n", resource);
+
+        resource->resource_ops->resource_unload(resource);
+    }
+
+    LIST_FOR_EACH_ENTRY(shader, &device->shaders, struct wined3d_shader, shader_list_entry)
+    {
+        device->shader_backend->shader_destroy(shader);
+    }
+#endif /* STAGING_CSMT */
 
     if (device->depth_blt_texture)
     {
@@ -4425,6 +5064,7 @@
 
     HeapFree(GetProcessHeap(), 0, swapchain->context);
     swapchain->context = NULL;
+#if defined(STAGING_CSMT)
     swapchain->num_contexts = 0;
 }
 
@@ -4444,6 +5084,14 @@
 
 static HRESULT create_primary_opengl_context(struct wined3d_device *device, struct wined3d_swapchain *swapchain)
 {
+#else  /* STAGING_CSMT */
+}
+
+static HRESULT create_primary_opengl_context(struct wined3d_device *device, struct wined3d_swapchain *swapchain)
+{
+    struct wined3d_context *context;
+    struct wined3d_surface *target;
+#endif /* STAGING_CSMT */
     HRESULT hr;
 
     if (FAILED(hr = device->shader_backend->shader_alloc_private(device,
@@ -4460,6 +5108,7 @@
         return hr;
     }
 
+#if defined(STAGING_CSMT)
     hr = wined3d_cs_emit_create_swapchain_context(device->cs, swapchain);
     if (FAILED(hr))
     {
@@ -4470,6 +5119,35 @@
     }
 
     wined3d_cs_emit_create_dummy_textures(device->cs);
+#else  /* STAGING_CSMT */
+    /* Recreate the primary swapchain's context */
+    swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
+    if (!swapchain->context)
+    {
+        ERR("Failed to allocate memory for swapchain context array.\n");
+        device->blitter->free_private(device);
+        device->shader_backend->shader_free_private(device);
+        return E_OUTOFMEMORY;
+    }
+
+    target = swapchain->back_buffers
+            ? surface_from_resource(wined3d_texture_get_sub_resource(swapchain->back_buffers[0], 0))
+            : surface_from_resource(wined3d_texture_get_sub_resource(swapchain->front_buffer, 0));
+    if (!(context = context_create(swapchain, target, swapchain->ds_format)))
+    {
+        WARN("Failed to create context.\n");
+        device->blitter->free_private(device);
+        device->shader_backend->shader_free_private(device);
+        HeapFree(GetProcessHeap(), 0, swapchain->context);
+        return E_FAIL;
+    }
+
+    swapchain->context[0] = context;
+    swapchain->num_contexts = 1;
+    create_dummy_textures(device, context);
+    create_default_sampler(device);
+    context_release(context);
+#endif /* STAGING_CSMT */
 
     return WINED3D_OK;
 }
@@ -4488,9 +5166,11 @@
     TRACE("device %p, swapchain_desc %p, mode %p, callback %p, reset_state %#x.\n",
             device, swapchain_desc, mode, callback, reset_state);
 
+#if defined(STAGING_CSMT)
     wined3d_cs_emit_glfinish(device->cs);
     device->cs->ops->finish(device->cs);
 
+#endif /* STAGING_CSMT */
     if (!(swapchain = wined3d_device_get_swapchain(device, 0)))
     {
         ERR("Failed to get the first implicit swapchain.\n");
@@ -4505,9 +5185,21 @@
             wined3d_texture_decref(device->logo_texture);
             device->logo_texture = NULL;
         }
+#if defined(STAGING_CSMT)
     }
 
     if (device->state.fb.render_targets)
+#else  /* STAGING_CSMT */
+        if (device->cursor_texture)
+        {
+            wined3d_texture_decref(device->cursor_texture);
+            device->cursor_texture = NULL;
+        }
+        state_unbind_resources(&device->state);
+    }
+
+    if (device->fb.render_targets)
+#endif /* STAGING_CSMT */
     {
         for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
         {
@@ -4516,6 +5208,7 @@
     }
     wined3d_device_set_depth_stencil_view(device, NULL);
 
+#if defined(STAGING_CSMT)
     if (reset_state)
     {
         state_unbind_resources(&device->state);
@@ -4525,6 +5218,12 @@
     {
         wined3d_texture_decref(device->cs->onscreen_depth_stencil->container);
         device->cs->onscreen_depth_stencil = NULL;
+#else  /* STAGING_CSMT */
+    if (device->onscreen_depth_stencil)
+    {
+        wined3d_texture_decref(device->onscreen_depth_stencil->container);
+        device->onscreen_depth_stencil = NULL;
+#endif /* STAGING_CSMT */
     }
 
     if (reset_state)
@@ -4537,6 +5236,7 @@
         }
     }
 
+#if defined(STAGING_CSMT)
     /* Free implicit resources and wait for the command stream before modifying
      * swapchain parameters. After modifying the swapchain parameters a new GL
      * context may be acquired by the worker thread. This causes problems in the
@@ -4558,6 +5258,7 @@
     }
     device->cs->ops->finish(device->cs);
 
+#endif /* STAGING_CSMT */
     TRACE("New params:\n");
     TRACE("backbuffer_width %u\n", swapchain_desc->backbuffer_width);
     TRACE("backbuffer_height %u\n", swapchain_desc->backbuffer_height);
@@ -4684,6 +5385,13 @@
             swapchain_desc->multisample_type, swapchain_desc->multisample_quality)))
         return hr;
 
+#if !defined(STAGING_CSMT)
+    if (device->auto_depth_stencil_view)
+    {
+        wined3d_rendertarget_view_decref(device->auto_depth_stencil_view);
+        device->auto_depth_stencil_view = NULL;
+    }
+#endif /* STAGING_CSMT */
     if (swapchain->desc.enable_auto_depth_stencil)
     {
         struct wined3d_resource_desc texture_desc;
@@ -4726,6 +5434,13 @@
         wined3d_device_set_depth_stencil_view(device, device->auto_depth_stencil_view);
     }
 
+#if !defined(STAGING_CSMT)
+    if (device->back_buffer_view)
+    {
+        wined3d_rendertarget_view_decref(device->back_buffer_view);
+        device->back_buffer_view = NULL;
+    }
+#endif /* STAGING_CSMT */
     if (swapchain->desc.backbuffer_count && FAILED(hr = wined3d_rendertarget_view_create_from_surface(
             surface_from_resource(wined3d_texture_get_sub_resource(swapchain->back_buffers[0], 0)),
             NULL, &wined3d_null_parent_ops, &device->back_buffer_view)))
@@ -4746,12 +5461,20 @@
         }
         wined3d_cs_emit_reset_state(device->cs);
         state_cleanup(&device->state);
+#if defined(STAGING_CSMT)
         memset(&device->state, 0, sizeof(device->state));
 
         if (device->d3d_initialized)
             delete_opengl_contexts(device, swapchain);
 
         if (FAILED(hr = state_init(&device->state, &device->adapter->gl_info,
+#else  /* STAGING_CSMT */
+
+        if (device->d3d_initialized)
+            delete_opengl_contexts(device, swapchain);
+
+        if (FAILED(hr = state_init(&device->state, &device->fb, &device->adapter->gl_info,
+#endif /* STAGING_CSMT */
                 &device->adapter->d3d_info, WINED3D_STATE_INIT_DEFAULT)))
             ERR("Failed to initialize device state, hr %#x.\n", hr);
         device->update_state = &device->state;
@@ -4760,6 +5483,7 @@
     }
     else if (device->back_buffer_view)
     {
+#if defined(STAGING_CSMT)
         struct wined3d_state *state = &device->state;
 
         wined3d_device_set_rendertarget_view(device, 0, device->back_buffer_view, FALSE);
@@ -4775,6 +5499,24 @@
         state->scissor_rect.left = 0;
         state->scissor_rect.right = swapchain->desc.backbuffer_width;
         state->scissor_rect.bottom = swapchain->desc.backbuffer_height;
+#else  /* STAGING_CSMT */
+        struct wined3d_rendertarget_view *view = device->back_buffer_view;
+        struct wined3d_state *state = &device->state;
+
+        wined3d_device_set_rendertarget_view(device, 0, view, FALSE);
+
+        /* Note the min_z / max_z is not reset. */
+        state->viewport.x = 0;
+        state->viewport.y = 0;
+        state->viewport.width = view->width;
+        state->viewport.height = view->height;
+        wined3d_cs_emit_set_viewport(device->cs, &state->viewport);
+
+        state->scissor_rect.top = 0;
+        state->scissor_rect.left = 0;
+        state->scissor_rect.right = view->width;
+        state->scissor_rect.bottom = view->height;
+#endif /* STAGING_CSMT */
         wined3d_cs_emit_set_scissor_rect(device->cs, &state->scissor_rect);
     }
 
@@ -4850,6 +5592,10 @@
 
     TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
 
+#if !defined(STAGING_CSMT)
+    context_resource_released(device, resource, type);
+
+#endif /* STAGING_CSMT */
     switch (type)
     {
         case WINED3D_RTYPE_SURFACE:
@@ -4860,6 +5606,7 @@
 
                 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
                 {
+#if defined(STAGING_CSMT)
                     if (wined3d_rendertarget_view_get_surface(device->state.fb.render_targets[i]) == surface)
                     {
                         ERR("Surface %p is still in use as render target %u.\n", surface, i);
@@ -4871,6 +5618,19 @@
                 {
                     ERR("Surface %p is still in use as depth/stencil buffer.\n", surface);
                     device->state.fb.depth_stencil = NULL;
+#else  /* STAGING_CSMT */
+                    if (wined3d_rendertarget_view_get_surface(device->fb.render_targets[i]) == surface)
+                    {
+                        ERR("Surface %p is still in use as render target %u.\n", surface, i);
+                        device->fb.render_targets[i] = NULL;
+                    }
+                }
+
+                if (wined3d_rendertarget_view_get_surface(device->fb.depth_stencil) == surface)
+                {
+                    ERR("Surface %p is still in use as depth/stencil buffer.\n", surface);
+                    device->fb.depth_stencil = NULL;
+#endif /* STAGING_CSMT */
                 }
             }
             break;
@@ -5033,7 +5793,11 @@
 
     device->blitter = adapter->blitter;
 
+#if defined(STAGING_CSMT)
     if (FAILED(hr = state_init(&device->state, &adapter->gl_info,
+#else  /* STAGING_CSMT */
+    if (FAILED(hr = state_init(&device->state, &device->fb, &adapter->gl_info,
+#endif /* STAGING_CSMT */
             &adapter->d3d_info, WINED3D_STATE_INIT_DEFAULT)))
     {
         ERR("Failed to initialize device state, hr %#x.\n", hr);
@@ -5132,6 +5896,7 @@
     else
         return CallWindowProcA(proc, window, message, wparam, lparam);
 }
+#if defined(STAGING_CSMT)
 
 /* Context activation is done by the caller */
 struct wined3d_gl_bo *wined3d_device_get_bo(struct wined3d_device *device, UINT size, GLenum gl_usage,
@@ -5185,3 +5950,4 @@
 
     wined3d_device_destroy_bo(device, context, bo);
 }
+#endif /* STAGING_CSMT */
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -5557,9 +5557,15 @@
     DebugBreak();
 }
 
+#if defined(STAGING_CSMT)
 /* Helper functions for providing vertex data to opengl. The arrays are initialized based on
  * the extension detection and are used in draw_strided_slow
  */
+#else  /* STAGING_CSMT */
+/* Helper functions for providing vertex data to opengl. The arrays are initialized based on
+ * the extension detection and are used in drawStridedSlow
+ */
+#endif /* STAGING_CSMT */
 static void WINE_GLAPI position_d3dcolor(const void *data)
 {
     DWORD pos = *((const DWORD *)data);
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -36,7 +36,11 @@
 #include <math.h>
 
 /* Context activation is done by the caller. */
+#if defined(STAGING_CSMT)
 static void draw_strided_fast(const struct wined3d_gl_info *gl_info, GLenum primitive_type, UINT count, UINT idx_size,
+#else  /* STAGING_CSMT */
+static void drawStridedFast(const struct wined3d_gl_info *gl_info, GLenum primitive_type, UINT count, UINT idx_size,
+#endif /* STAGING_CSMT */
         const void *idx_data, UINT start_idx, INT base_vertex_index, UINT start_instance, UINT instance_count)
 {
     if (idx_size)
@@ -95,7 +99,11 @@
  */
 
 /* Context activation is done by the caller. */
+#if defined(STAGING_CSMT)
 static void draw_strided_slow(const struct wined3d_state *state, struct wined3d_context *context,
+#else  /* STAGING_CSMT */
+static void drawStridedSlow(const struct wined3d_device *device, struct wined3d_context *context,
+#endif /* STAGING_CSMT */
         const struct wined3d_stream_info *si, UINT NumVertexes, GLenum glPrimType,
         const void *idxData, UINT idxSize, UINT startIdx)
 {
@@ -103,6 +111,9 @@
     const WORD                *pIdxBufS     = NULL;
     const DWORD               *pIdxBufL     = NULL;
     UINT vx_index;
+#if !defined(STAGING_CSMT)
+    const struct wined3d_state *state = &device->state;
+#endif /* STAGING_CSMT */
     LONG SkipnStrides = startIdx;
     BOOL pixelShader = use_ps(state);
     BOOL specular_fog = FALSE;
@@ -452,7 +463,11 @@
 }
 
 /* Context activation is done by the caller. */
+#if defined(STAGING_CSMT)
 static void draw_strided_slow_vs(struct wined3d_context *context, const struct wined3d_state *state,
+#else  /* STAGING_CSMT */
+static void drawStridedSlowVs(struct wined3d_context *context, const struct wined3d_state *state,
+#endif /* STAGING_CSMT */
         const struct wined3d_stream_info *si, UINT numberOfVertices, GLenum glPrimitiveType,
         const void *idxData, UINT idxSize, UINT startIdx)
 {
@@ -509,7 +524,11 @@
 }
 
 /* Context activation is done by the caller. */
+#if defined(STAGING_CSMT)
 static void draw_strided_instanced(struct wined3d_context *context, const struct wined3d_state *state,
+#else  /* STAGING_CSMT */
+static void drawStridedInstanced(struct wined3d_context *context, const struct wined3d_state *state,
+#endif /* STAGING_CSMT */
         const struct wined3d_stream_info *si, UINT numberOfVertices, GLenum glPrimitiveType,
         const void *idxData, UINT idxSize, UINT startIdx, UINT base_vertex_index, UINT instance_count)
 {
@@ -594,10 +613,17 @@
 }
 
 /* Routine common to the draw primitive and draw indexed primitive routines */
+#if defined(STAGING_CSMT)
 void draw_primitive(struct wined3d_device *device, const struct wined3d_state *state,
         UINT start_idx, UINT index_count, UINT start_instance, UINT instance_count,
         BOOL indexed)
 {
+#else  /* STAGING_CSMT */
+void draw_primitive(struct wined3d_device *device, UINT start_idx, UINT index_count,
+        UINT start_instance, UINT instance_count, BOOL indexed)
+{
+    const struct wined3d_state *state = &device->state;
+#endif /* STAGING_CSMT */
     const struct wined3d_stream_info *stream_info;
     struct wined3d_event_query *ib_query = NULL;
     struct wined3d_stream_info si_emulated;
@@ -610,7 +636,11 @@
 
     if (!index_count) return;
 
+#if defined(STAGING_CSMT)
     context = context_acquire(device, wined3d_rendertarget_view_get_surface(state->fb.render_targets[0]));
+#else  /* STAGING_CSMT */
+    context = context_acquire(device, wined3d_rendertarget_view_get_surface(device->fb.render_targets[0]));
+#endif /* STAGING_CSMT */
     if (!context->valid)
     {
         context_release(context);
@@ -621,6 +651,7 @@
 
     for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
     {
+#if defined(STAGING_CSMT)
         struct wined3d_surface *target = wined3d_rendertarget_view_get_surface(state->fb.render_targets[i]);
         if (target && target->resource.format->id != WINED3DFMT_NULL)
         {
@@ -628,6 +659,15 @@
             {
                 wined3d_resource_load_location(&target->resource, context, target->container->resource.draw_binding);
                 wined3d_resource_invalidate_location(&target->resource, ~target->container->resource.draw_binding);
+#else  /* STAGING_CSMT */
+        struct wined3d_surface *target = wined3d_rendertarget_view_get_surface(device->fb.render_targets[i]);
+        if (target && target->resource.format->id != WINED3DFMT_NULL)
+        {
+            if (state->render_states[WINED3D_RS_COLORWRITEENABLE])
+            {
+                surface_load_location(target, context, target->container->resource.draw_binding);
+                surface_invalidate_location(target, ~target->container->resource.draw_binding);
+#endif /* STAGING_CSMT */
             }
             else
             {
@@ -636,6 +676,7 @@
         }
     }
 
+#if defined(STAGING_CSMT)
     if (state->fb.depth_stencil)
     {
         /* Note that this depends on the context_acquire() call above to set
@@ -655,6 +696,27 @@
                 wined3d_cs_switch_onscreen_ds(device->cs, context, ds);
 
             if (ds->resource.locations & location)
+#else  /* STAGING_CSMT */
+    if (device->fb.depth_stencil)
+    {
+        /* Note that this depends on the context_acquire() call above to set
+         * context->render_offscreen properly. We don't currently take the
+         * Z-compare function into account, but we could skip loading the
+         * depthstencil for D3DCMP_NEVER and D3DCMP_ALWAYS as well. Also note
+         * that we never copy the stencil data.*/
+        DWORD location = context->render_offscreen ? device->fb.depth_stencil->resource->draw_binding
+                : WINED3D_LOCATION_DRAWABLE;
+        struct wined3d_surface *ds = wined3d_rendertarget_view_get_surface(device->fb.depth_stencil);
+
+        if (state->render_states[WINED3D_RS_ZWRITEENABLE] || state->render_states[WINED3D_RS_ZENABLE])
+        {
+            RECT current_rect, draw_rect, r;
+
+            if (!context->render_offscreen && ds != device->onscreen_depth_stencil)
+                device_switch_onscreen_ds(device, context, ds);
+
+            if (ds->locations & location)
+#endif /* STAGING_CSMT */
                 SetRect(&current_rect, 0, 0, ds->ds_current_size.cx, ds->ds_current_size.cy);
             else
                 SetRectEmpty(&current_rect);
@@ -671,6 +733,7 @@
             wined3d_surface_prepare(ds, context, location);
     }
 
+#if defined(STAGING_CSMT)
     if (!context_apply_draw_state(context, device, state))
     {
         context_release(context);
@@ -681,6 +744,18 @@
     if (state->fb.depth_stencil && state->render_states[WINED3D_RS_ZWRITEENABLE])
     {
         struct wined3d_surface *ds = wined3d_rendertarget_view_get_surface(state->fb.depth_stencil);
+#else  /* STAGING_CSMT */
+    if (!context_apply_draw_state(context, device))
+    {
+        context_release(context);
+        WARN("Unable to apply draw state, skipping draw.\n");
+        return;
+    }
+
+    if (device->fb.depth_stencil && state->render_states[WINED3D_RS_ZWRITEENABLE])
+    {
+        struct wined3d_surface *ds = wined3d_rendertarget_view_get_surface(device->fb.depth_stencil);
+#endif /* STAGING_CSMT */
         DWORD location = context->render_offscreen ? ds->container->resource.draw_binding : WINED3D_LOCATION_DRAWABLE;
 
         surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
@@ -763,6 +838,7 @@
             else
                 WARN_(d3d_perf)("Using immediate mode with vertex shaders for half float emulation.\n");
 
+#if defined(STAGING_CSMT)
             draw_strided_slow_vs(context, state, stream_info, index_count,
                     state->gl_primitive_type, idx_data, idx_size, start_idx);
         }
@@ -785,6 +861,30 @@
     else
     {
         draw_strided_fast(gl_info, state->gl_primitive_type, index_count, idx_size, idx_data,
+#else  /* STAGING_CSMT */
+            drawStridedSlowVs(context, state, stream_info, index_count,
+                    state->gl_primitive_type, idx_data, idx_size, start_idx);
+        }
+        else
+        {
+            if (context->d3d_info->ffp_generic_attributes)
+                drawStridedSlowVs(context, state, stream_info, index_count,
+                    state->gl_primitive_type, idx_data, idx_size, start_idx);
+            else
+                drawStridedSlow(device, context, stream_info, index_count,
+                        state->gl_primitive_type, idx_data, idx_size, start_idx);
+        }
+    }
+    else if (!gl_info->supported[ARB_INSTANCED_ARRAYS] && instance_count)
+    {
+        /* Instancing emulation by mixing immediate mode and arrays. */
+        drawStridedInstanced(context, state, stream_info, index_count, state->gl_primitive_type,
+                idx_data, idx_size, start_idx, state->base_vertex_index, instance_count);
+    }
+    else
+    {
+        drawStridedFast(gl_info, state->gl_primitive_type, index_count, idx_size, idx_data,
+#endif /* STAGING_CSMT */
                 start_idx, state->base_vertex_index, start_instance, instance_count);
     }
 
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -1623,9 +1623,17 @@
         const struct wined3d_shader_reg_maps *reg_maps, const struct shader_glsl_ctx_priv *ctx_priv)
 {
     const struct wined3d_shader_version *version = &reg_maps->shader_version;
+#if defined(STAGING_CSMT)
     const struct vs_compile_args *vs_args = ctx_priv->cur_vs_args;
     const struct ps_compile_args *ps_args = ctx_priv->cur_ps_args;
     const struct wined3d_gl_info *gl_info = context->gl_info;
+#else  /* STAGING_CSMT */
+    const struct wined3d_state *state = &shader->device->state;
+    const struct vs_compile_args *vs_args = ctx_priv->cur_vs_args;
+    const struct ps_compile_args *ps_args = ctx_priv->cur_ps_args;
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+    const struct wined3d_fb_state *fb = &shader->device->fb;
+#endif /* STAGING_CSMT */
     unsigned int i, extra_constants_needed = 0;
     const struct wined3d_shader_lconst *lconst;
     const char *prefix;
@@ -1928,7 +1936,11 @@
         {
             UINT in_count = min(vec4_varyings(version->major, gl_info), shader->limits->packed_input);
 
+#if defined(STAGING_CSMT)
             if (ps_args->vp_mode == vertexshader)
+#else  /* STAGING_CSMT */
+            if (use_vs(state))
+#endif /* STAGING_CSMT */
                 declare_in_varying(gl_info, buffer, FALSE, "vec4 %s_link[%u];\n", prefix, in_count);
             shader_addline(buffer, "vec4 %s_in[%u];\n", prefix, in_count);
         }
@@ -1969,6 +1981,7 @@
             }
             else
             {
+#if defined(STAGING_CSMT)
                 /* This happens because we do not have proper tracking of the
                  * constant registers that are actually used, only the max
                  * limit of the shader version.
@@ -1977,6 +1990,23 @@
                  * it and just create the uniform.
                  */
                 FIXME("Cannot find a free uniform for vpos correction params\n");
+#else  /* STAGING_CSMT */
+                float ycorrection[] =
+                {
+                    context->render_offscreen ? 0.0f : fb->render_targets[0]->height,
+                    context->render_offscreen ? 1.0f : -1.0f,
+                    0.0f,
+                    0.0f,
+                };
+
+                /* This happens because we do not have proper tracking of the
+                 * constant registers that are actually used, only the max
+                 * limit of the shader version. */
+                FIXME("Cannot find a free uniform for vpos correction params\n");
+                shader_addline(buffer, "const vec4 ycorrection = ");
+                shader_glsl_append_imm_vec4(buffer, ycorrection);
+                shader_addline(buffer, ";\n");
+#endif /* STAGING_CSMT */
             }
             shader_addline(buffer, "vec4 vpos;\n");
         }
diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c
--- a/dlls/wined3d/query.c
+++ b/dlls/wined3d/query.c
@@ -233,6 +233,7 @@
     return refcount;
 }
 
+#if defined(STAGING_CSMT)
 void wined3d_query_destroy(struct wined3d_query *query)
 {
     /* Queries are specific to the GL context that created them. Not
@@ -263,6 +264,7 @@
     HeapFree(GetProcessHeap(), 0, query);
 }
 
+#endif /* STAGING_CSMT */
 ULONG CDECL wined3d_query_decref(struct wined3d_query *query)
 {
     ULONG refcount = InterlockedDecrement(&query->ref);
@@ -270,7 +272,38 @@
     TRACE("%p decreasing refcount to %u.\n", query, refcount);
 
     if (!refcount)
+#if defined(STAGING_CSMT)
         wined3d_cs_emit_query_destroy(query->device->cs, query);
+#else  /* STAGING_CSMT */
+    {
+        /* Queries are specific to the GL context that created them. Not
+         * deleting the query will obviously leak it, but that's still better
+         * than potentially deleting a different query with the same id in this
+         * context, and (still) leaking the actual query. */
+        if (query->type == WINED3D_QUERY_TYPE_EVENT)
+        {
+            struct wined3d_event_query *event_query = query->extendedData;
+            if (event_query) wined3d_event_query_destroy(event_query);
+        }
+        else if (query->type == WINED3D_QUERY_TYPE_OCCLUSION)
+        {
+            struct wined3d_occlusion_query *oq = query->extendedData;
+
+            if (oq->context) context_free_occlusion_query(oq);
+            HeapFree(GetProcessHeap(), 0, query->extendedData);
+        }
+        else if (query->type == WINED3D_QUERY_TYPE_TIMESTAMP)
+        {
+            struct wined3d_timestamp_query *tq = query->extendedData;
+
+            if (tq->context)
+                context_free_timestamp_query(tq);
+            HeapFree(GetProcessHeap(), 0, query->extendedData);
+        }
+
+        HeapFree(GetProcessHeap(), 0, query);
+    }
+#endif /* STAGING_CSMT */
 
     return refcount;
 }
@@ -295,6 +328,7 @@
 {
     TRACE("query %p, flags %#x.\n", query, flags);
 
+#if defined(STAGING_CSMT)
     if (flags & WINED3DISSUE_END)
         query->counter_main++;
 
@@ -306,6 +340,9 @@
         query->state = QUERY_SIGNALLED;
 
     return WINED3D_OK;
+#else  /* STAGING_CSMT */
+    return query->query_ops->query_issue(query, flags);
+#endif /* STAGING_CSMT */
 }
 
 static void fill_query_data(void *out, unsigned int out_size, const void *result, unsigned int result_size)
@@ -316,10 +353,25 @@
 static HRESULT wined3d_occlusion_query_ops_get_data(struct wined3d_query *query,
         void *data, DWORD size, DWORD flags)
 {
+#if defined(STAGING_CSMT)
     struct wined3d_device *device = query->device;
     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
     struct wined3d_occlusion_query *oq = query->extendedData;
     GLuint samples;
+#else  /* STAGING_CSMT */
+    struct wined3d_occlusion_query *oq = query->extendedData;
+    struct wined3d_device *device = query->device;
+    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
+    struct wined3d_context *context;
+    GLuint available;
+    GLuint samples;
+    HRESULT res;
+
+    TRACE("query %p, data %p, size %#x, flags %#x.\n", query, data, size, flags);
+
+    if (!oq->context)
+        query->state = QUERY_CREATED;
+#endif /* STAGING_CSMT */
 
     if (query->state == QUERY_CREATED)
     {
@@ -330,8 +382,10 @@
         return S_OK;
     }
 
+#if defined(STAGING_CSMT)
     TRACE("(%p) : type D3DQUERY_OCCLUSION, data %p, size %#x, flags %#x.\n", query, data, size, flags);
 
+#endif /* STAGING_CSMT */
     if (query->state == QUERY_BUILDING)
     {
         /* Msdn says this returns an error, but our tests show that S_FALSE is returned */
@@ -347,6 +401,7 @@
         return S_OK;
     }
 
+#if defined(STAGING_CSMT)
     if (!wined3d_settings.cs_multithreaded)
     {
         if (!query->query_ops->query_poll(query))
@@ -378,6 +433,14 @@
         FIXME("%p Wrong thread, returning 1.\n", query);
         oq->samples = 1;
         return TRUE;
+#else  /* STAGING_CSMT */
+    if (oq->context->tid != GetCurrentThreadId())
+    {
+        FIXME("%p Wrong thread, returning 1.\n", query);
+        samples = 1;
+        fill_query_data(data, size, &samples, sizeof(samples));
+        return S_OK;
+#endif /* STAGING_CSMT */
     }
 
     context = context_acquire(query->device, oq->context->current_rt);
@@ -388,6 +451,7 @@
 
     if (available)
     {
+#if defined(STAGING_CSMT)
         GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT, &samples));
         checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT)");
         TRACE("Returning %d samples.\n", samples);
@@ -459,6 +523,69 @@
 
     if (data)
         fill_query_data(data, dwSize, &ret, sizeof(ret));
+#else  /* STAGING_CSMT */
+        if (size)
+        {
+            GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT, &samples));
+            checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT)");
+            TRACE("Returning %d samples.\n", samples);
+            fill_query_data(data, size, &samples, sizeof(samples));
+        }
+        res = S_OK;
+    }
+    else
+    {
+        res = S_FALSE;
+    }
+
+    context_release(context);
+
+    return res;
+}
+
+static HRESULT wined3d_event_query_ops_get_data(struct wined3d_query *query,
+        void *data, DWORD size, DWORD flags)
+{
+    struct wined3d_event_query *event_query = query->extendedData;
+    BOOL signaled;
+    enum wined3d_event_query_result ret;
+
+    TRACE("query %p, data %p, size %#x, flags %#x.\n", query, data, size, flags);
+
+    if (!data || !size) return S_OK;
+    if (!event_query)
+    {
+        WARN("Event query not supported by GL, reporting GPU idle.\n");
+        signaled = TRUE;
+        fill_query_data(data, size, &signaled, sizeof(signaled));
+        return S_OK;
+    }
+
+    ret = wined3d_event_query_test(event_query, query->device);
+    switch(ret)
+    {
+        case WINED3D_EVENT_QUERY_OK:
+        case WINED3D_EVENT_QUERY_NOT_STARTED:
+            signaled = TRUE;
+            fill_query_data(data, size, &signaled, sizeof(signaled));
+            break;
+
+        case WINED3D_EVENT_QUERY_WAITING:
+            signaled = FALSE;
+            fill_query_data(data, size, &signaled, sizeof(signaled));
+            break;
+
+        case WINED3D_EVENT_QUERY_WRONG_THREAD:
+            FIXME("(%p) Wrong thread, reporting GPU idle.\n", query);
+            signaled = TRUE;
+            fill_query_data(data, size, &signaled, sizeof(signaled));
+            break;
+
+        case WINED3D_EVENT_QUERY_ERROR:
+            ERR("The GL event query failed, returning D3DERR_INVALIDCALL\n");
+            return WINED3DERR_INVALIDCALL;
+    }
+#endif /* STAGING_CSMT */
 
     return S_OK;
 }
@@ -477,7 +604,11 @@
     return query->type;
 }
 
+#if defined(STAGING_CSMT)
 static BOOL wined3d_event_query_ops_issue(struct wined3d_query *query, DWORD flags)
+#else  /* STAGING_CSMT */
+static HRESULT wined3d_event_query_ops_issue(struct wined3d_query *query, DWORD flags)
+#endif /* STAGING_CSMT */
 {
     TRACE("query %p, flags %#x.\n", query, flags);
 
@@ -487,6 +618,7 @@
         struct wined3d_event_query *event_query = query->extendedData;
 
         /* Faked event query support */
+#if defined(STAGING_CSMT)
         if (!event_query) return FALSE;
 
         wined3d_event_query_issue(event_query, query->device);
@@ -505,6 +637,30 @@
     struct wined3d_device *device = query->device;
     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
     BOOL poll = FALSE;
+#else  /* STAGING_CSMT */
+        if (!event_query) return WINED3D_OK;
+
+        wined3d_event_query_issue(event_query, query->device);
+    }
+    else if (flags & WINED3DISSUE_BEGIN)
+    {
+        /* Started implicitly at device creation */
+        ERR("Event query issued with START flag - what to do?\n");
+    }
+
+    if (flags & WINED3DISSUE_BEGIN)
+        query->state = QUERY_BUILDING;
+    else
+        query->state = QUERY_SIGNALLED;
+
+    return WINED3D_OK;
+}
+
+static HRESULT wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DWORD flags)
+{
+    struct wined3d_device *device = query->device;
+    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
+#endif /* STAGING_CSMT */
 
     TRACE("query %p, flags %#x.\n", query, flags);
 
@@ -516,7 +672,11 @@
         /* This is allowed according to msdn and our tests. Reset the query and restart */
         if (flags & WINED3DISSUE_BEGIN)
         {
+#if defined(STAGING_CSMT)
             if (oq->started)
+#else  /* STAGING_CSMT */
+            if (query->state == QUERY_BUILDING)
+#endif /* STAGING_CSMT */
             {
                 if (oq->context->tid != GetCurrentThreadId())
                 {
@@ -545,7 +705,9 @@
             checkGLcall("glBeginQuery()");
 
             context_release(context);
+#if defined(STAGING_CSMT)
             oq->started = TRUE;
+#endif /* STAGING_CSMT */
         }
         if (flags & WINED3DISSUE_END)
         {
@@ -553,7 +715,11 @@
              * our tests show that it returns OK. But OpenGL doesn't like it, so avoid
              * generating an error
              */
+#if defined(STAGING_CSMT)
             if (oq->started)
+#else  /* STAGING_CSMT */
+            if (query->state == QUERY_BUILDING)
+#endif /* STAGING_CSMT */
             {
                 if (oq->context->tid != GetCurrentThreadId())
                 {
@@ -567,10 +733,15 @@
                     checkGLcall("glEndQuery()");
 
                     context_release(context);
+#if defined(STAGING_CSMT)
                     poll = TRUE;
                 }
             }
             oq->started = FALSE;
+#else  /* STAGING_CSMT */
+                }
+            }
+#endif /* STAGING_CSMT */
         }
     }
     else
@@ -578,6 +749,7 @@
         FIXME("%p Occlusion queries not supported.\n", query);
     }
 
+#if defined(STAGING_CSMT)
     return poll;
 }
 
@@ -636,6 +808,47 @@
         FIXME("%p Wrong thread, returning 1.\n", query);
         tq->timestamp = 1;
         return TRUE;
+#else  /* STAGING_CSMT */
+    if (flags & WINED3DISSUE_BEGIN)
+        query->state = QUERY_BUILDING;
+    else
+        query->state = QUERY_SIGNALLED;
+
+    return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL.    */
+}
+
+static HRESULT wined3d_timestamp_query_ops_get_data(struct wined3d_query *query,
+        void *data, DWORD size, DWORD flags)
+{
+    struct wined3d_timestamp_query *tq = query->extendedData;
+    struct wined3d_device *device = query->device;
+    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
+    struct wined3d_context *context;
+    GLuint available;
+    GLuint64 timestamp;
+    HRESULT res;
+
+    TRACE("query %p, data %p, size %#x, flags %#x.\n", query, data, size, flags);
+
+    if (!tq->context)
+        query->state = QUERY_CREATED;
+
+    if (query->state == QUERY_CREATED)
+    {
+        /* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves. */
+        TRACE("Query wasn't yet started, returning S_OK.\n");
+        timestamp = 0;
+        fill_query_data(data, size, &timestamp, sizeof(timestamp));
+        return S_OK;
+    }
+
+    if (tq->context->tid != GetCurrentThreadId())
+    {
+        FIXME("%p Wrong thread, returning 1.\n", query);
+        timestamp = 1;
+        fill_query_data(data, size, &timestamp, sizeof(timestamp));
+        return S_OK;
+#endif /* STAGING_CSMT */
     }
 
     context = context_acquire(query->device, tq->context->current_rt);
@@ -646,6 +859,7 @@
 
     if (available)
     {
+#if defined(STAGING_CSMT)
         GL_EXTCALL(glGetQueryObjectui64v(tq->id, GL_QUERY_RESULT, &timestamp));
         checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)");
         TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp));
@@ -663,6 +877,28 @@
 }
 
 static BOOL wined3d_timestamp_query_ops_issue(struct wined3d_query *query, DWORD flags)
+#else  /* STAGING_CSMT */
+        if (size)
+        {
+            GL_EXTCALL(glGetQueryObjectui64v(tq->id, GL_QUERY_RESULT, &timestamp));
+            checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)");
+            TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp));
+            fill_query_data(data, size, &timestamp, sizeof(timestamp));
+        }
+        res = S_OK;
+    }
+    else
+    {
+        res = S_FALSE;
+    }
+
+    context_release(context);
+
+    return res;
+}
+
+static HRESULT wined3d_timestamp_query_ops_issue(struct wined3d_query *query, DWORD flags)
+#endif /* STAGING_CSMT */
 {
     struct wined3d_device *device = query->device;
     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
@@ -695,6 +931,7 @@
     }
 
     if (flags & WINED3DISSUE_END)
+#if defined(STAGING_CSMT)
         return TRUE;
     return FALSE;
 }
@@ -711,6 +948,26 @@
         {
              TRACE("Query is building, returning S_FALSE.\n");
              return S_FALSE;
+#else  /* STAGING_CSMT */
+        query->state = QUERY_SIGNALLED;
+
+    return WINED3D_OK;
+}
+
+static HRESULT wined3d_timestamp_disjoint_query_ops_get_data(struct wined3d_query *query,
+        void *data, DWORD size, DWORD flags)
+{
+    TRACE("query %p, data %p, size %#x, flags %#x.\n", query, data, size, flags);
+
+    if (query->type == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT)
+    {
+        static const struct wined3d_query_data_timestamp_disjoint disjoint_data = {1000 * 1000 * 1000, FALSE};
+
+        if (query->state == QUERY_BUILDING)
+        {
+            TRACE("Query is building, returning S_FALSE.\n");
+            return S_FALSE;
+#endif /* STAGING_CSMT */
         }
 
         fill_query_data(data, size, &disjoint_data, sizeof(disjoint_data));
@@ -724,6 +981,7 @@
     return S_OK;
 }
 
+#if defined(STAGING_CSMT)
 static BOOL wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query *query)
 {
     return TRUE;
@@ -760,6 +1018,41 @@
 {
     wined3d_timestamp_disjoint_query_ops_get_data,
     wined3d_timestamp_disjoint_query_ops_poll,
+#else  /* STAGING_CSMT */
+static HRESULT wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query *query, DWORD flags)
+{
+    TRACE("query %p, flags %#x.\n", query, flags);
+
+    if (flags & WINED3DISSUE_BEGIN)
+        query->state = QUERY_BUILDING;
+    if (flags & WINED3DISSUE_END)
+        query->state = QUERY_SIGNALLED;
+
+    return WINED3D_OK;
+}
+
+static const struct wined3d_query_ops event_query_ops =
+{
+    wined3d_event_query_ops_get_data,
+    wined3d_event_query_ops_issue,
+};
+
+static const struct wined3d_query_ops occlusion_query_ops =
+{
+    wined3d_occlusion_query_ops_get_data,
+    wined3d_occlusion_query_ops_issue,
+};
+
+static const struct wined3d_query_ops timestamp_query_ops =
+{
+    wined3d_timestamp_query_ops_get_data,
+    wined3d_timestamp_query_ops_issue,
+};
+
+static const struct wined3d_query_ops timestamp_disjoint_query_ops =
+{
+    wined3d_timestamp_disjoint_query_ops_get_data,
+#endif /* STAGING_CSMT */
     wined3d_timestamp_disjoint_query_ops_issue,
 };
 
@@ -781,6 +1074,7 @@
             }
             query->query_ops = &occlusion_query_ops;
             query->data_size = sizeof(DWORD);
+#if defined(STAGING_CSMT)
             query->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                     sizeof(struct wined3d_occlusion_query));
             if (!query->extendedData)
@@ -788,6 +1082,15 @@
                 ERR("Failed to allocate occlusion query extended data.\n");
                 return E_OUTOFMEMORY;
             }
+#else  /* STAGING_CSMT */
+            query->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
+            if (!query->extendedData)
+            {
+                ERR("Failed to allocate occlusion query extended data.\n");
+                return E_OUTOFMEMORY;
+            }
+            ((struct wined3d_occlusion_query *)query->extendedData)->context = NULL;
+#endif /* STAGING_CSMT */
             break;
 
         case WINED3D_QUERY_TYPE_EVENT:
@@ -860,7 +1163,9 @@
     query->state = QUERY_CREATED;
     query->device = device;
     query->ref = 1;
+#if defined(STAGING_CSMT)
     list_init(&query->poll_list_entry);
+#endif /* STAGING_CSMT */
 
     return WINED3D_OK;
 }
diff --git a/dlls/wined3d/resource.c b/dlls/wined3d/resource.c
--- a/dlls/wined3d/resource.c
+++ b/dlls/wined3d/resource.c
@@ -203,7 +203,9 @@
             ERR("Failed to allocate system memory.\n");
             return E_OUTOFMEMORY;
         }
+#if defined(STAGING_CSMT)
         resource->heap_memory = resource->map_heap_memory;
+#endif /* STAGING_CSMT */
     }
     else
     {
@@ -227,6 +229,7 @@
     return WINED3D_OK;
 }
 
+#if defined(STAGING_CSMT)
 void wined3d_resource_free_bo(struct wined3d_resource *resource)
 {
     struct wined3d_context *context = context_acquire(resource->device, NULL);
@@ -252,6 +255,7 @@
     resource->map_heap_memory = NULL;
 }
 
+#endif /* STAGING_CSMT */
 void resource_cleanup(struct wined3d_resource *resource)
 {
     const struct wined3d *d3d = resource->device->wined3d;
@@ -264,7 +268,11 @@
         adapter_adjust_memory(resource->device->adapter, (INT64)0 - resource->size);
     }
 
+#if defined(STAGING_CSMT)
     wined3d_cs_emit_resource_cleanup(resource->device->cs, resource);
+#else  /* STAGING_CSMT */
+    wined3d_resource_free_sysmem(resource);
+#endif /* STAGING_CSMT */
 
     device_resource_released(resource->device, resource);
 }
@@ -274,9 +282,11 @@
     if (resource->map_count)
         ERR("Resource %p is being unloaded while mapped.\n", resource);
 
+#if defined(STAGING_CSMT)
     if (resource->buffer)
         wined3d_resource_free_bo(resource);
 
+#endif /* STAGING_CSMT */
     context_resource_unloaded(resource->device,
             resource, resource->type);
 }
@@ -355,7 +365,11 @@
     p = (void **)(((ULONG_PTR)mem + align) & ~(RESOURCE_ALIGNMENT - 1)) - 1;
     *p = mem;
 
+#if defined(STAGING_CSMT)
     resource->map_heap_memory = ++p;
+#else  /* STAGING_CSMT */
+    resource->heap_memory = ++p;
+#endif /* STAGING_CSMT */
 
     return TRUE;
 }
@@ -421,7 +435,11 @@
     return ret;
 }
 
+#if defined(STAGING_CSMT)
 static GLenum wined3d_resource_gl_legacy_map_flags(DWORD d3d_flags)
+#else  /* STAGING_CSMT */
+GLenum wined3d_resource_gl_legacy_map_flags(DWORD d3d_flags)
+#endif /* STAGING_CSMT */
 {
     if (d3d_flags & WINED3D_MAP_READONLY)
         return GL_READ_ONLY_ARB;
@@ -462,6 +480,7 @@
     else
         resource->draw_binding = WINED3D_LOCATION_TEXTURE_RGB;
 }
+#if defined(STAGING_CSMT)
 
 void wined3d_resource_get_pitch(const struct wined3d_resource *resource, UINT *row_pitch,
         UINT *slice_pitch)
@@ -1040,3 +1059,4 @@
 
     wined3d_resource_invalidate_location(resource, ~resource->map_binding);
 }
+#endif /* STAGING_CSMT */
diff --git a/dlls/wined3d/sampler.c b/dlls/wined3d/sampler.c
--- a/dlls/wined3d/sampler.c
+++ b/dlls/wined3d/sampler.c
@@ -33,6 +33,7 @@
     return refcount;
 }
 
+#if defined(STAGING_CSMT)
 void wined3d_sampler_destroy(struct wined3d_sampler *sampler)
 {
     struct wined3d_context *context = context_acquire(sampler->device, NULL);
@@ -54,6 +55,24 @@
     {
         struct wined3d_device *device = sampler->device;
         wined3d_cs_emit_sampler_destroy(device->cs, sampler);
+#else  /* STAGING_CSMT */
+ULONG CDECL wined3d_sampler_decref(struct wined3d_sampler *sampler)
+{
+    ULONG refcount = InterlockedDecrement(&sampler->refcount);
+    const struct wined3d_gl_info *gl_info;
+    struct wined3d_context *context;
+
+    TRACE("%p decreasing refcount to %u.\n", sampler, refcount);
+
+    if (!refcount)
+    {
+        context = context_acquire(sampler->device, NULL);
+        gl_info = context->gl_info;
+        GL_EXTCALL(glDeleteSamplers(1, &sampler->name));
+        context_release(context);
+
+        HeapFree(GetProcessHeap(), 0, sampler);
+#endif /* STAGING_CSMT */
     }
 
     return refcount;
diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c
--- a/dlls/wined3d/shader.c
+++ b/dlls/wined3d/shader.c
@@ -1904,7 +1904,11 @@
     }
 }
 
+#if defined(STAGING_CSMT)
 void shader_cleanup(struct wined3d_shader *shader)
+#else  /* STAGING_CSMT */
+static void shader_cleanup(struct wined3d_shader *shader)
+#endif /* STAGING_CSMT */
 {
     HeapFree(GetProcessHeap(), 0, shader->output_signature.elements);
     HeapFree(GetProcessHeap(), 0, shader->input_signature.elements);
@@ -2163,10 +2167,16 @@
 
     if (!refcount)
     {
+#if defined(STAGING_CSMT)
         const struct wined3d_device *device = shader->device;
 
         shader->parent_ops->wined3d_object_destroyed(shader->parent);
         wined3d_cs_emit_shader_cleanup(device->cs, shader);
+#else  /* STAGING_CSMT */
+        shader_cleanup(shader);
+        shader->parent_ops->wined3d_object_destroyed(shader->parent);
+        HeapFree(GetProcessHeap(), 0, shader);
+#endif /* STAGING_CSMT */
     }
 
     return refcount;
@@ -2449,7 +2459,11 @@
     memset(args, 0, sizeof(*args)); /* FIXME: Make sure all bits are set. */
     if (!gl_info->supported[ARB_FRAMEBUFFER_SRGB] && state->render_states[WINED3D_RS_SRGBWRITEENABLE])
     {
+#if defined(STAGING_CSMT)
         unsigned int rt_fmt_flags = state->fb.render_targets[0]->format_flags;
+#else  /* STAGING_CSMT */
+        unsigned int rt_fmt_flags = state->fb->render_targets[0]->format_flags;
+#endif /* STAGING_CSMT */
         if (rt_fmt_flags & WINED3DFMT_FLAG_SRGB_WRITE)
         {
             static unsigned int warned = 0;
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -105,7 +105,11 @@
     const struct wined3d_gl_info *gl_info = context->gl_info;
 
     /* No z test without depth stencil buffers */
+#if defined(STAGING_CSMT)
     if (!state->fb.depth_stencil)
+#else  /* STAGING_CSMT */
+    if (!state->fb->depth_stencil)
+#endif /* STAGING_CSMT */
     {
         TRACE("No Z buffer - disabling depth test\n");
         zenable = WINED3D_ZB_FALSE;
@@ -370,8 +374,13 @@
 
 static void state_blend(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
 {
+#if defined(STAGING_CSMT)
     const struct wined3d_format *rt_format = state->fb.render_targets[0]->format;
     unsigned int rt_fmt_flags = state->fb.render_targets[0]->format_flags;
+#else  /* STAGING_CSMT */
+    const struct wined3d_format *rt_format = state->fb->render_targets[0]->format;
+    unsigned int rt_fmt_flags = state->fb->render_targets[0]->format_flags;
+#endif /* STAGING_CSMT */
     const struct wined3d_gl_info *gl_info = context->gl_info;
     GLenum srcBlend, dstBlend;
     enum wined3d_blend d3d_blend;
@@ -816,7 +825,11 @@
     GLint depthFail_ccw;
 
     /* No stencil test without a stencil buffer. */
+#if defined(STAGING_CSMT)
     if (!state->fb.depth_stencil)
+#else  /* STAGING_CSMT */
+    if (!state->fb->depth_stencil)
+#endif /* STAGING_CSMT */
     {
         gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
         checkGLcall("glDisable GL_STENCIL_TEST");
@@ -912,7 +925,11 @@
 
 static void state_stencilwrite2s(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
 {
+#if defined(STAGING_CSMT)
     DWORD mask = state->fb.depth_stencil ? state->render_states[WINED3D_RS_STENCILWRITEMASK] : 0;
+#else  /* STAGING_CSMT */
+    DWORD mask = state->fb->depth_stencil ? state->render_states[WINED3D_RS_STENCILWRITEMASK] : 0;
+#endif /* STAGING_CSMT */
     const struct wined3d_gl_info *gl_info = context->gl_info;
 
     GL_EXTCALL(glActiveStencilFaceEXT(GL_BACK));
@@ -926,7 +943,11 @@
 
 static void state_stencilwrite(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
 {
+#if defined(STAGING_CSMT)
     DWORD mask = state->fb.depth_stencil ? state->render_states[WINED3D_RS_STENCILWRITEMASK] : 0;
+#else  /* STAGING_CSMT */
+    DWORD mask = state->fb->depth_stencil ? state->render_states[WINED3D_RS_STENCILWRITEMASK] : 0;
+#endif /* STAGING_CSMT */
     const struct wined3d_gl_info *gl_info = context->gl_info;
 
     gl_info->gl_ops.gl.p_glStencilMask(mask);
@@ -1128,10 +1149,17 @@
                     /* drop through */
 
                 case WINED3D_FOG_NONE:
+#if defined(STAGING_CSMT)
                     /* Both are none? According to msdn the alpha channel of the specular
                      * color contains a fog factor. Set it in draw_strided_slow.
                      * Same happens with Vertexfog on transformed vertices
                      */
+#else  /* STAGING_CSMT */
+                    /* Both are none? According to msdn the alpha channel of the specular
+                     * color contains a fog factor. Set it in drawStridedSlow.
+                     * Same happens with Vertexfog on transformed vertices
+                     */
+#endif /* STAGING_CSMT */
                     new_source = FOGSOURCE_COORD;
                     gl_info->gl_ops.gl.p_glFogi(GL_FOG_MODE, GL_LINEAR);
                     checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
@@ -1653,7 +1681,11 @@
     if (state->render_states[WINED3D_RS_SLOPESCALEDEPTHBIAS]
             || state->render_states[WINED3D_RS_DEPTHBIAS])
     {
+#if defined(STAGING_CSMT)
         const struct wined3d_rendertarget_view *depth = state->fb.depth_stencil;
+#else  /* STAGING_CSMT */
+        const struct wined3d_rendertarget_view *depth = state->fb->depth_stencil;
+#endif /* STAGING_CSMT */
         float scale;
 
         union
@@ -4190,9 +4222,15 @@
                 }
             }
         } else {
+#if defined(STAGING_CSMT)
             /* TODO: support blends in draw_strided_slow
              * No need to write a FIXME here, this is done after the general vertex decl decoding
              */
+#else  /* STAGING_CSMT */
+            /* TODO: support blends in drawStridedSlow
+             * No need to write a FIXME here, this is done after the general vertex decl decoding
+             */
+#endif /* STAGING_CSMT */
             WARN("unsupported blending in openGl\n");
         }
     }
@@ -4546,7 +4584,11 @@
 
 static void viewport_miscpart(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
 {
+#if defined(STAGING_CSMT)
     const struct wined3d_rendertarget_view *target = state->fb.render_targets[0];
+#else  /* STAGING_CSMT */
+    const struct wined3d_rendertarget_view *target = state->fb->render_targets[0];
+#endif /* STAGING_CSMT */
     const struct wined3d_gl_info *gl_info = context->gl_info;
     struct wined3d_viewport vp = state->viewport;
 
@@ -4724,7 +4766,11 @@
     }
     else
     {
+#if defined(STAGING_CSMT)
         const struct wined3d_rendertarget_view *target = state->fb.render_targets[0];
+#else  /* STAGING_CSMT */
+        const struct wined3d_rendertarget_view *target = state->fb->render_targets[0];
+#endif /* STAGING_CSMT */
         UINT height;
         UINT width;
 
@@ -4788,7 +4834,11 @@
 
 void state_srgbwrite(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
 {
+#if defined(STAGING_CSMT)
     unsigned int rt_fmt_flags = state->fb.render_targets[0]->format_flags;
+#else  /* STAGING_CSMT */
+    unsigned int rt_fmt_flags = state->fb->render_targets[0]->format_flags;
+#endif /* STAGING_CSMT */
     const struct wined3d_gl_info *gl_info = context->gl_info;
 
     TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id);
diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c
--- a/dlls/wined3d/stateblock.c
+++ b/dlls/wined3d/stateblock.c
@@ -464,7 +464,9 @@
     struct wined3d_texture *texture;
     struct wined3d_buffer *buffer;
     struct wined3d_shader *shader;
+#if defined(STAGING_CSMT)
     struct wined3d_rendertarget_view *view;
+#endif /* STAGING_CSMT */
     unsigned int i, j;
 
     if ((decl = state->vertex_declaration))
@@ -541,6 +543,7 @@
             }
         }
     }
+#if defined(STAGING_CSMT)
 
     if (state->fb.depth_stencil)
     {
@@ -566,6 +569,7 @@
             }
         }
     }
+#endif /* STAGING_CSMT */
 }
 
 void state_cleanup(struct wined3d_state *state)
@@ -593,7 +597,9 @@
 
     HeapFree(GetProcessHeap(), 0, state->vs_consts_f);
     HeapFree(GetProcessHeap(), 0, state->ps_consts_f);
+#if defined(STAGING_CSMT)
     HeapFree(GetProcessHeap(), 0, state->fb.render_targets);
+#endif /* STAGING_CSMT */
 }
 
 ULONG CDECL wined3d_stateblock_decref(struct wined3d_stateblock *stateblock)
@@ -1075,8 +1081,13 @@
         gl_primitive_type = stateblock->state.gl_primitive_type;
         prev = device->update_state->gl_primitive_type;
         device->update_state->gl_primitive_type = gl_primitive_type;
+#if defined(STAGING_CSMT)
         if (gl_primitive_type != prev)
             wined3d_cs_emit_set_primitive_type(device->cs, gl_primitive_type);
+#else  /* STAGING_CSMT */
+        if (gl_primitive_type != prev && (gl_primitive_type == GL_POINTS || prev == GL_POINTS))
+            device_invalidate_state(device, STATE_POINT_ENABLE);
+#endif /* STAGING_CSMT */
     }
 
     if (stateblock->changed.indices)
@@ -1334,6 +1345,7 @@
         state->sampler_states[i][WINED3D_SAMP_ELEMENT_INDEX] = 0;
         /* TODO: Vertex offset in the presampled displacement map. */
         state->sampler_states[i][WINED3D_SAMP_DMAP_OFFSET] = 0;
+#if defined(STAGING_CSMT)
         state->textures[i] = NULL;
     }
 
@@ -1351,6 +1363,19 @@
     unsigned int i;
 
     state->flags = flags;
+#else  /* STAGING_CSMT */
+    }
+}
+
+HRESULT state_init(struct wined3d_state *state, struct wined3d_fb_state *fb,
+        const struct wined3d_gl_info *gl_info, const struct wined3d_d3d_info *d3d_info,
+        DWORD flags)
+{
+    unsigned int i;
+
+    state->flags = flags;
+    state->fb = fb;
+#endif /* STAGING_CSMT */
 
     for (i = 0; i < LIGHTMAP_SIZE; i++)
     {
@@ -1368,6 +1393,7 @@
         return E_OUTOFMEMORY;
     }
 
+#if defined(STAGING_CSMT)
     if (!(state->fb.render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
             sizeof(*state->fb.render_targets) * gl_info->limits.buffers)))
     {
@@ -1377,6 +1403,7 @@
     }
     state->fb.rt_size = gl_info->limits.buffers;
 
+#endif /* STAGING_CSMT */
     if (flags & WINED3D_STATE_INIT_DEFAULT)
         state_init_default(state, gl_info);
 
@@ -1387,6 +1414,7 @@
         struct wined3d_device *device, enum wined3d_stateblock_type type)
 {
     HRESULT hr;
+#if defined(STAGING_CSMT)
     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
     const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
 
@@ -1394,6 +1422,14 @@
     stateblock->device = device;
 
     if (FAILED(hr = state_init(&stateblock->state, gl_info, d3d_info, 0)))
+#else  /* STAGING_CSMT */
+    const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
+
+    stateblock->ref = 1;
+    stateblock->device = device;
+
+    if (FAILED(hr = state_init(&stateblock->state, NULL, &device->adapter->gl_info, d3d_info, 0)))
+#endif /* STAGING_CSMT */
         return hr;
 
     if (FAILED(hr = stateblock_allocate_shader_constants(stateblock)))
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -36,6 +36,7 @@
 
 #define MAXLOCKCOUNT 50 /* After this amount of locks do not free the sysmem copy. */
 
+#if defined(STAGING_CSMT)
 
 static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
         struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
@@ -44,6 +45,20 @@
 void wined3d_surface_cleanup_cs(struct wined3d_surface *surface)
 {
     if (surface->rb_multisample || surface->rb_resolved || !list_empty(&surface->renderbuffers))
+#else  /* STAGING_CSMT */
+static const DWORD surface_simple_locations =
+        WINED3D_LOCATION_SYSMEM | WINED3D_LOCATION_USER_MEMORY
+        | WINED3D_LOCATION_DIB | WINED3D_LOCATION_BUFFER;
+
+static void surface_cleanup(struct wined3d_surface *surface)
+{
+    struct wined3d_surface *overlay, *cur;
+
+    TRACE("surface %p.\n", surface);
+
+    if (surface->pbo || surface->rb_multisample
+            || surface->rb_resolved || !list_empty(&surface->renderbuffers))
+#endif /* STAGING_CSMT */
     {
         struct wined3d_renderbuffer_entry *entry, *entry2;
         const struct wined3d_gl_info *gl_info;
@@ -52,6 +67,14 @@
         context = context_acquire(surface->resource.device, NULL);
         gl_info = context->gl_info;
 
+#if !defined(STAGING_CSMT)
+        if (surface->pbo)
+        {
+            TRACE("Deleting PBO %u.\n", surface->pbo);
+            GL_EXTCALL(glDeleteBuffers(1, &surface->pbo));
+        }
+
+#endif /* STAGING_CSMT */
         if (surface->rb_multisample)
         {
             TRACE("Deleting multisample renderbuffer %u.\n", surface->rb_multisample);
@@ -78,6 +101,7 @@
     {
         DeleteDC(surface->hDC);
         DeleteObject(surface->dib.DIBsection);
+#if defined(STAGING_CSMT)
         surface->resource.bitmap_data = NULL;
     }
 
@@ -92,6 +116,10 @@
     BOOL user_mem = surface->resource.map_binding == WINED3D_LOCATION_USER_MEMORY;
 
     TRACE("surface %p.\n", surface);
+#else  /* STAGING_CSMT */
+        surface->dib.bitmap_data = NULL;
+    }
+#endif /* STAGING_CSMT */
 
     if (surface->overlay_dest)
         list_remove(&surface->overlay_entry);
@@ -103,6 +131,7 @@
     }
 
     resource_cleanup(&surface->resource);
+#if defined(STAGING_CSMT)
     wined3d_cs_emit_surface_cleanup(cs, surface);
 
     /* Wait for the CS to finish operations on this surface when user memory was in use.
@@ -118,6 +147,17 @@
 
     surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
     surface_cleanup(surface);
+#else  /* STAGING_CSMT */
+}
+
+void wined3d_surface_destroy(struct wined3d_surface *surface)
+{
+    TRACE("surface %p.\n", surface);
+
+    surface_cleanup(surface);
+    surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
+    HeapFree(GetProcessHeap(), 0, surface);
+#endif /* STAGING_CSMT */
 }
 
 void surface_get_drawable_size(const struct wined3d_surface *surface, const struct wined3d_context *context,
@@ -372,7 +412,9 @@
     BITMAPINFO *b_info;
     int extraline = 0;
     DWORD *masks;
+#if defined(STAGING_CSMT)
     UINT row_pitch, slice_pitch;
+#endif /* STAGING_CSMT */
 
     TRACE("surface %p.\n", surface);
 
@@ -418,11 +460,18 @@
 
     b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
     /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
+#if defined(STAGING_CSMT)
     wined3d_resource_get_pitch(&surface->resource, &row_pitch, &slice_pitch);
     b_info->bmiHeader.biWidth = row_pitch / format->byte_count;
     b_info->bmiHeader.biHeight = 0 - surface->resource.height - extraline;
     b_info->bmiHeader.biSizeImage = (surface->resource.height + extraline)
             * row_pitch;
+#else  /* STAGING_CSMT */
+    b_info->bmiHeader.biWidth = wined3d_surface_get_pitch(surface) / format->byte_count;
+    b_info->bmiHeader.biHeight = 0 - surface->resource.height - extraline;
+    b_info->bmiHeader.biSizeImage = (surface->resource.height + extraline)
+            * wined3d_surface_get_pitch(surface);
+#endif /* STAGING_CSMT */
     b_info->bmiHeader.biPlanes = 1;
     b_info->bmiHeader.biBitCount = format->byte_count * 8;
 
@@ -464,7 +513,11 @@
     TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
             b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight,
             b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
+#if defined(STAGING_CSMT)
     surface->dib.DIBsection = CreateDIBSection(0, b_info, DIB_RGB_COLORS, &surface->resource.bitmap_data, 0, 0);
+#else  /* STAGING_CSMT */
+    surface->dib.DIBsection = CreateDIBSection(0, b_info, DIB_RGB_COLORS, &surface->dib.bitmap_data, 0, 0);
+#endif /* STAGING_CSMT */
 
     if (!surface->dib.DIBsection)
     {
@@ -473,7 +526,11 @@
         return HRESULT_FROM_WIN32(GetLastError());
     }
 
+#if defined(STAGING_CSMT)
     TRACE("DIBSection at %p.\n", surface->resource.bitmap_data);
+#else  /* STAGING_CSMT */
+    TRACE("DIBSection at %p.\n", surface->dib.bitmap_data);
+#endif /* STAGING_CSMT */
     surface->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
 
     HeapFree(GetProcessHeap(), 0, b_info);
@@ -487,6 +544,116 @@
     return WINED3D_OK;
 }
 
+#if !defined(STAGING_CSMT)
+static void surface_get_memory(const struct wined3d_surface *surface, struct wined3d_bo_address *data,
+        DWORD location)
+{
+    if (location & WINED3D_LOCATION_BUFFER)
+    {
+        data->addr = NULL;
+        data->buffer_object = surface->pbo;
+        return;
+    }
+    if (location & WINED3D_LOCATION_USER_MEMORY)
+    {
+        data->addr = surface->user_memory;
+        data->buffer_object = 0;
+        return;
+    }
+    if (location & WINED3D_LOCATION_DIB)
+    {
+        data->addr = surface->dib.bitmap_data;
+        data->buffer_object = 0;
+        return;
+    }
+    if (location & WINED3D_LOCATION_SYSMEM)
+    {
+        data->addr = surface->resource.heap_memory;
+        data->buffer_object = 0;
+        return;
+    }
+
+    ERR("Unexpected locations %s.\n", wined3d_debug_location(location));
+    data->addr = NULL;
+    data->buffer_object = 0;
+}
+
+static void surface_prepare_buffer(struct wined3d_surface *surface)
+{
+    struct wined3d_context *context;
+    GLenum error;
+    const struct wined3d_gl_info *gl_info;
+
+    if (surface->pbo)
+        return;
+
+    context = context_acquire(surface->resource.device, NULL);
+    gl_info = context->gl_info;
+
+    GL_EXTCALL(glGenBuffers(1, &surface->pbo));
+    error = gl_info->gl_ops.gl.p_glGetError();
+    if (!surface->pbo || error != GL_NO_ERROR)
+        ERR("Failed to create a PBO with error %s (%#x).\n", debug_glerror(error), error);
+
+    TRACE("Binding PBO %u.\n", surface->pbo);
+
+    GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, surface->pbo));
+    checkGLcall("glBindBuffer");
+
+    GL_EXTCALL(glBufferData(GL_PIXEL_UNPACK_BUFFER, surface->resource.size + 4,
+            NULL, GL_STREAM_DRAW));
+    checkGLcall("glBufferData");
+
+    GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
+    checkGLcall("glBindBuffer");
+
+    context_release(context);
+}
+
+static void surface_prepare_system_memory(struct wined3d_surface *surface)
+{
+    TRACE("surface %p.\n", surface);
+
+    if (surface->resource.heap_memory)
+        return;
+
+    /* Whatever surface we have, make sure that there is memory allocated
+     * for the downloaded copy, or a PBO to map. */
+    if (!wined3d_resource_allocate_sysmem(&surface->resource))
+        ERR("Failed to allocate system memory.\n");
+
+    if (surface->locations & WINED3D_LOCATION_SYSMEM)
+        ERR("Surface without system memory has WINED3D_LOCATION_SYSMEM set.\n");
+}
+
+void surface_prepare_map_memory(struct wined3d_surface *surface)
+{
+    switch (surface->resource.map_binding)
+    {
+        case WINED3D_LOCATION_SYSMEM:
+            surface_prepare_system_memory(surface);
+            break;
+
+        case WINED3D_LOCATION_USER_MEMORY:
+            if (!surface->user_memory)
+                ERR("Map binding is set to WINED3D_LOCATION_USER_MEMORY but surface->user_memory is NULL.\n");
+            break;
+
+        case WINED3D_LOCATION_DIB:
+            if (!surface->dib.bitmap_data)
+                ERR("Map binding is set to WINED3D_LOCATION_DIB but surface->dib.bitmap_data is NULL.\n");
+            break;
+
+        case WINED3D_LOCATION_BUFFER:
+            surface_prepare_buffer(surface);
+            break;
+
+        default:
+            ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface->resource.map_binding));
+    }
+}
+
+#endif /* STAGING_CSMT */
 static void surface_evict_sysmem(struct wined3d_surface *surface)
 {
     /* In some conditions the surface memory must not be freed:
@@ -497,8 +664,12 @@
         return;
 
     wined3d_resource_free_sysmem(&surface->resource);
+#if defined(STAGING_CSMT)
     surface->resource.map_heap_memory = NULL;
     wined3d_resource_invalidate_location(&surface->resource, WINED3D_LOCATION_SYSMEM);
+#else  /* STAGING_CSMT */
+    surface_invalidate_location(surface, WINED3D_LOCATION_SYSMEM);
+#endif /* STAGING_CSMT */
 }
 
 static BOOL surface_use_pbo(const struct wined3d_surface *surface)
@@ -583,7 +754,11 @@
     }
 
     if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
+#if defined(STAGING_CSMT)
         surface->resource.locations = WINED3D_LOCATION_DISCARDED;
+#else  /* STAGING_CSMT */
+        surface->locations = WINED3D_LOCATION_DISCARDED;
+#endif /* STAGING_CSMT */
 
     if (surface_use_pbo(surface))
         surface->resource.map_binding = WINED3D_LOCATION_BUFFER;
@@ -591,6 +766,7 @@
     return WINED3D_OK;
 }
 
+#if defined(STAGING_CSMT)
 static void surface_frontbuffer_updated(struct wined3d_surface *surface)
 {
     struct wined3d_context *context = NULL;
@@ -607,6 +783,54 @@
     wined3d_resource_load_location(&surface->resource, context, surface->container->resource.draw_binding);
     if (context)
         context_release(context);
+#else  /* STAGING_CSMT */
+static void surface_unmap(struct wined3d_surface *surface)
+{
+    struct wined3d_device *device = surface->resource.device;
+    const struct wined3d_gl_info *gl_info;
+    struct wined3d_context *context;
+
+    TRACE("surface %p.\n", surface);
+
+    memset(&surface->lockedRect, 0, sizeof(surface->lockedRect));
+
+    switch (surface->resource.map_binding)
+    {
+        case WINED3D_LOCATION_SYSMEM:
+        case WINED3D_LOCATION_USER_MEMORY:
+        case WINED3D_LOCATION_DIB:
+            break;
+
+        case WINED3D_LOCATION_BUFFER:
+            context = context_acquire(device, NULL);
+            gl_info = context->gl_info;
+
+            GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, surface->pbo));
+            GL_EXTCALL(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER));
+            GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
+            checkGLcall("glUnmapBuffer");
+            context_release(context);
+            break;
+
+        default:
+            ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface->resource.map_binding));
+    }
+
+    if (surface->locations & (WINED3D_LOCATION_DRAWABLE | WINED3D_LOCATION_TEXTURE_RGB))
+    {
+        TRACE("Not dirtified, nothing to do.\n");
+        return;
+    }
+
+    if (surface->container->swapchain && surface->container->swapchain->front_buffer == surface->container)
+    {
+        context = context_acquire(device, surface);
+        surface_load_location(surface, context, surface->container->resource.draw_binding);
+        context_release(context);
+    }
+    else if (surface->container->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
+        FIXME("Depth / stencil buffer locking is not implemented.\n");
+#endif /* STAGING_CSMT */
 }
 
 static BOOL surface_is_full_rect(const struct wined3d_surface *surface, const RECT *r)
@@ -667,9 +891,15 @@
 
     /* Make sure the locations are up-to-date. Loading the destination
      * surface isn't required if the entire surface is overwritten. */
+#if defined(STAGING_CSMT)
     wined3d_resource_load_location(&src_surface->resource, context, src_location);
     if (!surface_is_full_rect(dst_surface, dst_rect))
         wined3d_resource_load_location(&dst_surface->resource, context, dst_location);
+#else  /* STAGING_CSMT */
+    surface_load_location(src_surface, context, src_location);
+    if (!surface_is_full_rect(dst_surface, dst_rect))
+        surface_load_location(dst_surface, context, dst_location);
+#endif /* STAGING_CSMT */
     else
         wined3d_surface_prepare(dst_surface, context, dst_location);
 
@@ -760,9 +990,15 @@
      * surface isn't required if the entire surface is overwritten. (And is
      * in fact harmful if we're being called by surface_load_location() with
      * the purpose of loading the destination surface.) */
+#if defined(STAGING_CSMT)
     wined3d_resource_load_location(&src_surface->resource, old_ctx, src_location);
     if (!surface_is_full_rect(dst_surface, &dst_rect))
         wined3d_resource_load_location(&dst_surface->resource, old_ctx, dst_location);
+#else  /* STAGING_CSMT */
+    surface_load_location(src_surface, old_ctx, src_location);
+    if (!surface_is_full_rect(dst_surface, &dst_rect))
+        surface_load_location(dst_surface, old_ctx, dst_location);
+#endif /* STAGING_CSMT */
     else
         wined3d_surface_prepare(dst_surface, old_ctx, dst_location);
 
@@ -954,6 +1190,18 @@
     return WINED3D_OK;
 }
 
+#if !defined(STAGING_CSMT)
+/* Context activation is done by the caller. */
+static void surface_remove_pbo(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
+{
+    GL_EXTCALL(glDeleteBuffers(1, &surface->pbo));
+    checkGLcall("glDeleteBuffers(1, &surface->pbo)");
+
+    surface->pbo = 0;
+    surface_invalidate_location(surface, WINED3D_LOCATION_BUFFER);
+}
+
+#endif /* STAGING_CSMT */
 static ULONG surface_resource_incref(struct wined3d_resource *resource)
 {
     return wined3d_surface_incref(surface_from_resource(resource));
@@ -979,6 +1227,7 @@
 
     if (resource->pool == WINED3D_POOL_DEFAULT)
     {
+#if defined(STAGING_CSMT)
         /* Default pool resources are supposed to be destroyed before Reset is called.
          * Implicit resources stay however. So this means we have an implicit render target
          * or depth stencil. The content may be destroyed, but we still have to tear down
@@ -992,6 +1241,40 @@
         wined3d_resource_load_location(&surface->resource, context, surface->resource.map_binding);
         wined3d_resource_invalidate_location(&surface->resource, ~surface->resource.map_binding);
     }
+#else  /* STAGING_CSMT */
+        /* Default pool resources are supposed to be destroyed before Reset is called.
+         * Implicit resources stay however. So this means we have an implicit render target
+         * or depth stencil. The content may be destroyed, but we still have to tear down
+         * opengl resources, so we cannot leave early.
+         *
+         * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
+         * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
+         * or the depth stencil into an FBO the texture or render buffer will be removed
+         * and all flags get lost */
+        if (resource->usage & WINED3DUSAGE_DEPTHSTENCIL)
+        {
+            surface_validate_location(surface, WINED3D_LOCATION_DISCARDED);
+            surface_invalidate_location(surface, ~WINED3D_LOCATION_DISCARDED);
+        }
+        else
+        {
+            surface_prepare_system_memory(surface);
+            memset(surface->resource.heap_memory, 0, surface->resource.size);
+            surface_validate_location(surface, WINED3D_LOCATION_SYSMEM);
+            surface_invalidate_location(surface, ~WINED3D_LOCATION_SYSMEM);
+        }
+    }
+    else
+    {
+        surface_prepare_map_memory(surface);
+        surface_load_location(surface, context, surface->resource.map_binding);
+        surface_invalidate_location(surface, ~surface->resource.map_binding);
+    }
+
+    /* Destroy PBOs, but load them into real sysmem before */
+    if (surface->pbo)
+        surface_remove_pbo(surface, gl_info);
+#endif /* STAGING_CSMT */
 
     /* Destroy fbo render buffers. This is needed for implicit render targets, for
      * all application-created targets the application has to release the surface
@@ -1035,6 +1318,7 @@
     return WINED3DERR_INVALIDCALL;
 }
 
+#if defined(STAGING_CSMT)
 static void wined3d_surface_location_invalidated(struct wined3d_resource *resource, DWORD location)
 {
     struct wined3d_surface *surface = surface_from_resource(resource);
@@ -1050,6 +1334,21 @@
 {
     surface_private_setup,
     surface_frontbuffer_updated,
+#else  /* STAGING_CSMT */
+static const struct wined3d_resource_ops surface_resource_ops =
+{
+    surface_resource_incref,
+    surface_resource_decref,
+    surface_unload,
+    surface_resource_sub_resource_map,
+    surface_resource_sub_resource_unmap,
+};
+
+static const struct wined3d_surface_ops surface_ops =
+{
+    surface_private_setup,
+    surface_unmap,
+#endif /* STAGING_CSMT */
 };
 
 /*****************************************************************************
@@ -1093,6 +1392,7 @@
     return WINED3D_OK;
 }
 
+#if defined(STAGING_CSMT)
 static void gdi_surface_frontbuffer_updated(struct wined3d_surface *surface)
 {
     x11_copy_to_screen(surface->container->swapchain, &surface->lockedRect);
@@ -1102,6 +1402,23 @@
 {
     gdi_surface_private_setup,
     gdi_surface_frontbuffer_updated,
+#else  /* STAGING_CSMT */
+static void gdi_surface_unmap(struct wined3d_surface *surface)
+{
+    TRACE("surface %p.\n", surface);
+
+    /* Tell the swapchain to update the screen. */
+    if (surface->container->swapchain && surface->container == surface->container->swapchain->front_buffer)
+        x11_copy_to_screen(surface->container->swapchain, &surface->lockedRect);
+
+    memset(&surface->lockedRect, 0, sizeof(RECT));
+}
+
+static const struct wined3d_surface_ops gdi_surface_ops =
+{
+    gdi_surface_private_setup,
+    gdi_surface_unmap,
+#endif /* STAGING_CSMT */
 };
 
 /* This call just downloads data, the caller is responsible for binding the
@@ -1120,7 +1437,11 @@
         return;
     }
 
+#if defined(STAGING_CSMT)
     wined3d_resource_get_memory(&surface->resource, dst_location, &data);
+#else  /* STAGING_CSMT */
+    surface_get_memory(surface, &data, dst_location);
+#endif /* STAGING_CSMT */
 
     if (surface->container->resource.format_flags & WINED3DFMT_FLAG_COMPRESSED)
     {
@@ -1148,6 +1469,7 @@
         void *mem;
         GLenum gl_format = format->glFormat;
         GLenum gl_type = format->glType;
+#if defined(STAGING_CSMT)
         UINT src_pitch = 0;
         UINT dst_row_pitch, dst_slice_pitch;
 
@@ -1156,6 +1478,16 @@
             unsigned char alignment = surface->resource.device->surface_alignment;
             src_pitch = format->byte_count * surface->pow2Width;
             wined3d_resource_get_pitch(&surface->resource, &dst_row_pitch, &dst_slice_pitch);
+#else  /* STAGING_CSMT */
+        int src_pitch = 0;
+        int dst_pitch = 0;
+
+        if (surface->flags & SFLAG_NONPOW2)
+        {
+            unsigned char alignment = surface->resource.device->surface_alignment;
+            src_pitch = format->byte_count * surface->pow2Width;
+            dst_pitch = wined3d_surface_get_pitch(surface);
+#endif /* STAGING_CSMT */
             src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
             mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * surface->pow2Height);
         }
@@ -1242,12 +1574,21 @@
              * won't be released, and doesn't have to be re-read. */
             src_data = mem;
             dst_data = data.addr;
+#if defined(STAGING_CSMT)
             TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface, src_pitch, dst_row_pitch);
             for (y = 0; y < surface->resource.height; ++y)
             {
                 memcpy(dst_data, src_data, dst_row_pitch);
                 src_data += src_pitch;
                 dst_data += dst_row_pitch;
+#else  /* STAGING_CSMT */
+            TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface, src_pitch, dst_pitch);
+            for (y = 0; y < surface->resource.height; ++y)
+            {
+                memcpy(dst_data, src_data, dst_pitch);
+                src_data += src_pitch;
+                dst_data += dst_pitch;
+#endif /* STAGING_CSMT */
             }
 
             HeapFree(GetProcessHeap(), 0, mem);
@@ -1371,6 +1712,7 @@
 
 static BOOL surface_check_block_align(struct wined3d_surface *surface, const struct wined3d_box *box)
 {
+#if defined(STAGING_CSMT)
     if ((box->left >= box->right)
             || (box->top >= box->bottom)
             || (box->right > surface->resource.width)
@@ -1381,6 +1723,34 @@
 }
 
 BOOL surface_check_block_align_rect(struct wined3d_surface *surface, const RECT *rect)
+#else  /* STAGING_CSMT */
+    UINT width_mask, height_mask;
+
+    if (!box->left && !box->top
+            && box->right == surface->resource.width
+            && box->bottom == surface->resource.height)
+        return TRUE;
+
+    if ((box->left >= box->right)
+            || (box->top >= box->bottom)
+            || (box->right > surface->resource.width)
+            || (box->bottom > surface->resource.height))
+        return FALSE;
+
+    /* This assumes power of two block sizes, but NPOT block sizes would be
+     * silly anyway. */
+    width_mask = surface->resource.format->block_width - 1;
+    height_mask = surface->resource.format->block_height - 1;
+
+    if (!(box->left & width_mask) && !(box->top & height_mask)
+            && !(box->right & width_mask) && !(box->bottom & height_mask))
+        return TRUE;
+
+    return FALSE;
+}
+
+static BOOL surface_check_block_align_rect(struct wined3d_surface *surface, const RECT *rect)
+#endif /* STAGING_CSMT */
 {
     struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
 
@@ -1399,7 +1769,11 @@
     UINT update_w, update_h;
     UINT dst_w, dst_h;
     RECT r, dst_rect;
+#if defined(STAGING_CSMT)
     UINT src_row_pitch, src_slice_pitch;
+#else  /* STAGING_CSMT */
+    UINT src_pitch;
+#endif /* STAGING_CSMT */
     POINT p;
 
     TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
@@ -1470,11 +1844,17 @@
         return WINED3DERR_INVALIDCALL;
     }
 
+#if defined(STAGING_CSMT)
     /* Use surface_cpu_blt() instead of uploading directly if we need
      * conversion. Avoid calling wined3d_surface_blt() since that goes
      * through the CS. */
     if (dst_format->convert || wined3d_format_get_color_key_conversion(dst_surface->container, FALSE))
         return surface_cpu_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
+#else  /* STAGING_CSMT */
+    /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
+    if (dst_format->convert || wined3d_format_get_color_key_conversion(dst_surface->container, FALSE))
+        return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
+#endif /* STAGING_CSMT */
 
     context = context_acquire(dst_surface->resource.device, NULL);
     gl_info = context->gl_info;
@@ -1485,6 +1865,7 @@
     if (update_w == dst_w && update_h == dst_h)
         wined3d_texture_prepare_texture(dst_surface->container, context, FALSE);
     else
+#if defined(STAGING_CSMT)
         wined3d_resource_load_location(&dst_surface->resource, context, WINED3D_LOCATION_TEXTURE_RGB);
     wined3d_texture_bind_and_dirtify(dst_surface->container, context, FALSE);
 
@@ -1498,6 +1879,21 @@
 
     wined3d_resource_validate_location(&dst_surface->resource, WINED3D_LOCATION_TEXTURE_RGB);
     wined3d_resource_invalidate_location(&dst_surface->resource, ~WINED3D_LOCATION_TEXTURE_RGB);
+#else  /* STAGING_CSMT */
+        surface_load_location(dst_surface, context, WINED3D_LOCATION_TEXTURE_RGB);
+    wined3d_texture_bind_and_dirtify(dst_surface->container, context, FALSE);
+
+    surface_get_memory(src_surface, &data, src_surface->locations);
+    src_pitch = wined3d_surface_get_pitch(src_surface);
+
+    wined3d_surface_upload_data(dst_surface, gl_info, src_format, src_rect,
+            src_pitch, dst_point, FALSE, wined3d_const_bo_address(&data));
+
+    context_release(context);
+
+    surface_validate_location(dst_surface, WINED3D_LOCATION_TEXTURE_RGB);
+    surface_invalidate_location(dst_surface, ~WINED3D_LOCATION_TEXTURE_RGB);
+#endif /* STAGING_CSMT */
 
     return WINED3D_OK;
 }
@@ -1611,6 +2007,7 @@
     if (surface->resource.pool == WINED3D_POOL_SCRATCH)
         ERR("Not supported on scratch surfaces.\n");
 
+#if defined(STAGING_CSMT)
     if (surface->resource.locations & location)
     {
         TRACE("surface is already in texture\n");
@@ -1619,6 +2016,16 @@
     TRACE("Reloading because surface is dirty.\n");
 
     wined3d_resource_load_location(&surface->resource, context, location);
+#else  /* STAGING_CSMT */
+    if (surface->locations & location)
+    {
+        TRACE("surface is already in texture\n");
+        return;
+    }
+    TRACE("Reloading because surface is dirty.\n");
+
+    surface_load_location(surface, context, location);
+#endif /* STAGING_CSMT */
     surface_evict_sysmem(surface);
 }
 
@@ -1701,6 +2108,7 @@
 
 void CDECL wined3d_surface_preload(struct wined3d_surface *surface)
 {
+#if defined(STAGING_CSMT)
     const struct wined3d_device *device = surface->resource.device;
     TRACE("surface %p.\n", surface);
 
@@ -1711,6 +2119,17 @@
     }
 
     wined3d_cs_emit_surface_preload(device->cs, surface);
+#else  /* STAGING_CSMT */
+    TRACE("surface %p.\n", surface);
+
+    if (!surface->resource.device->d3d_initialized)
+    {
+        ERR("D3D not initialized.\n");
+        return;
+    }
+
+    wined3d_texture_preload(surface->container);
+#endif /* STAGING_CSMT */
 }
 
 void * CDECL wined3d_surface_get_parent(const struct wined3d_surface *surface)
@@ -1729,10 +2148,28 @@
 
 DWORD CDECL wined3d_surface_get_pitch(const struct wined3d_surface *surface)
 {
+#if defined(STAGING_CSMT)
     UINT row_pitch, slice_pitch;
     const struct wined3d_resource *resource = &surface->resource;
     wined3d_resource_get_pitch(resource, &row_pitch, &slice_pitch);
     return row_pitch;
+#else  /* STAGING_CSMT */
+    unsigned int alignment;
+    DWORD pitch;
+
+    TRACE("surface %p.\n", surface);
+
+    if (surface->pitch)
+        return surface->pitch;
+
+    alignment = surface->resource.device->surface_alignment;
+    pitch = wined3d_format_calculate_pitch(surface->resource.format, surface->resource.width);
+    pitch = (pitch + alignment - 1) & ~(alignment - 1);
+
+    TRACE("Returning %u.\n", pitch);
+
+    return pitch;
+#endif /* STAGING_CSMT */
 }
 
 HRESULT CDECL wined3d_surface_set_overlay_position(struct wined3d_surface *surface, LONG x, LONG y)
@@ -1857,6 +2294,7 @@
     {
         DeleteDC(surface->hDC);
         DeleteObject(surface->dib.DIBsection);
+#if defined(STAGING_CSMT)
         surface->resource.bitmap_data = NULL;
         surface->flags &= ~SFLAG_DIBSECTION;
         create_dib = TRUE;
@@ -1865,6 +2303,15 @@
     surface->resource.locations = 0;
     wined3d_resource_free_sysmem(&surface->resource);
     surface->resource.map_heap_memory = NULL;
+#else  /* STAGING_CSMT */
+        surface->dib.bitmap_data = NULL;
+        surface->flags &= ~SFLAG_DIBSECTION;
+        create_dib = TRUE;
+    }
+
+    surface->locations = 0;
+    wined3d_resource_free_sysmem(&surface->resource);
+#endif /* STAGING_CSMT */
 
     width = texture_resource->width;
     height = texture_resource->height;
@@ -1890,6 +2337,7 @@
     else
         surface->flags &= ~SFLAG_NONPOW2;
 
+#if defined(STAGING_CSMT)
     if ((surface->resource.user_memory = mem))
     {
         surface->resource.map_binding = WINED3D_LOCATION_USER_MEMORY;
@@ -1910,6 +2358,27 @@
         surface->resource.size = wined3d_format_calculate_size(texture_resource->format,
                 1, width, height, 1);
         surface->resource.custom_row_pitch = wined3d_format_calculate_pitch(texture_resource->format, width);
+#else  /* STAGING_CSMT */
+    if ((surface->user_memory = mem))
+    {
+        surface->resource.map_binding = WINED3D_LOCATION_USER_MEMORY;
+        valid_location = WINED3D_LOCATION_USER_MEMORY;
+    }
+    surface->pitch = pitch;
+    surface->resource.format = texture_resource->format;
+    surface->resource.multisample_type = texture_resource->multisample_type;
+    surface->resource.multisample_quality = texture_resource->multisample_quality;
+    if (surface->pitch)
+    {
+        surface->resource.size = height * surface->pitch;
+    }
+    else
+    {
+        /* User memory surfaces don't have the regular surface alignment. */
+        surface->resource.size = wined3d_format_calculate_size(texture_resource->format,
+                1, width, height, 1);
+        surface->pitch = wined3d_format_calculate_pitch(texture_resource->format, width);
+#endif /* STAGING_CSMT */
     }
 
     /* The format might be changed to a format that needs conversion.
@@ -1932,11 +2401,19 @@
 
     if (!valid_location)
     {
+#if defined(STAGING_CSMT)
         wined3d_resource_prepare_system_memory(&surface->resource);
         valid_location = WINED3D_LOCATION_SYSMEM;
     }
 
     wined3d_resource_validate_location(&surface->resource, valid_location);
+#else  /* STAGING_CSMT */
+        surface_prepare_system_memory(surface);
+        valid_location = WINED3D_LOCATION_SYSMEM;
+    }
+
+    surface_validate_location(surface, valid_location);
+#endif /* STAGING_CSMT */
 
     return WINED3D_OK;
 }
@@ -2295,6 +2772,7 @@
 
 static struct wined3d_texture *surface_convert_format(struct wined3d_surface *source, enum wined3d_format_id to_fmt)
 {
+#if defined(STAGING_CSMT)
     void *dst_data = NULL, *src_data = NULL;
     UINT src_row_pitch, src_slice_pitch, dst_row_pitch, dst_slice_pitch;
     const struct d3dfmt_converter_desc *conv;
@@ -2303,6 +2781,13 @@
     struct wined3d_surface *dst;
     struct wined3d_context *context = NULL;
     struct wined3d_device *device = source->resource.device;
+#else  /* STAGING_CSMT */
+    struct wined3d_map_desc src_map, dst_map;
+    const struct d3dfmt_converter_desc *conv;
+    struct wined3d_texture *ret = NULL;
+    struct wined3d_resource_desc desc;
+    struct wined3d_surface *dst;
+#endif /* STAGING_CSMT */
 
     conv = find_converter(source->resource.format->id, to_fmt);
     if (!conv)
@@ -2326,6 +2811,7 @@
     }
     dst = surface_from_resource(wined3d_texture_get_sub_resource(ret, 0));
 
+#if defined(STAGING_CSMT)
     wined3d_resource_get_pitch(&source->resource, &src_row_pitch, &src_slice_pitch);
     wined3d_resource_get_pitch(&ret->resource, &dst_row_pitch, &dst_slice_pitch);
 
@@ -2366,6 +2852,32 @@
     if (context)
         context_release(context);
     return NULL;
+#else  /* STAGING_CSMT */
+    memset(&src_map, 0, sizeof(src_map));
+    memset(&dst_map, 0, sizeof(dst_map));
+
+    if (FAILED(wined3d_surface_map(source, &src_map, NULL, WINED3D_MAP_READONLY)))
+    {
+        ERR("Failed to lock the source surface.\n");
+        wined3d_texture_decref(ret);
+        return NULL;
+    }
+    if (FAILED(wined3d_surface_map(dst, &dst_map, NULL, 0)))
+    {
+        ERR("Failed to lock the destination surface.\n");
+        wined3d_surface_unmap(source);
+        wined3d_texture_decref(ret);
+        return NULL;
+    }
+
+    conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch,
+            source->resource.width, source->resource.height);
+
+    wined3d_surface_unmap(dst);
+    wined3d_surface_unmap(source);
+
+    return ret;
+#endif /* STAGING_CSMT */
 }
 
 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
@@ -2433,6 +2945,7 @@
 
 HRESULT CDECL wined3d_surface_unmap(struct wined3d_surface *surface)
 {
+#if defined(STAGING_CSMT)
     HRESULT hr;
     TRACE("surface %p.\n", surface);
 
@@ -2443,6 +2956,20 @@
     memset(&surface->lockedRect, 0, sizeof(surface->lockedRect));
 
     return hr;
+#else  /* STAGING_CSMT */
+    TRACE("surface %p.\n", surface);
+
+    if (!surface->resource.map_count)
+    {
+        WARN("Trying to unmap unmapped surface.\n");
+        return WINEDDERR_NOTLOCKED;
+    }
+    --surface->resource.map_count;
+
+    surface->surface_ops->surface_unmap(surface);
+
+    return WINED3D_OK;
+#endif /* STAGING_CSMT */
 }
 
 HRESULT CDECL wined3d_surface_map(struct wined3d_surface *surface,
@@ -2450,10 +2977,25 @@
 {
     const struct wined3d_format *format = surface->resource.format;
     unsigned int fmt_flags = surface->container->resource.format_flags;
+#if !defined(STAGING_CSMT)
+    struct wined3d_device *device = surface->resource.device;
+    struct wined3d_context *context;
+    const struct wined3d_gl_info *gl_info;
+    BYTE *base_memory;
 
-    if ((fmt_flags & WINED3DFMT_FLAG_BLOCKS) && box
-            && !surface_check_block_align(surface, box))
-    {
+    TRACE("surface %p, map_desc %p, box %p, flags %#x.\n",
+            surface, map_desc, box, flags);
+
+    if (surface->resource.map_count)
+    {
+        WARN("Surface is already mapped.\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+#endif /* STAGING_CSMT */
+
+    if ((fmt_flags & WINED3DFMT_FLAG_BLOCKS) && box
+            && !surface_check_block_align(surface, box))
+    {
         WARN("Map rect %p is misaligned for %ux%u blocks.\n",
                 box, format->block_width, format->block_height);
 
@@ -2461,6 +3003,13 @@
             return WINED3DERR_INVALIDCALL;
     }
 
+#if !defined(STAGING_CSMT)
+    ++surface->resource.map_count;
+
+    if (!(surface->resource.access_flags & WINED3D_RESOURCE_ACCESS_CPU))
+        WARN("Trying to lock unlockable surface.\n");
+
+#endif /* STAGING_CSMT */
     /* Performance optimization: Count how often a surface is mapped, if it is
      * mapped regularly do not throw away the system memory copy. This avoids
      * the need to download the surface from OpenGL all the time. The surface
@@ -2476,6 +3025,7 @@
         }
     }
 
+#if defined(STAGING_CSMT)
     if (box)
     {
         surface->lockedRect.left = box->left;
@@ -2499,6 +3049,120 @@
     HRESULT hr;
     struct wined3d_device *device = surface->resource.device;
     struct wined3d_context *context = NULL;
+#else  /* STAGING_CSMT */
+    surface_prepare_map_memory(surface);
+    if (flags & WINED3D_MAP_DISCARD)
+    {
+        TRACE("WINED3D_MAP_DISCARD flag passed, marking %s as up to date.\n",
+                wined3d_debug_location(surface->resource.map_binding));
+        surface_validate_location(surface, surface->resource.map_binding);
+    }
+    else
+    {
+        struct wined3d_context *context = NULL;
+
+        if (surface->resource.usage & WINED3DUSAGE_DYNAMIC)
+            WARN_(d3d_perf)("Mapping a dynamic surface without WINED3D_MAP_DISCARD.\n");
+
+        if (surface->resource.device->d3d_initialized)
+            context = context_acquire(surface->resource.device, NULL);
+        surface_load_location(surface, context, surface->resource.map_binding);
+        if (context)
+            context_release(context);
+    }
+
+    if (!(flags & (WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY)))
+        surface_invalidate_location(surface, ~surface->resource.map_binding);
+
+    switch (surface->resource.map_binding)
+    {
+        case WINED3D_LOCATION_SYSMEM:
+            base_memory = surface->resource.heap_memory;
+            break;
+
+        case WINED3D_LOCATION_USER_MEMORY:
+            base_memory = surface->user_memory;
+            break;
+
+        case WINED3D_LOCATION_DIB:
+            base_memory = surface->dib.bitmap_data;
+            break;
+
+        case WINED3D_LOCATION_BUFFER:
+            context = context_acquire(device, NULL);
+            gl_info = context->gl_info;
+
+            GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, surface->pbo));
+            base_memory = GL_EXTCALL(glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE));
+            GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
+            checkGLcall("map PBO");
+
+            context_release(context);
+            break;
+
+        default:
+            ERR("Unexpected map binding %s.\n", wined3d_debug_location(surface->resource.map_binding));
+            base_memory = NULL;
+    }
+
+    if (fmt_flags & WINED3DFMT_FLAG_BROKEN_PITCH)
+        map_desc->row_pitch = surface->resource.width * format->byte_count;
+    else
+        map_desc->row_pitch = wined3d_surface_get_pitch(surface);
+    map_desc->slice_pitch = surface->resource.height * map_desc->row_pitch;
+
+    if (!box)
+    {
+        map_desc->data = base_memory;
+        surface->lockedRect.left = 0;
+        surface->lockedRect.top = 0;
+        surface->lockedRect.right = surface->resource.width;
+        surface->lockedRect.bottom = surface->resource.height;
+    }
+    else
+    {
+        if ((fmt_flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
+        {
+            /* Compressed textures are block based, so calculate the offset of
+             * the block that contains the top-left pixel of the locked rectangle. */
+            map_desc->data = base_memory
+                    + ((box->top / format->block_height) * map_desc->row_pitch)
+                    + ((box->left / format->block_width) * format->block_byte_count);
+        }
+        else
+        {
+            map_desc->data = base_memory
+                    + (map_desc->row_pitch * box->top)
+                    + (box->left * format->byte_count);
+        }
+        surface->lockedRect.left = box->left;
+        surface->lockedRect.top = box->top;
+        surface->lockedRect.right = box->right;
+        surface->lockedRect.bottom = box->bottom;
+    }
+
+    TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
+    TRACE("Returning memory %p, pitch %u.\n", map_desc->data, map_desc->row_pitch);
+
+    return WINED3D_OK;
+}
+
+HRESULT CDECL wined3d_surface_getdc(struct wined3d_surface *surface, HDC *dc)
+{
+    HRESULT hr;
+    struct wined3d_device *device = surface->resource.device;
+    struct wined3d_context *context = NULL;
+
+    TRACE("surface %p, dc %p.\n", surface, dc);
+
+    /* Give more detailed info for ddraw. */
+    if (surface->flags & SFLAG_DCINUSE)
+        return WINEDDERR_DCALREADYCREATED;
+
+    /* Can't GetDC if the surface is locked. */
+    if (surface->resource.map_count)
+        return WINED3DERR_INVALIDCALL;
+#endif /* STAGING_CSMT */
 
     if (device->d3d_initialized)
         context = context_acquire(surface->resource.device, NULL);
@@ -2510,6 +3174,7 @@
         {
             if (context)
                 context_release(context);
+#if defined(STAGING_CSMT)
             return;
         }
         if (!(surface->resource.map_binding == WINED3D_LOCATION_USER_MEMORY
@@ -2557,6 +3222,50 @@
 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
+#else  /* STAGING_CSMT */
+             return WINED3DERR_INVALIDCALL;
+        }
+        if (!(surface->resource.map_binding == WINED3D_LOCATION_USER_MEMORY
+                || surface->container->flags & WINED3D_TEXTURE_PIN_SYSMEM
+                || surface->pbo))
+            surface->resource.map_binding = WINED3D_LOCATION_DIB;
+    }
+
+    surface_load_location(surface, context, WINED3D_LOCATION_DIB);
+    surface_invalidate_location(surface, ~WINED3D_LOCATION_DIB);
+
+    if (context)
+        context_release(context);
+
+    surface->flags |= SFLAG_DCINUSE;
+    surface->resource.map_count++;
+
+    *dc = surface->hDC;
+    TRACE("Returning dc %p.\n", *dc);
+
+    return WINED3D_OK;
+}
+
+HRESULT CDECL wined3d_surface_releasedc(struct wined3d_surface *surface, HDC dc)
+{
+    TRACE("surface %p, dc %p.\n", surface, dc);
+
+    if (!(surface->flags & SFLAG_DCINUSE))
+        return WINEDDERR_NODC;
+
+    if (surface->hDC != dc)
+    {
+        WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
+                dc, surface->hDC);
+        return WINEDDERR_NODC;
+    }
+
+    surface->resource.map_count--;
+    surface->flags &= ~SFLAG_DCINUSE;
+
+    if (surface->resource.map_binding == WINED3D_LOCATION_USER_MEMORY
+            || (surface->container->flags & WINED3D_TEXTURE_PIN_SYSMEM
+#endif /* STAGING_CSMT */
             && surface->resource.map_binding != WINED3D_LOCATION_DIB))
     {
         /* The game Salammbo modifies the surface contents without mapping the surface between
@@ -2572,6 +3281,7 @@
         if (device->d3d_initialized)
             context = context_acquire(device, NULL);
 
+#if defined(STAGING_CSMT)
         wined3d_resource_load_location(&surface->resource, context, surface->resource.map_binding);
         wined3d_resource_invalidate_location(&surface->resource, WINED3D_LOCATION_DIB);
         if (context)
@@ -2597,6 +3307,13 @@
     surface->flags &= ~SFLAG_DCINUSE;
 
     wined3d_cs_emit_releasedc(surface->resource.device->cs, surface);
+#else  /* STAGING_CSMT */
+        surface_load_location(surface, context, surface->resource.map_binding);
+        surface_invalidate_location(surface, WINED3D_LOCATION_DIB);
+        if (context)
+            context_release(context);
+    }
+#endif /* STAGING_CSMT */
 
     return WINED3D_OK;
 }
@@ -2613,9 +3330,14 @@
     int i;
     BOOL srcIsUpsideDown;
     struct wined3d_bo_address data;
+#if defined(STAGING_CSMT)
     DWORD slice_pitch, pitch;
 
     wined3d_resource_get_memory(&surface->resource, dst_location, &data);
+#else  /* STAGING_CSMT */
+
+    surface_get_memory(surface, &data, dst_location);
+#endif /* STAGING_CSMT */
 
     if (surface != old_ctx->current_rt)
     {
@@ -2655,8 +3377,13 @@
     }
 
     /* Setup pixel store pack state -- to glReadPixels into the correct place */
+#if defined(STAGING_CSMT)
     wined3d_resource_get_pitch(&surface->resource, &pitch, &slice_pitch);
     gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, pitch / surface->resource.format->byte_count);
+#else  /* STAGING_CSMT */
+    gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH,
+            wined3d_surface_get_pitch(surface) / surface->resource.format->byte_count);
+#endif /* STAGING_CSMT */
     checkGLcall("glPixelStorei");
 
     gl_info->gl_ops.gl.p_glReadPixels(0, 0,
@@ -2673,6 +3400,10 @@
     {
         /* glReadPixels returns the image upside down, and there is no way to prevent this.
          * Flip the lines in software. */
+#if !defined(STAGING_CSMT)
+        UINT pitch = wined3d_surface_get_pitch(surface);
+
+#endif /* STAGING_CSMT */
         if (!(row = HeapAlloc(GetProcessHeap(), 0, pitch)))
             goto error;
 
@@ -2899,8 +3630,13 @@
 
     /* The texture is now most up to date - If the surface is a render target
      * and has a drawable, this path is never entered. */
+#if defined(STAGING_CSMT)
     wined3d_resource_validate_location(&dst_surface->resource, WINED3D_LOCATION_TEXTURE_RGB);
     wined3d_resource_invalidate_location(&dst_surface->resource, ~WINED3D_LOCATION_TEXTURE_RGB);
+#else  /* STAGING_CSMT */
+    surface_validate_location(dst_surface, WINED3D_LOCATION_TEXTURE_RGB);
+    surface_invalidate_location(dst_surface, ~WINED3D_LOCATION_TEXTURE_RGB);
+#endif /* STAGING_CSMT */
 }
 
 /* Uses the hardware to stretch and flip the image */
@@ -2968,7 +3704,11 @@
         checkGLcall("glEnable(texture_target)");
 
         /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
+#if defined(STAGING_CSMT)
         wined3d_resource_invalidate_location(&src_surface->resource, WINED3D_LOCATION_TEXTURE_RGB);
+#else  /* STAGING_CSMT */
+        src_surface->locations &= ~WINED3D_LOCATION_TEXTURE_RGB;
+#endif /* STAGING_CSMT */
     }
 
     /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
@@ -3165,6 +3905,7 @@
         checkGLcall("glDeleteTextures(1, &backup)");
     }
 
+#if defined(STAGING_CSMT)
     if (wined3d_settings.cs_multithreaded)
         gl_info->gl_ops.gl.p_glFinish();
     else if (wined3d_settings.strict_draw_ordering)
@@ -3176,6 +3917,17 @@
      * and has a drawable, this path is never entered. */
     wined3d_resource_validate_location(&dst_surface->resource, WINED3D_LOCATION_TEXTURE_RGB);
     wined3d_resource_invalidate_location(&dst_surface->resource, ~WINED3D_LOCATION_TEXTURE_RGB);
+#else  /* STAGING_CSMT */
+    if (wined3d_settings.strict_draw_ordering)
+        gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
+
+    context_release(context);
+
+    /* The texture is now most up to date - If the surface is a render target
+     * and has a drawable, this path is never entered. */
+    surface_validate_location(dst_surface, WINED3D_LOCATION_TEXTURE_RGB);
+    surface_invalidate_location(dst_surface, ~WINED3D_LOCATION_TEXTURE_RGB);
+#endif /* STAGING_CSMT */
 }
 
 /* Front buffer coordinates are always full screen coordinates, but our GL
@@ -3230,9 +3982,15 @@
 
     gl_info = context->gl_info;
 
+#if defined(STAGING_CSMT)
     /* Make sure the surface is up-to-date. This should probably use
      * wined3d_resource_load_location() and worry about the destination
      * surface too, unless we're overwriting it completely. */
+#else  /* STAGING_CSMT */
+    /* Make sure the surface is up-to-date. This should probably use
+     * surface_load_location() and worry about the destination surface too,
+     * unless we're overwriting it completely. */
+#endif /* STAGING_CSMT */
     wined3d_texture_load(src_surface->container, context, FALSE);
 
     /* Activate the destination context, set it up for blitting */
@@ -3275,9 +4033,13 @@
     /* Leave the opengl state valid for blitting */
     device->blitter->unset_shader(context->gl_info);
 
+#if defined(STAGING_CSMT)
     if (wined3d_settings.cs_multithreaded)
         gl_info->gl_ops.gl.p_glFinish();
     else if (wined3d_settings.strict_draw_ordering
+#else  /* STAGING_CSMT */
+    if (wined3d_settings.strict_draw_ordering
+#endif /* STAGING_CSMT */
             || (dst_surface->container->swapchain
             && dst_surface->container->swapchain->front_buffer == dst_surface->container))
         gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
@@ -3307,8 +4069,13 @@
         enum wined3d_texture_filter_type filter)
 {
     struct wined3d_device *device = dst_surface->resource.device;
+#if defined(STAGING_CSMT)
     struct wined3d_swapchain *src_swapchain, *dst_swapchain;
     const struct wined3d_surface *rt = wined3d_rendertarget_view_get_surface(device->state.fb.render_targets[0]);
+#else  /* STAGING_CSMT */
+    const struct wined3d_surface *rt = wined3d_rendertarget_view_get_surface(device->fb.render_targets[0]);
+    struct wined3d_swapchain *src_swapchain, *dst_swapchain;
+#endif /* STAGING_CSMT */
 
     TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
             dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
@@ -3499,6 +4266,7 @@
 {
     TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
 
+#if defined(STAGING_CSMT)
     if (((surface->resource.locations & WINED3D_LOCATION_TEXTURE_RGB) && !(location & WINED3D_LOCATION_TEXTURE_RGB))
             || (!(surface->resource.locations & WINED3D_LOCATION_TEXTURE_RGB)
             && (location & WINED3D_LOCATION_TEXTURE_RGB)))
@@ -3507,6 +4275,15 @@
     surface->ds_current_size.cx = w;
     surface->ds_current_size.cy = h;
     surface->resource.locations = location;
+#else  /* STAGING_CSMT */
+    if (((surface->locations & WINED3D_LOCATION_TEXTURE_RGB) && !(location & WINED3D_LOCATION_TEXTURE_RGB))
+            || (!(surface->locations & WINED3D_LOCATION_TEXTURE_RGB) && (location & WINED3D_LOCATION_TEXTURE_RGB)))
+        wined3d_texture_set_dirty(surface->container);
+
+    surface->ds_current_size.cx = w;
+    surface->ds_current_size.cy = h;
+    surface->locations = location;
+#endif /* STAGING_CSMT */
 }
 
 /* Context activation is done by the caller. */
@@ -3521,7 +4298,11 @@
     /* TODO: Make this work for modes other than FBO */
     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
 
+#if defined(STAGING_CSMT)
     if (!(surface->resource.locations & location))
+#else  /* STAGING_CSMT */
+    if (!(surface->locations & location))
+#endif /* STAGING_CSMT */
     {
         w = surface->ds_current_size.cx;
         h = surface->ds_current_size.cy;
@@ -3548,6 +4329,7 @@
     }
 
     wined3d_surface_prepare(surface, context, location);
+#if defined(STAGING_CSMT)
     if (surface->resource.locations & WINED3D_LOCATION_DISCARDED)
     {
         TRACE("Surface was discarded, no need copy data.\n");
@@ -3562,6 +4344,22 @@
     {
         FIXME("No up to date depth stencil location.\n");
         surface->resource.locations |= location;
+#else  /* STAGING_CSMT */
+    if (surface->locations & WINED3D_LOCATION_DISCARDED)
+    {
+        TRACE("Surface was discarded, no need copy data.\n");
+        surface->locations &= ~WINED3D_LOCATION_DISCARDED;
+        surface->locations |= location;
+        surface->ds_current_size.cx = surface->resource.width;
+        surface->ds_current_size.cy = surface->resource.height;
+        return;
+    }
+
+    if (!surface->locations)
+    {
+        FIXME("No up to date depth stencil location.\n");
+        surface->locations |= location;
+#endif /* STAGING_CSMT */
         surface->ds_current_size.cx = surface->resource.width;
         surface->ds_current_size.cy = surface->resource.height;
         return;
@@ -3625,9 +4423,13 @@
 
         context_invalidate_state(context, STATE_FRAMEBUFFER);
 
+#if defined(STAGING_CSMT)
         if (wined3d_settings.cs_multithreaded)
             gl_info->gl_ops.gl.p_glFinish();
         else if (wined3d_settings.strict_draw_ordering)
+#else  /* STAGING_CSMT */
+        if (wined3d_settings.strict_draw_ordering)
+#endif /* STAGING_CSMT */
             gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
     }
     else if (location == WINED3D_LOCATION_DRAWABLE)
@@ -3643,9 +4445,13 @@
 
         context_invalidate_state(context, STATE_FRAMEBUFFER);
 
+#if defined(STAGING_CSMT)
         if (wined3d_settings.cs_multithreaded)
             gl_info->gl_ops.gl.p_glFinish();
         else if (wined3d_settings.strict_draw_ordering)
+#else  /* STAGING_CSMT */
+        if (wined3d_settings.strict_draw_ordering)
+#endif /* STAGING_CSMT */
             gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
     }
     else
@@ -3653,6 +4459,7 @@
         ERR("Invalid location (%#x) specified.\n", location);
     }
 
+#if defined(STAGING_CSMT)
     surface->resource.locations |= location;
     surface->ds_current_size.cx = surface->resource.width;
     surface->ds_current_size.cy = surface->resource.height;
@@ -3685,6 +4492,124 @@
 
     FIXME("Can't load surface %p with location flags %s into sysmem.\n",
             surface, wined3d_debug_location(surface->resource.locations));
+#else  /* STAGING_CSMT */
+    surface->locations |= location;
+    surface->ds_current_size.cx = surface->resource.width;
+    surface->ds_current_size.cy = surface->resource.height;
+}
+
+void surface_validate_location(struct wined3d_surface *surface, DWORD location)
+{
+    TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
+
+    surface->locations |= location;
+}
+
+void surface_invalidate_location(struct wined3d_surface *surface, DWORD location)
+{
+    TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
+
+    if (location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
+        wined3d_texture_set_dirty(surface->container);
+    surface->locations &= ~location;
+
+    if (!surface->locations)
+        ERR("Surface %p does not have any up to date location.\n", surface);
+}
+
+static DWORD resource_access_from_location(DWORD location)
+{
+    switch (location)
+    {
+        case WINED3D_LOCATION_SYSMEM:
+        case WINED3D_LOCATION_USER_MEMORY:
+        case WINED3D_LOCATION_DIB:
+        case WINED3D_LOCATION_BUFFER:
+            return WINED3D_RESOURCE_ACCESS_CPU;
+
+        case WINED3D_LOCATION_DRAWABLE:
+        case WINED3D_LOCATION_TEXTURE_SRGB:
+        case WINED3D_LOCATION_TEXTURE_RGB:
+        case WINED3D_LOCATION_RB_MULTISAMPLE:
+        case WINED3D_LOCATION_RB_RESOLVED:
+            return WINED3D_RESOURCE_ACCESS_GPU;
+
+        default:
+            FIXME("Unhandled location %#x.\n", location);
+            return 0;
+    }
+}
+
+static void surface_copy_simple_location(struct wined3d_surface *surface, DWORD location)
+{
+    struct wined3d_device *device = surface->resource.device;
+    struct wined3d_context *context;
+    const struct wined3d_gl_info *gl_info;
+    struct wined3d_bo_address dst, src;
+    UINT size = surface->resource.size;
+
+    surface_get_memory(surface, &dst, location);
+    surface_get_memory(surface, &src, surface->locations);
+
+    if (dst.buffer_object)
+    {
+        context = context_acquire(device, NULL);
+        gl_info = context->gl_info;
+        GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, dst.buffer_object));
+        GL_EXTCALL(glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, size, src.addr));
+        GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
+        checkGLcall("Upload PBO");
+        context_release(context);
+        return;
+    }
+    if (src.buffer_object)
+    {
+        context = context_acquire(device, NULL);
+        gl_info = context->gl_info;
+        GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, src.buffer_object));
+        GL_EXTCALL(glGetBufferSubData(GL_PIXEL_PACK_BUFFER, 0, size, dst.addr));
+        GL_EXTCALL(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));
+        checkGLcall("Download PBO");
+        context_release(context);
+        return;
+    }
+    memcpy(dst.addr, src.addr, size);
+}
+
+/* Context activation is done by the caller. */
+static void surface_load_sysmem(struct wined3d_surface *surface,
+        struct wined3d_context *context, DWORD dst_location)
+{
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+
+    if (surface->locations & surface_simple_locations)
+    {
+        surface_copy_simple_location(surface, dst_location);
+        return;
+    }
+
+    if (surface->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED))
+        surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
+
+    /* Download the surface to system memory. */
+    if (surface->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
+    {
+        wined3d_texture_bind_and_dirtify(surface->container, context,
+                !(surface->locations & WINED3D_LOCATION_TEXTURE_RGB));
+        surface_download_data(surface, gl_info, dst_location);
+
+        return;
+    }
+
+    if (surface->locations & WINED3D_LOCATION_DRAWABLE)
+    {
+        read_from_framebuffer(surface, context, dst_location);
+        return;
+    }
+
+    FIXME("Can't load surface %p with location flags %s into sysmem.\n",
+            surface, wined3d_debug_location(surface->locations));
+#endif /* STAGING_CSMT */
 }
 
 /* Context activation is done by the caller. */
@@ -3693,12 +4618,14 @@
 {
     RECT r;
 
+#if defined(STAGING_CSMT)
     if (surface->resource.locations & WINED3D_LOCATION_DISCARDED)
     {
         TRACE("Surface was discarded, nothing to do.\n");
         return WINED3D_OK;
     }
 
+#endif /* STAGING_CSMT */
     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
             && wined3d_resource_is_offscreen(&surface->container->resource))
     {
@@ -3707,7 +4634,11 @@
     }
 
     surface_get_rect(surface, NULL, &r);
+#if defined(STAGING_CSMT)
     wined3d_resource_load_location(&surface->resource, context, WINED3D_LOCATION_TEXTURE_RGB);
+#else  /* STAGING_CSMT */
+    surface_load_location(surface, context, WINED3D_LOCATION_TEXTURE_RGB);
+#endif /* STAGING_CSMT */
     surface_blt_to_drawable(surface->resource.device, context,
             WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
 
@@ -3722,6 +4653,7 @@
     struct wined3d_device *device = surface->resource.device;
     const struct wined3d_color_key_conversion *conversion;
     struct wined3d_texture *texture = surface->container;
+#if defined(STAGING_CSMT)
     UINT width, src_row_pitch, src_slice_pitch, dst_pitch;
     struct wined3d_bo_address data;
     struct wined3d_format format;
@@ -3748,6 +4680,24 @@
     }
 
     if (surface->resource.locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
+#else  /* STAGING_CSMT */
+    UINT width, src_pitch, dst_pitch;
+    struct wined3d_bo_address data;
+    struct wined3d_format format;
+    POINT dst_point = {0, 0};
+    BYTE *mem = NULL;
+
+    if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
+            && wined3d_resource_is_offscreen(&texture->resource)
+            && (surface->locations & WINED3D_LOCATION_DRAWABLE))
+    {
+        surface_load_fb_texture(surface, srgb, context);
+
+        return WINED3D_OK;
+    }
+
+    if (surface->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
+#endif /* STAGING_CSMT */
             && (surface->container->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
             && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
                 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
@@ -3763,6 +4713,7 @@
         return WINED3D_OK;
     }
 
+#if defined(STAGING_CSMT)
     if (surface->resource.locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
             && (!srgb || (surface->container->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
             && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
@@ -3770,6 +4721,15 @@
                 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
     {
         DWORD src_location = surface->resource.locations & WINED3D_LOCATION_RB_RESOLVED ?
+#else  /* STAGING_CSMT */
+    if (surface->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
+            && (!srgb || (surface->container->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
+            && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
+                NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
+                NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
+    {
+        DWORD src_location = surface->locations & WINED3D_LOCATION_RB_RESOLVED ?
+#endif /* STAGING_CSMT */
                 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
         DWORD dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
         RECT rect = {0, 0, surface->resource.width, surface->resource.height};
@@ -3784,6 +4744,7 @@
 
     if (srgb)
     {
+#if defined(STAGING_CSMT)
         if ((surface->resource.locations & (WINED3D_LOCATION_TEXTURE_RGB | surface->resource.map_binding))
                 == WINED3D_LOCATION_TEXTURE_RGB)
         {
@@ -3818,15 +4779,55 @@
 
     width = surface->resource.width;
     wined3d_resource_get_pitch(&surface->resource, &src_row_pitch, &src_slice_pitch);
-
-    format = *texture->resource.format;
-    if ((conversion = wined3d_format_get_color_key_conversion(texture, TRUE)))
-        format = *wined3d_get_format(gl_info, conversion->dst_format);
-
-    /* Don't use PBOs for converted surfaces. During PBO conversion we look at
-     * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
-     * getting called. */
-    if ((format.convert || conversion) && surface->resource.buffer)
+#else  /* STAGING_CSMT */
+        if ((surface->locations & (WINED3D_LOCATION_TEXTURE_RGB | surface->resource.map_binding))
+                == WINED3D_LOCATION_TEXTURE_RGB)
+        {
+            /* Performance warning... */
+            FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
+            surface_prepare_map_memory(surface);
+            surface_load_location(surface, context, surface->resource.map_binding);
+        }
+    }
+    else
+    {
+        if ((surface->locations & (WINED3D_LOCATION_TEXTURE_SRGB | surface->resource.map_binding))
+                == WINED3D_LOCATION_TEXTURE_SRGB)
+        {
+            /* Performance warning... */
+            FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
+            surface_prepare_map_memory(surface);
+            surface_load_location(surface, context, surface->resource.map_binding);
+        }
+    }
+
+    if (!(surface->locations & surface_simple_locations))
+    {
+        WARN("Trying to load a texture from sysmem, but no simple location is valid.\n");
+        /* Lets hope we get it from somewhere... */
+        surface_prepare_system_memory(surface);
+        surface_load_location(surface, context, WINED3D_LOCATION_SYSMEM);
+    }
+
+    wined3d_texture_prepare_texture(texture, context, srgb);
+    wined3d_texture_bind_and_dirtify(texture, context, srgb);
+
+    width = surface->resource.width;
+    src_pitch = wined3d_surface_get_pitch(surface);
+#endif /* STAGING_CSMT */
+
+    format = *texture->resource.format;
+    if ((conversion = wined3d_format_get_color_key_conversion(texture, TRUE)))
+        format = *wined3d_get_format(gl_info, conversion->dst_format);
+
+    /* Don't use PBOs for converted surfaces. During PBO conversion we look at
+     * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
+     * getting called. */
+#if defined(STAGING_CSMT)
+    if ((format.convert || conversion) && surface->resource.buffer)
+#else  /* STAGING_CSMT */
+    if ((format.convert || conversion) && surface->pbo)
+#endif /* STAGING_CSMT */
     {
         TRACE("Removing the pbo attached to surface %p.\n", surface);
 
@@ -3835,6 +4836,7 @@
         else
             surface->resource.map_binding = WINED3D_LOCATION_SYSMEM;
 
+#if defined(STAGING_CSMT)
         wined3d_resource_prepare_map_memory(&surface->resource, context);
         wined3d_resource_load_location(&surface->resource, context, surface->resource.map_binding);
         wined3d_resource_free_bo(&surface->resource);
@@ -3842,6 +4844,14 @@
     }
 
     wined3d_resource_get_memory(&surface->resource, surface->resource.locations, &data);
+#else  /* STAGING_CSMT */
+        surface_prepare_map_memory(surface);
+        surface_load_location(surface, context, surface->resource.map_binding);
+        surface_remove_pbo(surface, gl_info);
+    }
+
+    surface_get_memory(surface, &data, surface->locations);
+#endif /* STAGING_CSMT */
     if (format.convert)
     {
         /* This code is entered for texture formats which need a fixup. */
@@ -3856,9 +4866,15 @@
             context_release(context);
             return E_OUTOFMEMORY;
         }
+#if defined(STAGING_CSMT)
         format.convert(data.addr, mem, src_row_pitch, src_row_pitch * height,
                 dst_pitch, dst_pitch * height, width, height, 1);
         src_row_pitch = dst_pitch;
+#else  /* STAGING_CSMT */
+        format.convert(data.addr, mem, src_pitch, src_pitch * height,
+                dst_pitch, dst_pitch * height, width, height, 1);
+        src_pitch = dst_pitch;
+#endif /* STAGING_CSMT */
         data.addr = mem;
     }
     else if (conversion)
@@ -3878,6 +4894,7 @@
         }
         if (texture->swapchain && texture->swapchain->palette)
             palette = texture->swapchain->palette;
+#if defined(STAGING_CSMT)
         conversion->convert(data.addr, src_row_pitch, mem, dst_pitch,
                 width, height, palette, &texture->async.gl_color_key);
         src_row_pitch = dst_pitch;
@@ -3886,6 +4903,16 @@
 
     wined3d_surface_upload_data(surface, gl_info, &format, &src_rect,
             src_row_pitch, &dst_point, srgb, wined3d_const_bo_address(&data));
+#else  /* STAGING_CSMT */
+        conversion->convert(data.addr, src_pitch, mem, dst_pitch,
+                width, height, palette, &texture->async.gl_color_key);
+        src_pitch = dst_pitch;
+        data.addr = mem;
+    }
+
+    wined3d_surface_upload_data(surface, gl_info, &format, &src_rect,
+            src_pitch, &dst_point, srgb, wined3d_const_bo_address(&data));
+#endif /* STAGING_CSMT */
 
     HeapFree(GetProcessHeap(), 0, mem);
 
@@ -3899,11 +4926,19 @@
     const RECT rect = {0, 0, surface->resource.width, surface->resource.height};
     DWORD src_location;
 
+#if defined(STAGING_CSMT)
     if (surface->resource.locations & WINED3D_LOCATION_RB_MULTISAMPLE)
         src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
     else if (surface->resource.locations & WINED3D_LOCATION_RB_RESOLVED)
         src_location = WINED3D_LOCATION_RB_RESOLVED;
     else if (surface->resource.locations & WINED3D_LOCATION_TEXTURE_SRGB)
+#else  /* STAGING_CSMT */
+    if (surface->locations & WINED3D_LOCATION_RB_MULTISAMPLE)
+        src_location = WINED3D_LOCATION_RB_MULTISAMPLE;
+    else if (surface->locations & WINED3D_LOCATION_RB_RESOLVED)
+        src_location = WINED3D_LOCATION_RB_RESOLVED;
+    else if (surface->locations & WINED3D_LOCATION_TEXTURE_SRGB)
+#endif /* STAGING_CSMT */
         src_location = WINED3D_LOCATION_TEXTURE_SRGB;
     else /* surface_blt_fbo will load the source location if necessary. */
         src_location = WINED3D_LOCATION_TEXTURE_RGB;
@@ -3912,11 +4947,17 @@
             surface, src_location, &rect, surface, dst_location, &rect);
 }
 
+#if defined(STAGING_CSMT)
 /* Context activation is done by the caller. */
 static void wined3d_surface_load_location(struct wined3d_resource *resource,
         struct wined3d_context *context, DWORD location)
 {
     struct wined3d_surface *surface = surface_from_resource(resource);
+#else  /* STAGING_CSMT */
+/* Context activation is done by the caller. Context may be NULL in ddraw-only mode. */
+HRESULT surface_load_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
+{
+#endif /* STAGING_CSMT */
     HRESULT hr;
 
     TRACE("surface %p, location %s.\n", surface, wined3d_debug_location(location));
@@ -3924,6 +4965,7 @@
     if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
     {
         if (location == WINED3D_LOCATION_TEXTURE_RGB
+#if defined(STAGING_CSMT)
                 && surface->resource.locations & (WINED3D_LOCATION_DRAWABLE | WINED3D_LOCATION_DISCARDED))
         {
             surface_load_ds_location(surface, context, location);
@@ -3947,6 +4989,45 @@
     {
         ERR("Surface %p does not have any up to date location.\n", surface);
         return;
+#else  /* STAGING_CSMT */
+                && surface->locations & (WINED3D_LOCATION_DRAWABLE | WINED3D_LOCATION_DISCARDED))
+        {
+            surface_load_ds_location(surface, context, location);
+            return WINED3D_OK;
+        }
+        else if (location & surface->locations
+                && surface->container->resource.draw_binding != WINED3D_LOCATION_DRAWABLE)
+        {
+            /* Already up to date, nothing to do. */
+            return WINED3D_OK;
+        }
+        else
+        {
+            FIXME("Unimplemented copy from %s to %s for depth/stencil buffers.\n",
+                    wined3d_debug_location(surface->locations), wined3d_debug_location(location));
+            return WINED3DERR_INVALIDCALL;
+        }
+    }
+
+    if (surface->locations & location)
+    {
+        TRACE("Location already up to date.\n");
+        return WINED3D_OK;
+    }
+
+    if (WARN_ON(d3d_surface))
+    {
+        DWORD required_access = resource_access_from_location(location);
+        if ((surface->resource.access_flags & required_access) != required_access)
+            WARN("Operation requires %#x access, but surface only has %#x.\n",
+                    required_access, surface->resource.access_flags);
+    }
+
+    if (!surface->locations)
+    {
+        ERR("Surface %p does not have any up to date location.\n", surface);
+        return WINED3DERR_INVALIDCALL;
+#endif /* STAGING_CSMT */
     }
 
     switch (location)
@@ -3960,7 +5041,11 @@
 
         case WINED3D_LOCATION_DRAWABLE:
             if (FAILED(hr = surface_load_drawable(surface, context)))
+#if defined(STAGING_CSMT)
                 return;
+#else  /* STAGING_CSMT */
+                return hr;
+#endif /* STAGING_CSMT */
             break;
 
         case WINED3D_LOCATION_RB_RESOLVED:
@@ -3972,7 +5057,11 @@
         case WINED3D_LOCATION_TEXTURE_SRGB:
             if (FAILED(hr = surface_load_texture(surface, context,
                     location == WINED3D_LOCATION_TEXTURE_SRGB)))
+#if defined(STAGING_CSMT)
                 return;
+#else  /* STAGING_CSMT */
+                return hr;
+#endif /* STAGING_CSMT */
             break;
 
         default:
@@ -3980,12 +5069,21 @@
             break;
     }
 
+#if defined(STAGING_CSMT)
     wined3d_resource_validate_location(&surface->resource, location);
 
     if (location != WINED3D_LOCATION_SYSMEM && (surface->resource.locations & WINED3D_LOCATION_SYSMEM))
         surface_evict_sysmem(surface);
 
     return;
+#else  /* STAGING_CSMT */
+    surface_validate_location(surface, location);
+
+    if (location != WINED3D_LOCATION_SYSMEM && (surface->locations & WINED3D_LOCATION_SYSMEM))
+        surface_evict_sysmem(surface);
+
+    return WINED3D_OK;
+#endif /* STAGING_CSMT */
 }
 
 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
@@ -4094,6 +5192,7 @@
         const RECT *dst_rect, const struct wined3d_color *color)
 {
     const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height};
+#if defined(STAGING_CSMT)
     struct wined3d_rendertarget_view view, *view_ptr = &view;
     struct wined3d_fb_state fb = {&view_ptr, NULL, 1};
     struct wined3d_texture *texture = dst_surface->container;
@@ -4114,6 +5213,21 @@
     view.sub_resource_idx = dst_surface->texture_layer * texture->level_count + dst_surface->texture_level;
 
     device_clear_render_targets(device, 1, &fb, 1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
+#else  /* STAGING_CSMT */
+    struct wined3d_rendertarget_view *view;
+    struct wined3d_fb_state fb = {&view, NULL};
+    HRESULT hr;
+
+    if (FAILED(hr = wined3d_rendertarget_view_create_from_surface(dst_surface,
+            NULL, &wined3d_null_parent_ops, &view)))
+    {
+        ERR("Failed to create rendertarget view, hr %#x.\n", hr);
+        return hr;
+    }
+
+    device_clear_render_targets(device, 1, &fb, 1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
+    wined3d_rendertarget_view_decref(view);
+#endif /* STAGING_CSMT */
 
     return WINED3D_OK;
 }
@@ -4122,6 +5236,7 @@
         const RECT *dst_rect, float depth)
 {
     const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height};
+#if defined(STAGING_CSMT)
     struct wined3d_rendertarget_view view;
     struct wined3d_fb_state fb = {NULL, &view};
     struct wined3d_texture *texture = dst_surface->container;
@@ -4137,6 +5252,20 @@
     view.sub_resource_idx = dst_surface->texture_layer * texture->level_count + dst_surface->texture_level;
 
     device_clear_render_targets(device, 0, &fb, 1, dst_rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
+#else  /* STAGING_CSMT */
+    struct wined3d_fb_state fb = {NULL, NULL};
+    HRESULT hr;
+
+    if (FAILED(hr = wined3d_rendertarget_view_create_from_surface(dst_surface,
+            NULL, &wined3d_null_parent_ops, &fb.depth_stencil)))
+    {
+        ERR("Failed to create rendertarget view, hr %#x.\n", hr);
+        return hr;
+    }
+
+    device_clear_render_targets(device, 0, &fb, 1, dst_rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
+    wined3d_rendertarget_view_decref(fb.depth_stencil);
+#endif /* STAGING_CSMT */
 
     return WINED3D_OK;
 }
@@ -4173,8 +5302,13 @@
     wined3d_texture_set_color_key(src_surface->container, WINED3D_CKEY_SRC_BLT,
             (old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_blt_key : NULL);
 
+#if defined(STAGING_CSMT)
     wined3d_resource_validate_location(&dst_surface->resource, dst_surface->container->resource.draw_binding);
     wined3d_resource_invalidate_location(&dst_surface->resource, ~dst_surface->container->resource.draw_binding);
+#else  /* STAGING_CSMT */
+    surface_validate_location(dst_surface, dst_surface->container->resource.draw_binding);
+    surface_invalidate_location(dst_surface, ~dst_surface->container->resource.draw_binding);
+#endif /* STAGING_CSMT */
 }
 
 const struct blit_shader ffp_blit =  {
@@ -4330,6 +5464,7 @@
         struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
         const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
 {
+#if defined(STAGING_CSMT)
     int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
     const struct wined3d_format *src_format, *dst_format;
     unsigned int src_fmt_flags, dst_fmt_flags;
@@ -4364,6 +5499,28 @@
         wined3d_resource_get_pitch(&dst_surface->resource, &dst_row_pitch, &dst_slice_pitch);
         src_data = dst_data;
         src_row_pitch = dst_row_pitch;
+#else  /* STAGING_CSMT */
+    const struct wined3d_box dst_box = {dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, 0, 1};
+    int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
+    const struct wined3d_format *src_format, *dst_format;
+    unsigned int src_fmt_flags, dst_fmt_flags;
+    struct wined3d_texture *src_texture = NULL;
+    struct wined3d_map_desc dst_map, src_map;
+    const BYTE *sbase = NULL;
+    HRESULT hr = WINED3D_OK;
+    const BYTE *sbuf;
+    BYTE *dbuf;
+    int x, y;
+
+    TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
+            dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
+            flags, fx, debug_d3dtexturefiltertype(filter));
+
+    if (src_surface == dst_surface)
+    {
+        wined3d_surface_map(dst_surface, &dst_map, NULL, 0);
+        src_map = dst_map;
+#endif /* STAGING_CSMT */
         src_format = dst_surface->resource.format;
         dst_format = src_format;
         dst_fmt_flags = dst_surface->container->resource.format_flags;
@@ -4375,12 +5532,14 @@
         dst_fmt_flags = dst_surface->container->resource.format_flags;
         if (src_surface)
         {
+#if defined(STAGING_CSMT)
             if (!wined3d_resource_prepare_map_memory(&src_surface->resource, context))
             {
                 hr = E_OUTOFMEMORY;
                 goto error;
             }
 
+#endif /* STAGING_CSMT */
             if (dst_surface->resource.format->id != src_surface->resource.format->id)
             {
                 if (!(src_texture = surface_convert_format(src_surface, dst_format->id)))
@@ -4391,9 +5550,13 @@
                 }
                 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, 0));
             }
+#if defined(STAGING_CSMT)
             wined3d_resource_load_location(&src_surface->resource, context, src_surface->resource.map_binding);
             wined3d_resource_get_pitch(&src_surface->resource, &src_row_pitch, &src_slice_pitch);
             src_data = wined3d_resource_get_map_ptr(&src_surface->resource, context, 0);
+#else  /* STAGING_CSMT */
+            wined3d_surface_map(src_surface, &src_map, NULL, WINED3D_MAP_READONLY);
+#endif /* STAGING_CSMT */
             src_format = src_surface->resource.format;
             src_fmt_flags = src_surface->container->resource.format_flags;
         }
@@ -4403,8 +5566,12 @@
             src_fmt_flags = dst_fmt_flags;
         }
 
+#if defined(STAGING_CSMT)
         wined3d_resource_get_pitch(&dst_surface->resource, &dst_row_pitch, &dst_slice_pitch);
         dst_data = wined3d_resource_get_map_ptr(&dst_surface->resource, context, 0);
+#else  /* STAGING_CSMT */
+        wined3d_surface_map(dst_surface, &dst_map, &dst_box, 0);
+#endif /* STAGING_CSMT */
     }
 
     bpp = dst_surface->resource.format->byte_count;
@@ -4415,12 +5582,24 @@
     width = (dst_rect->right - dst_rect->left) * bpp;
 
     if (src_surface)
+#if defined(STAGING_CSMT)
         sbase = (BYTE *)src_data
                 + ((src_rect->top / src_format->block_height) * src_row_pitch)
                 + ((src_rect->left / src_format->block_width) * src_format->block_byte_count);
     dbuf = (BYTE *)dst_data
             + ((dst_rect->top / dst_format->block_height) * dst_row_pitch)
             + ((dst_rect->left / dst_format->block_width) * dst_format->block_byte_count);
+#else  /* STAGING_CSMT */
+        sbase = (BYTE *)src_map.data
+                + ((src_rect->top / src_format->block_height) * src_map.row_pitch)
+                + ((src_rect->left / src_format->block_width) * src_format->block_byte_count);
+    if (src_surface != dst_surface)
+        dbuf = dst_map.data;
+    else
+        dbuf = (BYTE *)dst_map.data
+                + ((dst_rect->top / dst_format->block_height) * dst_map.row_pitch)
+                + ((dst_rect->left / dst_format->block_width) * dst_format->block_byte_count);
+#endif /* STAGING_CSMT */
 
     if (src_fmt_flags & dst_fmt_flags & WINED3DFMT_FLAG_BLOCKS)
     {
@@ -4455,7 +5634,11 @@
         }
 
         hr = surface_cpu_blt_compressed(sbase, dbuf,
+#if defined(STAGING_CSMT)
                 src_row_pitch, dst_row_pitch, dstwidth, dstheight,
+#else  /* STAGING_CSMT */
+                src_map.row_pitch, dst_map.row_pitch, dstwidth, dstheight,
+#endif /* STAGING_CSMT */
                 src_format, flags, fx);
         goto release;
     }
@@ -4463,7 +5646,11 @@
     /* First, all the 'source-less' blits */
     if (flags & WINEDDBLT_COLORFILL)
     {
+#if defined(STAGING_CSMT)
         hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_row_pitch, fx->u5.dwFillColor);
+#else  /* STAGING_CSMT */
+        hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, fx->u5.dwFillColor);
+#endif /* STAGING_CSMT */
         flags &= ~WINEDDBLT_COLORFILL;
     }
 
@@ -4513,6 +5700,7 @@
                         for (y = 0; y < dstheight; ++y)
                         {
                             memcpy(dbuf, sbuf, width);
+#if defined(STAGING_CSMT)
                             sbuf += src_row_pitch;
                             dbuf += dst_row_pitch;
                         }
@@ -4526,6 +5714,21 @@
                         {
                             sbuf -= src_row_pitch;
                             dbuf -= dst_row_pitch;
+#else  /* STAGING_CSMT */
+                            sbuf += src_map.row_pitch;
+                            dbuf += dst_map.row_pitch;
+                        }
+                    }
+                    else if (dst_rect->top > src_rect->top)
+                    {
+                        /* Copy from bottom upwards. */
+                        sbuf += src_map.row_pitch * dstheight;
+                        dbuf += dst_map.row_pitch * dstheight;
+                        for (y = 0; y < dstheight; ++y)
+                        {
+                            sbuf -= src_map.row_pitch;
+                            dbuf -= dst_map.row_pitch;
+#endif /* STAGING_CSMT */
                             memcpy(dbuf, sbuf, width);
                         }
                     }
@@ -4535,8 +5738,13 @@
                         for (y = 0; y < dstheight; ++y)
                         {
                             memmove(dbuf, sbuf, width);
+#if defined(STAGING_CSMT)
                             sbuf += src_row_pitch;
                             dbuf += dst_row_pitch;
+#else  /* STAGING_CSMT */
+                            sbuf += src_map.row_pitch;
+                            dbuf += dst_map.row_pitch;
+#endif /* STAGING_CSMT */
                         }
                     }
                 }
@@ -4545,9 +5753,15 @@
                     /* Stretching in y direction only. */
                     for (y = sy = 0; y < dstheight; ++y, sy += yinc)
                     {
+#if defined(STAGING_CSMT)
                         sbuf = sbase + (sy >> 16) * src_row_pitch;
                         memcpy(dbuf, sbuf, width);
                         dbuf += dst_row_pitch;
+#else  /* STAGING_CSMT */
+                        sbuf = sbase + (sy >> 16) * src_map.row_pitch;
+                        memcpy(dbuf, sbuf, width);
+                        dbuf += dst_map.row_pitch;
+#endif /* STAGING_CSMT */
                     }
                 }
             }
@@ -4557,6 +5771,7 @@
                 int last_sy = -1;
                 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
                 {
+#if defined(STAGING_CSMT)
                     sbuf = sbase + (sy >> 16) * src_row_pitch;
 
                     if ((sy >> 16) == (last_sy >> 16))
@@ -4564,6 +5779,15 @@
                         /* This source row is the same as last source row -
                          * Copy the already stretched row. */
                         memcpy(dbuf, dbuf - dst_row_pitch, width);
+#else  /* STAGING_CSMT */
+                    sbuf = sbase + (sy >> 16) * src_map.row_pitch;
+
+                    if ((sy >> 16) == (last_sy >> 16))
+                    {
+                        /* This source row is the same as last source row -
+                         * Copy the already stretched row. */
+                        memcpy(dbuf, dbuf - dst_map.row_pitch, width);
+#endif /* STAGING_CSMT */
                     }
                     else
                     {
@@ -4610,6 +5834,7 @@
                         }
 #undef STRETCH_ROW
                     }
+#if defined(STAGING_CSMT)
                     dbuf += dst_row_pitch;
                     last_sy = sy;
                 }
@@ -4618,6 +5843,16 @@
         else
         {
             LONG dstyinc = dst_row_pitch, dstxinc = bpp;
+#else  /* STAGING_CSMT */
+                    dbuf += dst_map.row_pitch;
+                    last_sy = sy;
+                }
+            }
+        }
+        else
+        {
+            LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
+#endif /* STAGING_CSMT */
             DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
             DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
             if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
@@ -4667,7 +5902,11 @@
                 LONG tmpxy;
                 dTopLeft     = dbuf;
                 dTopRight    = dbuf + ((dstwidth - 1) * bpp);
+#if defined(STAGING_CSMT)
                 dBottomLeft  = dTopLeft + ((dstheight - 1) * dst_row_pitch);
+#else  /* STAGING_CSMT */
+                dBottomLeft  = dTopLeft + ((dstheight - 1) * dst_map.row_pitch);
+#endif /* STAGING_CSMT */
                 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp);
 
                 if (fx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
@@ -4744,6 +5983,7 @@
                 flags &= ~(WINEDDBLT_DDFX);
             }
 
+#if defined(STAGING_CSMT)
 #define COPY_COLORKEY_FX(type) \
 do { \
     const type *s; \
@@ -4765,6 +6005,29 @@
         d = (type *)(((BYTE *)d) + dstyinc); \
     } \
 } while(0)
+#else  /* STAGING_CSMT */
+#define COPY_COLORKEY_FX(type) \
+do { \
+    const type *s; \
+    type *d = (type *)dbuf, *dx, tmp; \
+    for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
+    { \
+        s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
+        dx = d; \
+        for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
+        { \
+            tmp = s[sx >> 16]; \
+            if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
+                    && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
+            { \
+                dx[0] = tmp; \
+            } \
+            dx = (type *)(((BYTE *)dx) + dstxinc); \
+        } \
+        d = (type *)(((BYTE *)d) + dstyinc); \
+    } \
+} while(0)
+#endif /* STAGING_CSMT */
 
             switch (bpp)
             {
@@ -4783,7 +6046,11 @@
                     BYTE *d = dbuf, *dx;
                     for (y = sy = 0; y < dstheight; ++y, sy += yinc)
                     {
+#if defined(STAGING_CSMT)
                         sbuf = sbase + (sy >> 16) * src_row_pitch;
+#else  /* STAGING_CSMT */
+                        sbuf = sbase + (sy >> 16) * src_map.row_pitch;
+#endif /* STAGING_CSMT */
                         dx = d;
                         for (x = sx = 0; x < dstwidth; ++x, sx+= xinc)
                         {
@@ -4814,10 +6081,12 @@
         }
     }
 
+#if defined(STAGING_CSMT)
     wined3d_resource_invalidate_location(&dst_surface->resource, ~dst_surface->resource.map_binding);
     if (dst_surface->container)
         wined3d_texture_set_dirty(dst_surface->container);
 
+#endif /* STAGING_CSMT */
 error:
     if (flags && FIXME_ON(d3d_surface))
     {
@@ -4825,6 +6094,7 @@
     }
 
 release:
+#if defined(STAGING_CSMT)
     if (dst_data)
     {
         wined3d_resource_release_map_ptr(&dst_surface->resource, context);
@@ -4843,6 +6113,14 @@
         wined3d_texture_decref(src_texture);
     if (context)
         context_release(context);
+#else  /* STAGING_CSMT */
+    wined3d_surface_unmap(dst_surface);
+    if (src_surface && src_surface != dst_surface)
+        wined3d_surface_unmap(src_surface);
+    /* Release the converted surface, if any. */
+    if (src_texture)
+        wined3d_texture_decref(src_texture);
+#endif /* STAGING_CSMT */
 
     return hr;
 }
@@ -4887,6 +6165,7 @@
     cpu_blit_blit_surface,
 };
 
+#if defined(STAGING_CSMT)
 void surface_blt_ugly(struct wined3d_surface *dst_surface, const RECT *dst_rect,
         struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
         const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
@@ -4894,6 +6173,16 @@
     struct wined3d_swapchain *src_swapchain, *dst_swapchain;
     struct wined3d_device *device = dst_surface->resource.device;
     DWORD src_ds_flags, dst_ds_flags;
+#else  /* STAGING_CSMT */
+HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect_in,
+        struct wined3d_surface *src_surface, const RECT *src_rect_in, DWORD flags,
+        const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
+{
+    struct wined3d_swapchain *src_swapchain, *dst_swapchain;
+    struct wined3d_device *device = dst_surface->resource.device;
+    DWORD src_ds_flags, dst_ds_flags;
+    RECT src_rect, dst_rect;
+#endif /* STAGING_CSMT */
     BOOL scale, convert;
 
     static const DWORD simple_blit = WINEDDBLT_ASYNC
@@ -4905,6 +6194,106 @@
             | WINEDDBLT_DONOTWAIT
             | WINEDDBLT_ALPHATEST;
 
+#if !defined(STAGING_CSMT)
+    TRACE("dst_surface %p, dst_rect_in %s, src_surface %p, src_rect_in %s, flags %#x, fx %p, filter %s.\n",
+            dst_surface, wine_dbgstr_rect(dst_rect_in), src_surface, wine_dbgstr_rect(src_rect_in),
+            flags, fx, debug_d3dtexturefiltertype(filter));
+    TRACE("Usage is %s.\n", debug_d3dusage(dst_surface->resource.usage));
+
+    if (fx)
+    {
+        TRACE("dwSize %#x.\n", fx->dwSize);
+        TRACE("dwDDFX %#x.\n", fx->dwDDFX);
+        TRACE("dwROP %#x.\n", fx->dwROP);
+        TRACE("dwDDROP %#x.\n", fx->dwDDROP);
+        TRACE("dwRotationAngle %#x.\n", fx->dwRotationAngle);
+        TRACE("dwZBufferOpCode %#x.\n", fx->dwZBufferOpCode);
+        TRACE("dwZBufferLow %#x.\n", fx->dwZBufferLow);
+        TRACE("dwZBufferHigh %#x.\n", fx->dwZBufferHigh);
+        TRACE("dwZBufferBaseDest %#x.\n", fx->dwZBufferBaseDest);
+        TRACE("dwZDestConstBitDepth %#x.\n", fx->dwZDestConstBitDepth);
+        TRACE("lpDDSZBufferDest %p.\n", fx->u1.lpDDSZBufferDest);
+        TRACE("dwZSrcConstBitDepth %#x.\n", fx->dwZSrcConstBitDepth);
+        TRACE("lpDDSZBufferSrc %p.\n", fx->u2.lpDDSZBufferSrc);
+        TRACE("dwAlphaEdgeBlendBitDepth %#x.\n", fx->dwAlphaEdgeBlendBitDepth);
+        TRACE("dwAlphaEdgeBlend %#x.\n", fx->dwAlphaEdgeBlend);
+        TRACE("dwReserved %#x.\n", fx->dwReserved);
+        TRACE("dwAlphaDestConstBitDepth %#x.\n", fx->dwAlphaDestConstBitDepth);
+        TRACE("lpDDSAlphaDest %p.\n", fx->u3.lpDDSAlphaDest);
+        TRACE("dwAlphaSrcConstBitDepth %#x.\n", fx->dwAlphaSrcConstBitDepth);
+        TRACE("lpDDSAlphaSrc %p.\n", fx->u4.lpDDSAlphaSrc);
+        TRACE("lpDDSPattern %p.\n", fx->u5.lpDDSPattern);
+        TRACE("ddckDestColorkey {%#x, %#x}.\n",
+                fx->ddckDestColorkey.color_space_low_value,
+                fx->ddckDestColorkey.color_space_high_value);
+        TRACE("ddckSrcColorkey {%#x, %#x}.\n",
+                fx->ddckSrcColorkey.color_space_low_value,
+                fx->ddckSrcColorkey.color_space_high_value);
+    }
+
+    if (dst_surface->resource.map_count || (src_surface && src_surface->resource.map_count))
+    {
+        WARN("Surface is busy, returning WINEDDERR_SURFACEBUSY.\n");
+        return WINEDDERR_SURFACEBUSY;
+    }
+
+    surface_get_rect(dst_surface, dst_rect_in, &dst_rect);
+
+    if (dst_rect.left >= dst_rect.right || dst_rect.top >= dst_rect.bottom
+            || dst_rect.left > dst_surface->resource.width || dst_rect.left < 0
+            || dst_rect.top > dst_surface->resource.height || dst_rect.top < 0
+            || dst_rect.right > dst_surface->resource.width || dst_rect.right < 0
+            || dst_rect.bottom > dst_surface->resource.height || dst_rect.bottom < 0)
+    {
+        WARN("The application gave us a bad destination rectangle.\n");
+        return WINEDDERR_INVALIDRECT;
+    }
+
+    if (src_surface)
+    {
+        surface_get_rect(src_surface, src_rect_in, &src_rect);
+
+        if (src_rect.left >= src_rect.right || src_rect.top >= src_rect.bottom
+                || src_rect.left > src_surface->resource.width || src_rect.left < 0
+                || src_rect.top > src_surface->resource.height || src_rect.top < 0
+                || src_rect.right > src_surface->resource.width || src_rect.right < 0
+                || src_rect.bottom > src_surface->resource.height || src_rect.bottom < 0)
+        {
+            WARN("Application gave us bad source rectangle for Blt.\n");
+            return WINEDDERR_INVALIDRECT;
+        }
+    }
+    else
+    {
+        memset(&src_rect, 0, sizeof(src_rect));
+    }
+
+    if (!fx || !(fx->dwDDFX))
+        flags &= ~WINEDDBLT_DDFX;
+
+    if (flags & WINEDDBLT_WAIT)
+        flags &= ~WINEDDBLT_WAIT;
+
+    if (flags & WINEDDBLT_ASYNC)
+    {
+        static unsigned int once;
+
+        if (!once++)
+            FIXME("Can't handle WINEDDBLT_ASYNC flag.\n");
+        flags &= ~WINEDDBLT_ASYNC;
+    }
+
+    /* WINEDDBLT_DONOTWAIT appeared in DX7. */
+    if (flags & WINEDDBLT_DONOTWAIT)
+    {
+        static unsigned int once;
+
+        if (!once++)
+            FIXME("Can't handle WINEDDBLT_DONOTWAIT flag.\n");
+        flags &= ~WINEDDBLT_DONOTWAIT;
+    }
+
+#endif /* STAGING_CSMT */
     if (!device->d3d_initialized)
     {
         WARN("D3D not initialized, using fallback.\n");
@@ -4947,8 +6336,13 @@
     }
 
     scale = src_surface
+#if defined(STAGING_CSMT)
             && (src_rect->right - src_rect->left != dst_rect->right - dst_rect->left
             || src_rect->bottom - src_rect->top != dst_rect->bottom - dst_rect->top);
+#else  /* STAGING_CSMT */
+            && (src_rect.right - src_rect.left != dst_rect.right - dst_rect.left
+            || src_rect.bottom - src_rect.top != dst_rect.bottom - dst_rect.top);
+#endif /* STAGING_CSMT */
     convert = src_surface && src_surface->resource.format->id != dst_surface->resource.format->id;
 
     dst_ds_flags = dst_surface->container->resource.format_flags
@@ -4968,6 +6362,7 @@
             TRACE("Depth fill.\n");
 
             if (!surface_convert_depth_to_float(dst_surface, fx->u5.dwFillDepth, &depth))
+#if defined(STAGING_CSMT)
                 return;
 
             if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, dst_rect, depth)))
@@ -4978,6 +6373,24 @@
             if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, src_surface->container->resource.draw_binding,
                     src_rect, dst_surface, dst_surface->container->resource.draw_binding, dst_rect)))
                 return;
+#else  /* STAGING_CSMT */
+                return WINED3DERR_INVALIDCALL;
+
+            if (SUCCEEDED(wined3d_surface_depth_fill(dst_surface, &dst_rect, depth)))
+                return WINED3D_OK;
+        }
+        else
+        {
+            if (src_ds_flags != dst_ds_flags)
+            {
+                WARN("Rejecting depth / stencil blit between incompatible formats.\n");
+                return WINED3DERR_INVALIDCALL;
+            }
+
+            if (SUCCEEDED(wined3d_surface_depth_blt(src_surface, src_surface->container->resource.draw_binding,
+                    &src_rect, dst_surface, dst_surface->container->resource.draw_binding, &dst_rect)))
+                return WINED3D_OK;
+#endif /* STAGING_CSMT */
         }
     }
     else
@@ -4986,8 +6399,13 @@
 
         /* In principle this would apply to depth blits as well, but we don't
          * implement those in the CPU blitter at the moment. */
+#if defined(STAGING_CSMT)
         if ((dst_surface->resource.locations & dst_surface->resource.map_binding)
                 && (!src_surface || (src_surface->resource.locations & src_surface->resource.map_binding)))
+#else  /* STAGING_CSMT */
+        if ((dst_surface->locations & dst_surface->resource.map_binding)
+                && (!src_surface || (src_surface->locations & src_surface->resource.map_binding)))
+#endif /* STAGING_CSMT */
         {
             if (scale)
                 TRACE("Not doing sysmem blit because of scaling.\n");
@@ -5008,8 +6426,13 @@
                     palette, fx->u5.dwFillColor, &color))
                 goto fallback;
 
+#if defined(STAGING_CSMT)
             if (SUCCEEDED(surface_color_fill(dst_surface, dst_rect, &color)))
                 return;
+#else  /* STAGING_CSMT */
+            if (SUCCEEDED(surface_color_fill(dst_surface, &dst_rect, &color)))
+                return WINED3D_OK;
+#endif /* STAGING_CSMT */
         }
         else
         {
@@ -5031,8 +6454,13 @@
             {
                 blit_op = WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST;
             }
+#if defined(STAGING_CSMT)
             else if ((src_surface->resource.locations & WINED3D_LOCATION_SYSMEM)
                     && !(dst_surface->resource.locations & WINED3D_LOCATION_SYSMEM))
+#else  /* STAGING_CSMT */
+            else if ((src_surface->locations & WINED3D_LOCATION_SYSMEM)
+                    && !(dst_surface->locations & WINED3D_LOCATION_SYSMEM))
+#endif /* STAGING_CSMT */
             {
                 /* Upload */
                 if (scale)
@@ -5041,6 +6469,7 @@
                     TRACE("Not doing upload because of format conversion.\n");
                 else
                 {
+#if defined(STAGING_CSMT)
                     POINT dst_point = {dst_rect->left, dst_rect->top};
 
                     if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, src_rect)))
@@ -5053,6 +6482,19 @@
                             context_release(context);
                         }
                         return;
+#else  /* STAGING_CSMT */
+                    POINT dst_point = {dst_rect.left, dst_rect.top};
+
+                    if (SUCCEEDED(surface_upload_from_surface(dst_surface, &dst_point, src_surface, &src_rect)))
+                    {
+                        if (!wined3d_resource_is_offscreen(&dst_surface->container->resource))
+                        {
+                            struct wined3d_context *context = context_acquire(device, dst_surface);
+                            surface_load_location(dst_surface, context, dst_surface->container->resource.draw_binding);
+                            context_release(context);
+                        }
+                        return WINED3D_OK;
+#endif /* STAGING_CSMT */
                     }
                 }
             }
@@ -5076,6 +6518,7 @@
                 wined3d_swapchain_present(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, NULL, 0);
                 dst_swapchain->desc.swap_effect = swap_effect;
 
+#if defined(STAGING_CSMT)
                 return;
             }
 
@@ -5284,6 +6727,54 @@
     wined3d_surface_location_invalidated,
     wined3d_surface_load_location,
 };
+#else  /* STAGING_CSMT */
+                return WINED3D_OK;
+            }
+
+            if (fbo_blit_supported(&device->adapter->gl_info, blit_op,
+                    &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
+                    &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
+            {
+                struct wined3d_context *context;
+                TRACE("Using FBO blit.\n");
+
+                context = context_acquire(device, NULL);
+                surface_blt_fbo(device, context, filter,
+                        src_surface, src_surface->container->resource.draw_binding, &src_rect,
+                        dst_surface, dst_surface->container->resource.draw_binding, &dst_rect);
+                context_release(context);
+
+                surface_validate_location(dst_surface, dst_surface->container->resource.draw_binding);
+                surface_invalidate_location(dst_surface, ~dst_surface->container->resource.draw_binding);
+
+                return WINED3D_OK;
+            }
+
+            blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info, blit_op,
+                    &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
+                    &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format);
+            if (blitter)
+            {
+                blitter->blit_surface(device, blit_op, filter, src_surface,
+                        &src_rect, dst_surface, &dst_rect, color_key);
+                return WINED3D_OK;
+            }
+        }
+    }
+
+fallback:
+    /* Special cases for render targets. */
+    if (SUCCEEDED(surface_blt_special(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter)))
+        return WINED3D_OK;
+
+cpu:
+
+    /* For the rest call the X11 surface implementation. For render targets
+     * this should be implemented OpenGL accelerated in surface_blt_special(),
+     * other blits are rather rare. */
+    return surface_cpu_blt(dst_surface, &dst_rect, src_surface, &src_rect, flags, fx, filter);
+}
+#endif /* STAGING_CSMT */
 
 static HRESULT surface_init(struct wined3d_surface *surface, struct wined3d_texture *container,
         const struct wined3d_resource_desc *desc, GLenum target, unsigned int level, unsigned int layer, DWORD flags)
@@ -5345,7 +6836,11 @@
     }
 
     surface->container = container;
+#if defined(STAGING_CSMT)
     wined3d_resource_validate_location(&surface->resource, WINED3D_LOCATION_SYSMEM);
+#else  /* STAGING_CSMT */
+    surface_validate_location(surface, WINED3D_LOCATION_SYSMEM);
+#endif /* STAGING_CSMT */
     list_init(&surface->renderbuffers);
     list_init(&surface->overlays);
 
@@ -5377,9 +6872,14 @@
     if (surface->resource.map_binding == WINED3D_LOCATION_DIB)
     {
         wined3d_resource_free_sysmem(&surface->resource);
+#if defined(STAGING_CSMT)
         surface->resource.map_heap_memory = NULL;
         wined3d_resource_validate_location(&surface->resource, WINED3D_LOCATION_DIB);
         wined3d_resource_invalidate_location(&surface->resource, WINED3D_LOCATION_SYSMEM);
+#else  /* STAGING_CSMT */
+        surface_validate_location(surface, WINED3D_LOCATION_DIB);
+        surface_invalidate_location(surface, WINED3D_LOCATION_SYSMEM);
+#endif /* STAGING_CSMT */
     }
 
     return hr;
@@ -5406,7 +6906,11 @@
     if (FAILED(hr = surface_init(object, container, desc, target, level, layer, flags)))
     {
         WARN("Failed to initialize surface, returning %#x.\n", hr);
+#if defined(STAGING_CSMT)
         /* The command stream takes care of freeing the memory. */
+#else  /* STAGING_CSMT */
+        HeapFree(GetProcessHeap(), 0, object);
+#endif /* STAGING_CSMT */
         return hr;
     }
 
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c
--- a/dlls/wined3d/swapchain.c
+++ b/dlls/wined3d/swapchain.c
@@ -320,7 +320,11 @@
         if (backbuffer->resource.multisample_type)
         {
             location = WINED3D_LOCATION_RB_RESOLVED;
+#if defined(STAGING_CSMT)
             wined3d_resource_load_location(&backbuffer->resource, context, location);
+#else  /* STAGING_CSMT */
+            surface_load_location(backbuffer, context, location);
+#endif /* STAGING_CSMT */
         }
 
         context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, backbuffer, NULL, location);
@@ -428,11 +432,19 @@
 }
 
 static void swapchain_gl_present(struct wined3d_swapchain *swapchain, const RECT *src_rect_in,
+#if defined(STAGING_CSMT)
         const RECT *dst_rect_in, const RGNDATA *dirty_region, DWORD flags,
         struct wined3d_surface *depth_stencil)
 {
     struct wined3d_surface *back_buffer = surface_from_resource(
             wined3d_texture_get_sub_resource(swapchain->back_buffers[0], 0));
+#else  /* STAGING_CSMT */
+        const RECT *dst_rect_in, const RGNDATA *dirty_region, DWORD flags)
+{
+    struct wined3d_surface *back_buffer = surface_from_resource(
+            wined3d_texture_get_sub_resource(swapchain->back_buffers[0], 0));
+    const struct wined3d_fb_state *fb = &swapchain->device->fb;
+#endif /* STAGING_CSMT */
     const struct wined3d_gl_info *gl_info;
     struct wined3d_context *context;
     struct wined3d_surface *front;
@@ -460,6 +472,37 @@
                 NULL, WINED3D_TEXF_POINT);
     }
 
+#if !defined(STAGING_CSMT)
+    if (swapchain->device->bCursorVisible && swapchain->device->cursor_texture
+            && !swapchain->device->hardwareCursor)
+    {
+        struct wined3d_surface *cursor = surface_from_resource(
+                wined3d_texture_get_sub_resource(swapchain->device->cursor_texture, 0));
+        RECT destRect =
+        {
+            swapchain->device->xScreenSpace - swapchain->device->xHotSpot,
+            swapchain->device->yScreenSpace - swapchain->device->yHotSpot,
+            swapchain->device->xScreenSpace + swapchain->device->cursorWidth - swapchain->device->xHotSpot,
+            swapchain->device->yScreenSpace + swapchain->device->cursorHeight - swapchain->device->yHotSpot,
+        };
+        RECT src_rect =
+        {
+            0, 0,
+            swapchain->device->cursor_texture->resource.width,
+            swapchain->device->cursor_texture->resource.height
+        };
+        const RECT clip_rect = {0, 0, back_buffer->resource.width, back_buffer->resource.height};
+
+        TRACE("Rendering the software cursor.\n");
+
+        if (swapchain->desc.windowed)
+            MapWindowPoints(NULL, swapchain->win_handle, (POINT *)&destRect, 2);
+        if (wined3d_clip_blit(&clip_rect, &destRect, &src_rect))
+            wined3d_surface_blt(back_buffer, &destRect, cursor, &src_rect, WINEDDBLT_ALPHATEST,
+                    NULL, WINED3D_TEXF_POINT);
+    }
+
+#endif /* STAGING_CSMT */
     TRACE("Presenting HDC %p.\n", context->hdc);
 
     render_to_fbo = swapchain->render_to_fbo;
@@ -501,6 +544,7 @@
      */
     if (!swapchain->render_to_fbo && render_to_fbo && wined3d_settings.offscreen_rendering_mode == ORM_FBO)
     {
+#if defined(STAGING_CSMT)
         wined3d_resource_load_location(&back_buffer->resource, context, WINED3D_LOCATION_TEXTURE_RGB);
         wined3d_resource_invalidate_location(&back_buffer->resource, WINED3D_LOCATION_DRAWABLE);
         swapchain->render_to_fbo = TRUE;
@@ -509,6 +553,16 @@
     else
     {
         wined3d_resource_load_location(&back_buffer->resource, context, back_buffer->container->resource.draw_binding);
+#else  /* STAGING_CSMT */
+        surface_load_location(back_buffer, context, WINED3D_LOCATION_TEXTURE_RGB);
+        surface_invalidate_location(back_buffer, WINED3D_LOCATION_DRAWABLE);
+        swapchain->render_to_fbo = TRUE;
+        swapchain_update_draw_bindings(swapchain);
+    }
+    else
+    {
+        surface_load_location(back_buffer, context, back_buffer->container->resource.draw_binding);
+#endif /* STAGING_CSMT */
     }
 
     if (swapchain->render_to_fbo)
@@ -521,8 +575,13 @@
         swapchain_blit(swapchain, context, &src_rect, &dst_rect);
     }
 
+#if defined(STAGING_CSMT)
     if (swapchain->num_contexts > 1 && !wined3d_settings.cs_multithreaded)
         gl_info->gl_ops.gl.p_glFlush();
+#else  /* STAGING_CSMT */
+    if (swapchain->num_contexts > 1)
+        gl_info->gl_ops.gl.p_glFinish();
+#endif /* STAGING_CSMT */
 
     /* call wglSwapBuffers through the gl table to avoid confusing the Steam overlay */
     gl_info->gl_ops.wgl.p_wglSwapBuffers(context->hdc); /* TODO: cycle through the swapchain buffers */
@@ -546,6 +605,7 @@
 
     front = surface_from_resource(wined3d_texture_get_sub_resource(swapchain->front_buffer, 0));
 
+#if defined(STAGING_CSMT)
     wined3d_resource_validate_location(&front->resource, WINED3D_LOCATION_DRAWABLE);
     wined3d_resource_invalidate_location(&front->resource, ~WINED3D_LOCATION_DRAWABLE);
     switch (swapchain->desc.swap_effect)
@@ -574,6 +634,31 @@
             {
                 wined3d_texture_decref(swapchain->device->cs->onscreen_depth_stencil->container);
                 swapchain->device->cs->onscreen_depth_stencil = NULL;
+#else  /* STAGING_CSMT */
+    surface_validate_location(front, WINED3D_LOCATION_DRAWABLE);
+    surface_invalidate_location(front, ~WINED3D_LOCATION_DRAWABLE);
+    /* If the swapeffect is DISCARD, the back buffer is undefined. That means the SYSMEM
+     * and INTEXTURE copies can keep their old content if they have any defined content.
+     * If the swapeffect is COPY, the content remains the same.
+     *
+     * The FLIP swap effect is not implemented yet. We could mark WINED3D_LOCATION_DRAWABLE
+     * up to date and hope WGL flipped front and back buffers and read this data into
+     * the FBO. Don't bother about this for now. */
+
+    if (fb->depth_stencil)
+    {
+        struct wined3d_surface *ds = wined3d_rendertarget_view_get_surface(fb->depth_stencil);
+
+        if (ds && (swapchain->desc.flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
+                || ds->flags & SFLAG_DISCARD))
+        {
+            surface_modify_ds_location(ds, WINED3D_LOCATION_DISCARDED,
+                    fb->depth_stencil->width, fb->depth_stencil->height);
+            if (ds == swapchain->device->onscreen_depth_stencil)
+            {
+                wined3d_texture_decref(swapchain->device->onscreen_depth_stencil->container);
+                swapchain->device->onscreen_depth_stencil = NULL;
+#endif /* STAGING_CSMT */
             }
         }
     }
@@ -606,7 +691,11 @@
 
     TRACE("Copying surface %p to screen.\n", front);
 
+#if defined(STAGING_CSMT)
     wined3d_resource_load_location(&front->resource, NULL, WINED3D_LOCATION_DIB);
+#else  /* STAGING_CSMT */
+    surface_load_location(front, NULL, WINED3D_LOCATION_DIB);
+#endif /* STAGING_CSMT */
 
     src_dc = front->hDC;
     window = swapchain->win_handle;
@@ -634,8 +723,12 @@
 }
 
 static void swapchain_gdi_present(struct wined3d_swapchain *swapchain, const RECT *src_rect_in,
+#if defined(STAGING_CSMT)
         const RECT *dst_rect_in, const RGNDATA *dirty_region, DWORD flags,
         struct wined3d_surface *depth_stencil)
+#else  /* STAGING_CSMT */
+        const RECT *dst_rect_in, const RGNDATA *dirty_region, DWORD flags)
+#endif /* STAGING_CSMT */
 {
     struct wined3d_surface *front, *back;
 
@@ -662,9 +755,15 @@
     {
         void *tmp;
 
+#if defined(STAGING_CSMT)
         tmp = front->resource.bitmap_data;
         front->resource.bitmap_data = back->resource.bitmap_data;
         back->resource.bitmap_data = tmp;
+#else  /* STAGING_CSMT */
+        tmp = front->dib.bitmap_data;
+        front->dib.bitmap_data = back->dib.bitmap_data;
+        back->dib.bitmap_data = tmp;
+#endif /* STAGING_CSMT */
 
         if (front->resource.heap_memory)
             ERR("GDI Surface %p has heap memory allocated.\n", front);
@@ -735,6 +834,7 @@
     swapchain->render_to_fbo = TRUE;
 }
 
+#if defined(STAGING_CSMT)
 HRESULT swapchain_create_context_cs(struct wined3d_device *device, struct wined3d_swapchain *swapchain)
 {
     const struct wined3d_adapter *adapter = device->adapter;
@@ -798,6 +898,7 @@
     return WINED3D_OK;
 }
 
+#endif /* STAGING_CSMT */
 static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, struct wined3d_device *device,
         struct wined3d_swapchain_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops)
 {
@@ -888,8 +989,13 @@
     front_buffer = surface_from_resource(wined3d_texture_get_sub_resource(swapchain->front_buffer, 0));
     if (!(device->wined3d->flags & WINED3D_NO3D))
     {
+#if defined(STAGING_CSMT)
         wined3d_resource_validate_location(&front_buffer->resource, WINED3D_LOCATION_DRAWABLE);
         wined3d_resource_invalidate_location(&front_buffer->resource, ~WINED3D_LOCATION_DRAWABLE);
+#else  /* STAGING_CSMT */
+        surface_validate_location(front_buffer, WINED3D_LOCATION_DRAWABLE);
+        surface_invalidate_location(front_buffer, ~WINED3D_LOCATION_DRAWABLE);
+#endif /* STAGING_CSMT */
     }
 
     /* MSDN says we're only allowed a single fullscreen swapchain per device,
@@ -915,9 +1021,66 @@
 
     if (!(device->wined3d->flags & WINED3D_NO3D))
     {
+#if defined(STAGING_CSMT)
         hr = wined3d_cs_emit_create_swapchain_context(device->cs, swapchain);
         if (FAILED(hr))
             goto err;
+#else  /* STAGING_CSMT */
+        static const enum wined3d_format_id formats[] =
+        {
+            WINED3DFMT_D24_UNORM_S8_UINT,
+            WINED3DFMT_D32_UNORM,
+            WINED3DFMT_R24_UNORM_X8_TYPELESS,
+            WINED3DFMT_D16_UNORM,
+            WINED3DFMT_S1_UINT_D15_UNORM
+        };
+
+        const struct wined3d_gl_info *gl_info = &adapter->gl_info;
+
+        swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
+        if (!swapchain->context)
+        {
+            ERR("Failed to create the context array.\n");
+            hr = E_OUTOFMEMORY;
+            goto err;
+        }
+        swapchain->num_contexts = 1;
+
+        /* In WGL both color, depth and stencil are features of a pixel format. In case of D3D they are separate.
+         * You are able to add a depth + stencil surface at a later stage when you need it.
+         * In order to support this properly in WineD3D we need the ability to recreate the opengl context and
+         * drawable when this is required. This is very tricky as we need to reapply ALL opengl states for the new
+         * context, need torecreate shaders, textures and other resources.
+         *
+         * The context manager already takes care of the state problem and for the other tasks code from Reset
+         * can be used. These changes are way to risky during the 1.0 code freeze which is taking place right now.
+         * Likely a lot of other new bugs will be exposed. For that reason request a depth stencil surface all the
+         * time. It can cause a slight performance hit but fixes a lot of regressions. A fixme reminds of that this
+         * issue needs to be fixed. */
+        for (i = 0; i < (sizeof(formats) / sizeof(*formats)); i++)
+        {
+            swapchain->ds_format = wined3d_get_format(gl_info, formats[i]);
+            swapchain->context[0] = context_create(swapchain, front_buffer, swapchain->ds_format);
+            if (swapchain->context[0]) break;
+            TRACE("Depth stencil format %s is not supported, trying next format\n",
+                  debug_d3dformat(formats[i]));
+        }
+
+        if (!swapchain->context[0])
+        {
+            WARN("Failed to create context.\n");
+            hr = WINED3DERR_NOTAVAILABLE;
+            goto err;
+        }
+
+        if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
+                && (!desc->enable_auto_depth_stencil
+                || swapchain->desc.auto_depth_stencil_format != swapchain->ds_format->id))
+        {
+            FIXME("Add OpenGL context recreation support to context_validate_onscreen_formats\n");
+        }
+        context_release(swapchain->context[0]);
+#endif /* STAGING_CSMT */
     }
 
     if (swapchain->desc.backbuffer_count > 0)
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -68,8 +68,10 @@
     {
         ERR("Failed to allocate sub-resource array.\n");
         resource_cleanup(&texture->resource);
+#if defined(STAGING_CSMT)
         if (wined3d_settings.cs_multithreaded)
             texture->resource.device->cs->ops->finish(texture->resource.device->cs);
+#endif /* STAGING_CSMT */
         return E_OUTOFMEMORY;
     }
 
@@ -114,6 +116,7 @@
     resource_unload(&texture->resource);
 }
 
+#if defined(STAGING_CSMT)
 void wined3d_texture_cleanup_cs(struct wined3d_texture *texture)
 {
     wined3d_texture_unload_gl_texture(texture);
@@ -126,6 +129,12 @@
     UINT sub_count = texture->level_count * texture->layer_count;
     UINT i;
     struct wined3d_device *device = texture->resource.device;
+#else  /* STAGING_CSMT */
+static void wined3d_texture_cleanup(struct wined3d_texture *texture)
+{
+    UINT sub_count = texture->level_count * texture->layer_count;
+    UINT i;
+#endif /* STAGING_CSMT */
 
     TRACE("texture %p.\n", texture);
 
@@ -137,8 +146,14 @@
             texture->texture_ops->texture_sub_resource_cleanup(sub_resource);
     }
 
+#if defined(STAGING_CSMT)
     resource_cleanup(&texture->resource);
     wined3d_cs_emit_texture_cleanup(device->cs, texture);
+#else  /* STAGING_CSMT */
+    wined3d_texture_unload_gl_texture(texture);
+    HeapFree(GetProcessHeap(), 0, texture->sub_resources);
+    resource_cleanup(&texture->resource);
+#endif /* STAGING_CSMT */
 }
 
 void wined3d_texture_set_swapchain(struct wined3d_texture *texture, struct wined3d_swapchain *swapchain)
@@ -422,10 +437,16 @@
 
     if (!refcount)
     {
+#if defined(STAGING_CSMT)
         void *parent = texture->resource.parent;
         const struct wined3d_parent_ops *parent_ops = texture->resource.parent_ops;
         wined3d_texture_cleanup(texture);
         parent_ops->wined3d_object_destroyed(parent);
+#else  /* STAGING_CSMT */
+        wined3d_texture_cleanup(texture);
+        texture->resource.parent_ops->wined3d_object_destroyed(texture->resource.parent);
+        HeapFree(GetProcessHeap(), 0, texture);
+#endif /* STAGING_CSMT */
     }
 
     return refcount;
@@ -497,8 +518,15 @@
 
 void CDECL wined3d_texture_preload(struct wined3d_texture *texture)
 {
+#if defined(STAGING_CSMT)
     const struct wined3d_device *device = texture->resource.device;
     wined3d_cs_emit_texture_preload(device->cs, texture);
+#else  /* STAGING_CSMT */
+    struct wined3d_context *context;
+    context = context_acquire(texture->resource.device, NULL);
+    wined3d_texture_load(texture, context, texture->flags & WINED3D_TEXTURE_IS_SRGB);
+    context_release(context);
+#endif /* STAGING_CSMT */
 }
 
 void * CDECL wined3d_texture_get_parent(const struct wined3d_texture *texture)
@@ -527,6 +555,7 @@
 
     if (texture->lod != lod)
     {
+#if defined(STAGING_CSMT)
         if (wined3d_settings.cs_multithreaded)
         {
             struct wined3d_device *device = texture->resource.device;
@@ -534,6 +563,7 @@
             device->cs->ops->finish(device->cs);
         }
 
+#endif /* STAGING_CSMT */
         texture->lod = lod;
 
         texture->texture_rgb.base_level = ~0u;
@@ -652,10 +682,14 @@
     }
 
     if (device->d3d_initialized)
+#if defined(STAGING_CSMT)
     {
         wined3d_cs_emit_evict_resource(device->cs, &surface->resource);
         device->cs->ops->finish(device->cs);
     }
+#else  /* STAGING_CSMT */
+        texture->resource.resource_ops->resource_unload(&texture->resource);
+#endif /* STAGING_CSMT */
 
     texture->resource.format = format;
     texture->resource.multisample_type = multisample_type;
@@ -790,11 +824,19 @@
     struct wined3d_surface *surface = surface_from_resource(sub_resource);
     struct wined3d_context *context;
 
+#if defined(STAGING_CSMT)
     context = context_acquire(surface->resource.device, NULL);
     wined3d_resource_prepare_map_memory(&surface->resource, context);
     wined3d_resource_load_location(&surface->resource, context, surface->resource.map_binding);
     context_release(context);
     wined3d_resource_invalidate_location(&surface->resource, ~surface->resource.map_binding);
+#else  /* STAGING_CSMT */
+    surface_prepare_map_memory(surface);
+    context = context_acquire(surface->resource.device, NULL);
+    surface_load_location(surface, context, surface->resource.map_binding);
+    context_release(context);
+    surface_invalidate_location(surface, ~surface->resource.map_binding);
+#endif /* STAGING_CSMT */
 }
 
 static void texture2d_sub_resource_cleanup(struct wined3d_resource *sub_resource)
@@ -806,12 +848,25 @@
 
 static void texture2d_sub_resource_invalidate_location(struct wined3d_resource *sub_resource, DWORD location)
 {
+#if defined(STAGING_CSMT)
     wined3d_resource_invalidate_location(sub_resource, location);
 }
 
 static void texture2d_sub_resource_validate_location(struct wined3d_resource *sub_resource, DWORD location)
 {
     wined3d_resource_validate_location(sub_resource, location);
+#else  /* STAGING_CSMT */
+    struct wined3d_surface *surface = surface_from_resource(sub_resource);
+
+    surface_invalidate_location(surface, location);
+}
+
+static void texture2d_sub_resource_validate_location(struct wined3d_resource *sub_resource, DWORD location)
+{
+    struct wined3d_surface *surface = surface_from_resource(sub_resource);
+
+    surface_validate_location(surface, location);
+#endif /* STAGING_CSMT */
 }
 
 static void texture2d_sub_resource_upload_data(struct wined3d_resource *sub_resource,
@@ -954,6 +1009,7 @@
     return wined3d_surface_unmap(surface_from_resource(sub_resource));
 }
 
+#if defined(STAGING_CSMT)
 static void wined3d_texture_load_location_invalidated(struct wined3d_resource *resource, DWORD location)
 {
     ERR("Should not be called on textures.\n");
@@ -966,6 +1022,7 @@
     ERR("Should not be called on textures.\n");
 }
 
+#endif /* STAGING_CSMT */
 static const struct wined3d_resource_ops texture2d_resource_ops =
 {
     texture_resource_incref,
@@ -973,8 +1030,10 @@
     wined3d_texture_unload,
     texture2d_resource_sub_resource_map,
     texture2d_resource_sub_resource_unmap,
+#if defined(STAGING_CSMT)
     wined3d_texture_load_location_invalidated,
     wined3d_texture_load_location,
+#endif /* STAGING_CSMT */
 };
 
 static HRESULT cubetexture_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc,
@@ -991,7 +1050,9 @@
     if (WINED3DFMT_UNKNOWN >= desc->format)
     {
         WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture);
+#if defined(STAGING_CSMT)
         HeapFree(GetProcessHeap(), 0, texture);
+#endif /* STAGING_CSMT */
         return WINED3DERR_INVALIDCALL;
     }
 
@@ -1001,6 +1062,7 @@
         if (!gl_info->supported[SGIS_GENERATE_MIPMAP])
         {
             WARN("No mipmap generation support, returning D3DERR_INVALIDCALL.\n");
+#if defined(STAGING_CSMT)
             HeapFree(GetProcessHeap(), 0, texture);
             return WINED3DERR_INVALIDCALL;
         }
@@ -1009,6 +1071,14 @@
         {
             WARN("WINED3DUSAGE_AUTOGENMIPMAP is set, and level count != 1, returning D3DERR_INVALIDCALL.\n");
             HeapFree(GetProcessHeap(), 0, texture);
+#else  /* STAGING_CSMT */
+            return WINED3DERR_INVALIDCALL;
+        }
+
+        if (levels != 1)
+        {
+            WARN("WINED3DUSAGE_AUTOGENMIPMAP is set, and level count != 1, returning D3DERR_INVALIDCALL.\n");
+#endif /* STAGING_CSMT */
             return WINED3DERR_INVALIDCALL;
         }
     }
@@ -1029,7 +1099,9 @@
             else
             {
                 WARN("Attempted to create a NPOT cube texture (edge length %u) without GL support.\n", desc->width);
+#if defined(STAGING_CSMT)
                 HeapFree(GetProcessHeap(), 0, texture);
+#endif /* STAGING_CSMT */
                 return WINED3DERR_INVALIDCALL;
             }
         }
@@ -1039,7 +1111,9 @@
             surface_flags, device, parent, parent_ops, &texture2d_resource_ops)))
     {
         WARN("Failed to initialize texture, returning %#x\n", hr);
+#if defined(STAGING_CSMT)
         HeapFree(GetProcessHeap(), 0, texture);
+#endif /* STAGING_CSMT */
         return hr;
     }
 
@@ -1102,7 +1176,9 @@
     if (WINED3DFMT_UNKNOWN >= desc->format)
     {
         WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture);
+#if defined(STAGING_CSMT)
         HeapFree(GetProcessHeap(), 0, texture);
+#endif /* STAGING_CSMT */
         return WINED3DERR_INVALIDCALL;
     }
 
@@ -1133,7 +1209,9 @@
                 else
                 {
                     WARN("Attempted to create a mipmapped NPOT texture without unconditional NPOT support.\n");
+#if defined(STAGING_CSMT)
                     HeapFree(GetProcessHeap(), 0, texture);
+#endif /* STAGING_CSMT */
                     return WINED3DERR_INVALIDCALL;
                 }
             }
@@ -1146,6 +1224,7 @@
         if (!gl_info->supported[SGIS_GENERATE_MIPMAP])
         {
             WARN("No mipmap generation support, returning WINED3DERR_INVALIDCALL.\n");
+#if defined(STAGING_CSMT)
             HeapFree(GetProcessHeap(), 0, texture);
             return WINED3DERR_INVALIDCALL;
         }
@@ -1154,6 +1233,14 @@
         {
             WARN("WINED3DUSAGE_AUTOGENMIPMAP is set, and level count != 1, returning WINED3DERR_INVALIDCALL.\n");
             HeapFree(GetProcessHeap(), 0, texture);
+#else  /* STAGING_CSMT */
+            return WINED3DERR_INVALIDCALL;
+        }
+
+        if (levels != 1)
+        {
+            WARN("WINED3DUSAGE_AUTOGENMIPMAP is set, and level count != 1, returning WINED3DERR_INVALIDCALL.\n");
+#endif /* STAGING_CSMT */
             return WINED3DERR_INVALIDCALL;
         }
     }
@@ -1162,7 +1249,9 @@
             surface_flags, device, parent, parent_ops, &texture2d_resource_ops)))
     {
         WARN("Failed to initialize texture, returning %#x.\n", hr);
+#if defined(STAGING_CSMT)
         HeapFree(GetProcessHeap(), 0, texture);
+#endif /* STAGING_CSMT */
         return hr;
     }
 
@@ -1248,12 +1337,25 @@
 
 static void texture3d_sub_resource_invalidate_location(struct wined3d_resource *sub_resource, DWORD location)
 {
+#if defined(STAGING_CSMT)
     wined3d_resource_invalidate_location(sub_resource, location);
 }
 
 static void texture3d_sub_resource_validate_location(struct wined3d_resource *sub_resource, DWORD location)
 {
     wined3d_resource_validate_location(sub_resource, location);
+#else  /* STAGING_CSMT */
+    struct wined3d_volume *volume = volume_from_resource(sub_resource);
+
+    wined3d_volume_invalidate_location(volume, location);
+}
+
+static void texture3d_sub_resource_validate_location(struct wined3d_resource *sub_resource, DWORD location)
+{
+    struct wined3d_volume *volume = volume_from_resource(sub_resource);
+
+    wined3d_volume_validate_location(volume, location);
+#endif /* STAGING_CSMT */
 }
 
 static void texture3d_sub_resource_upload_data(struct wined3d_resource *sub_resource,
@@ -1263,7 +1365,11 @@
     struct wined3d_const_bo_address addr;
     unsigned int row_pitch, slice_pitch;
 
+#if defined(STAGING_CSMT)
     wined3d_resource_get_pitch(sub_resource, &row_pitch, &slice_pitch);
+#else  /* STAGING_CSMT */
+    wined3d_volume_get_pitch(volume, &row_pitch, &slice_pitch);
+#endif /* STAGING_CSMT */
     if (row_pitch != data->row_pitch || slice_pitch != data->slice_pitch)
         FIXME("Ignoring row/slice pitch (%u/%u).\n", data->row_pitch, data->slice_pitch);
 
@@ -1348,6 +1454,7 @@
     if (WINED3DFMT_UNKNOWN >= desc->format)
     {
         WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture);
+#if defined(STAGING_CSMT)
         HeapFree(GetProcessHeap(), 0, texture);
         return WINED3DERR_INVALIDCALL;
     }
@@ -1356,6 +1463,14 @@
     {
         WARN("(%p) : Texture cannot be created - no volume texture support.\n", texture);
         HeapFree(GetProcessHeap(), 0, texture);
+#else  /* STAGING_CSMT */
+        return WINED3DERR_INVALIDCALL;
+    }
+
+    if (!gl_info->supported[EXT_TEXTURE3D])
+    {
+        WARN("(%p) : Texture cannot be created - no volume texture support.\n", texture);
+#endif /* STAGING_CSMT */
         return WINED3DERR_INVALIDCALL;
     }
 
@@ -1365,6 +1480,7 @@
         if (!gl_info->supported[SGIS_GENERATE_MIPMAP])
         {
             WARN("No mipmap generation support, returning D3DERR_INVALIDCALL.\n");
+#if defined(STAGING_CSMT)
             HeapFree(GetProcessHeap(), 0, texture);
             return WINED3DERR_INVALIDCALL;
         }
@@ -1373,6 +1489,14 @@
         {
             WARN("WINED3DUSAGE_AUTOGENMIPMAP is set, and level count != 1, returning D3DERR_INVALIDCALL.\n");
             HeapFree(GetProcessHeap(), 0, texture);
+#else  /* STAGING_CSMT */
+            return WINED3DERR_INVALIDCALL;
+        }
+
+        if (levels != 1)
+        {
+            WARN("WINED3DUSAGE_AUTOGENMIPMAP is set, and level count != 1, returning D3DERR_INVALIDCALL.\n");
+#endif /* STAGING_CSMT */
             return WINED3DERR_INVALIDCALL;
         }
     }
@@ -1400,7 +1524,9 @@
             {
                 WARN("Attempted to create a NPOT volume texture (%u, %u, %u) without GL support.\n",
                         desc->width, desc->height, desc->depth);
+#if defined(STAGING_CSMT)
                 HeapFree(GetProcessHeap(), 0, texture);
+#endif /* STAGING_CSMT */
                 return WINED3DERR_INVALIDCALL;
             }
         }
@@ -1410,7 +1536,9 @@
             0, device, parent, parent_ops, &texture3d_resource_ops)))
     {
         WARN("Failed to initialize texture, returning %#x.\n", hr);
+#if defined(STAGING_CSMT)
         HeapFree(GetProcessHeap(), 0, texture);
+#endif /* STAGING_CSMT */
         return hr;
     }
 
@@ -1511,6 +1639,9 @@
     if (FAILED(hr))
     {
         WARN("Failed to initialize texture, returning %#x.\n", hr);
+#if !defined(STAGING_CSMT)
+        HeapFree(GetProcessHeap(), 0, object);
+#endif /* STAGING_CSMT */
         return hr;
     }
 
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -3765,7 +3765,11 @@
         float y_offset = context->render_offscreen
                 ? (center_offset - (2.0f * y) - h) / h
                 : (center_offset - (2.0f * y) - h) / -h;
+#if defined(STAGING_CSMT)
         enum wined3d_depth_buffer_type zenable = state->fb.depth_stencil ?
+#else  /* STAGING_CSMT */
+        enum wined3d_depth_buffer_type zenable = state->fb->depth_stencil ?
+#endif /* STAGING_CSMT */
                 state->render_states[WINED3D_RS_ZENABLE] : WINED3D_ZB_FALSE;
         float z_scale = zenable ? 2.0f : 0.0f;
         float z_offset = zenable ? -1.0f : 0.0f;
@@ -3888,6 +3892,7 @@
                 /* case WINED3D_TTFF_COUNT1: Won't ever get here. */
                 case WINED3D_TTFF_COUNT2:
                     mat._13 = mat._23 = mat._33 = mat._43 = 0.0f;
+#if defined(STAGING_CSMT)
                 /* OpenGL divides the first 3 vertex coord by the 4th by default,
                 * which is essentially the same as D3DTTFF_PROJECTED. Make sure that
                 * the 4th coord evaluates to 1.0 to eliminate that.
@@ -3900,6 +3905,20 @@
                 * A more serious problem occurs if the app passes 4 coordinates in, and the
                 * 4th is != 1.0(opengl default). This would have to be fixed in draw_strided_slow
                 * or a replacement shader. */
+#else  /* STAGING_CSMT */
+                /* OpenGL divides the first 3 vertex coord by the 4th by default,
+                * which is essentially the same as D3DTTFF_PROJECTED. Make sure that
+                * the 4th coord evaluates to 1.0 to eliminate that.
+                *
+                * If the fixed function pipeline is used, the 4th value remains unused,
+                * so there is no danger in doing this. With vertex shaders we have a
+                * problem. Should an app hit that problem, the code here would have to
+                * check for pixel shaders, and the shader has to undo the default gl divide.
+                *
+                * A more serious problem occurs if the app passes 4 coordinates in, and the
+                * 4th is != 1.0(opengl default). This would have to be fixed in drawStridedSlow
+                * or a replacement shader. */
+#endif /* STAGING_CSMT */
                 default:
                     mat._14 = mat._24 = mat._34 = 0.0f; mat._44 = 1.0f;
             }
@@ -4357,7 +4376,11 @@
     unsigned int i;
     DWORD ttff;
     DWORD cop, aop, carg0, carg1, carg2, aarg0, aarg1, aarg2;
+#if defined(STAGING_CSMT)
     unsigned int rt_fmt_flags = state->fb.render_targets[0]->format_flags;
+#else  /* STAGING_CSMT */
+    unsigned int rt_fmt_flags = state->fb->render_targets[0]->format_flags;
+#endif /* STAGING_CSMT */
     const struct wined3d_gl_info *gl_info = context->gl_info;
     const struct wined3d_d3d_info *d3d_info = context->d3d_info;
 
diff --git a/dlls/wined3d/vertexdeclaration.c b/dlls/wined3d/vertexdeclaration.c
--- a/dlls/wined3d/vertexdeclaration.c
+++ b/dlls/wined3d/vertexdeclaration.c
@@ -50,12 +50,14 @@
     return refcount;
 }
 
+#if defined(STAGING_CSMT)
 void wined3d_vertex_declaration_destroy(struct wined3d_vertex_declaration *declaration)
 {
     HeapFree(GetProcessHeap(), 0, declaration->elements);
     HeapFree(GetProcessHeap(), 0, declaration);
 }
 
+#endif /* STAGING_CSMT */
 ULONG CDECL wined3d_vertex_declaration_decref(struct wined3d_vertex_declaration *declaration)
 {
     ULONG refcount = InterlockedDecrement(&declaration->ref);
@@ -64,9 +66,15 @@
 
     if (!refcount)
     {
+#if defined(STAGING_CSMT)
         const struct wined3d_device *device = declaration->device;
         declaration->parent_ops->wined3d_object_destroyed(declaration->parent);
         wined3d_cs_emit_vertex_declaration_destroy(device->cs, declaration);
+#else  /* STAGING_CSMT */
+        HeapFree(GetProcessHeap(), 0, declaration->elements);
+        declaration->parent_ops->wined3d_object_destroyed(declaration->parent);
+        HeapFree(GetProcessHeap(), 0, declaration);
+#endif /* STAGING_CSMT */
     }
 
     return refcount;
diff --git a/dlls/wined3d/view.c b/dlls/wined3d/view.c
--- a/dlls/wined3d/view.c
+++ b/dlls/wined3d/view.c
@@ -33,11 +33,13 @@
     return refcount;
 }
 
+#if defined(STAGING_CSMT)
 void wined3d_rendertarget_view_destroy(struct wined3d_rendertarget_view *view)
 {
     HeapFree(GetProcessHeap(), 0, view);
 }
 
+#endif /* STAGING_CSMT */
 ULONG CDECL wined3d_rendertarget_view_decref(struct wined3d_rendertarget_view *view)
 {
     ULONG refcount = InterlockedDecrement(&view->refcount);
@@ -46,6 +48,7 @@
 
     if (!refcount)
     {
+#if defined(STAGING_CSMT)
         struct wined3d_device *device = view->resource->device;
 
         /* Call wined3d_object_destroyed() before releasing the resource,
@@ -53,6 +56,13 @@
         view->parent_ops->wined3d_object_destroyed(view->parent);
         wined3d_resource_decref(view->resource);
         wined3d_cs_emit_view_destroy(device->cs, view);
+#else  /* STAGING_CSMT */
+        /* Call wined3d_object_destroyed() before releasing the resource,
+         * since releasing the resource may end up destroying the parent. */
+        view->parent_ops->wined3d_object_destroyed(view->parent);
+        wined3d_resource_decref(view->resource);
+        HeapFree(GetProcessHeap(), 0, view);
+#endif /* STAGING_CSMT */
     }
 
     return refcount;
diff --git a/dlls/wined3d/volume.c b/dlls/wined3d/volume.c
--- a/dlls/wined3d/volume.c
+++ b/dlls/wined3d/volume.c
@@ -40,6 +40,32 @@
     return TRUE;
 }
 
+#if !defined(STAGING_CSMT)
+void wined3d_volume_get_pitch(const struct wined3d_volume *volume, UINT *row_pitch, UINT *slice_pitch)
+{
+    const struct wined3d_format *format = volume->resource.format;
+
+    if (volume->container->resource.format_flags & WINED3DFMT_FLAG_BLOCKS)
+    {
+        /* Since compressed formats are block based, pitch means the amount of
+         * bytes to the next row of block rather than the next row of pixels. */
+        UINT row_block_count = (volume->resource.width + format->block_width - 1) / format->block_width;
+        UINT slice_block_count = (volume->resource.height + format->block_height - 1) / format->block_height;
+        *row_pitch = row_block_count * format->block_byte_count;
+        *slice_pitch = *row_pitch * slice_block_count;
+    }
+    else
+    {
+        unsigned char alignment = volume->resource.device->surface_alignment;
+        *row_pitch = format->byte_count * volume->resource.width;  /* Bytes / row */
+        *row_pitch = (*row_pitch + alignment - 1) & ~(alignment - 1);
+        *slice_pitch = *row_pitch * volume->resource.height;
+    }
+
+    TRACE("Returning row pitch %u, slice pitch %u.\n", *row_pitch, *slice_pitch);
+}
+
+#endif /* STAGING_CSMT */
 /* This call just uploads data, the caller is responsible for binding the
  * correct texture. */
 /* Context activation is done by the caller. */
@@ -71,7 +97,11 @@
         dst_row_pitch = width * format->conv_byte_count;
         dst_slice_pitch = dst_row_pitch * height;
 
+#if defined(STAGING_CSMT)
         wined3d_resource_get_pitch(&volume->resource, &src_row_pitch, &src_slice_pitch);
+#else  /* STAGING_CSMT */
+        wined3d_volume_get_pitch(volume, &src_row_pitch, &src_slice_pitch);
+#endif /* STAGING_CSMT */
 
         converted_mem = HeapAlloc(GetProcessHeap(), 0, dst_slice_pitch * depth);
         format->convert(data->addr, converted_mem, src_row_pitch, src_slice_pitch,
@@ -99,6 +129,22 @@
     HeapFree(GetProcessHeap(), 0, converted_mem);
 }
 
+#if !defined(STAGING_CSMT)
+void wined3d_volume_validate_location(struct wined3d_volume *volume, DWORD location)
+{
+    TRACE("Volume %p, setting %s.\n", volume, wined3d_debug_location(location));
+    volume->locations |= location;
+    TRACE("new location flags are %s.\n", wined3d_debug_location(volume->locations));
+}
+
+void wined3d_volume_invalidate_location(struct wined3d_volume *volume, DWORD location)
+{
+    TRACE("Volume %p, clearing %s.\n", volume, wined3d_debug_location(location));
+    volume->locations &= ~location;
+    TRACE("new location flags are %s.\n", wined3d_debug_location(volume->locations));
+}
+
+#endif /* STAGING_CSMT */
 /* Context activation is done by the caller. */
 static void wined3d_volume_download_data(struct wined3d_volume *volume,
         const struct wined3d_context *context, const struct wined3d_bo_address *data)
@@ -134,8 +180,33 @@
 static void wined3d_volume_evict_sysmem(struct wined3d_volume *volume)
 {
     wined3d_resource_free_sysmem(&volume->resource);
+#if defined(STAGING_CSMT)
     volume->resource.map_heap_memory = NULL;
     wined3d_resource_invalidate_location(&volume->resource, WINED3D_LOCATION_SYSMEM);
+#else  /* STAGING_CSMT */
+    wined3d_volume_invalidate_location(volume, WINED3D_LOCATION_SYSMEM);
+}
+
+static DWORD volume_access_from_location(DWORD location)
+{
+    switch (location)
+    {
+        case WINED3D_LOCATION_DISCARDED:
+            return 0;
+
+        case WINED3D_LOCATION_SYSMEM:
+            return WINED3D_RESOURCE_ACCESS_CPU;
+
+        case WINED3D_LOCATION_BUFFER:
+        case WINED3D_LOCATION_TEXTURE_RGB:
+        case WINED3D_LOCATION_TEXTURE_SRGB:
+            return WINED3D_RESOURCE_ACCESS_GPU;
+
+        default:
+            FIXME("Unhandled location %#x.\n", location);
+            return 0;
+    }
+#endif /* STAGING_CSMT */
 }
 
 /* Context activation is done by the caller. */
@@ -175,6 +246,7 @@
 
     return TRUE;
 }
+#if defined(STAGING_CSMT)
 
 /* Context activation is done by the caller. */
 static void wined3d_volume_load_location(struct wined3d_resource *resource,
@@ -185,6 +257,22 @@
 
     TRACE("Volume %p, loading %s, have %s.\n", volume, wined3d_debug_location(location),
         wined3d_debug_location(volume->resource.locations));
+#else  /* STAGING_CSMT */
+/* Context activation is done by the caller. */
+static void wined3d_volume_load_location(struct wined3d_volume *volume,
+        struct wined3d_context *context, DWORD location)
+{
+    DWORD required_access = volume_access_from_location(location);
+
+    TRACE("Volume %p, loading %s, have %s.\n", volume, wined3d_debug_location(location),
+        wined3d_debug_location(volume->locations));
+
+    if ((volume->locations & location) == location)
+    {
+        TRACE("Location(s) already up to date.\n");
+        return;
+    }
+#endif /* STAGING_CSMT */
 
     if ((volume->resource.access_flags & required_access) != required_access)
     {
@@ -203,6 +291,7 @@
                     && !(volume->container->flags & WINED3D_TEXTURE_SRGB_ALLOCATED)))
                 ERR("Trying to load (s)RGB texture without prior allocation.\n");
 
+#if defined(STAGING_CSMT)
             if (volume->resource.locations & WINED3D_LOCATION_DISCARDED)
             {
                 TRACE("Volume previously discarded, nothing to do.\n");
@@ -236,6 +325,41 @@
                 return;
             }
             wined3d_resource_validate_location(&volume->resource, location);
+#else  /* STAGING_CSMT */
+            if (volume->locations & WINED3D_LOCATION_DISCARDED)
+            {
+                TRACE("Volume previously discarded, nothing to do.\n");
+                wined3d_volume_invalidate_location(volume, WINED3D_LOCATION_DISCARDED);
+            }
+            else if (volume->locations & WINED3D_LOCATION_SYSMEM)
+            {
+                struct wined3d_const_bo_address data = {0, volume->resource.heap_memory};
+                wined3d_texture_bind_and_dirtify(volume->container, context,
+                        location == WINED3D_LOCATION_TEXTURE_SRGB);
+                wined3d_volume_upload_data(volume, context, &data);
+            }
+            else if (volume->locations & WINED3D_LOCATION_BUFFER)
+            {
+                struct wined3d_const_bo_address data = {volume->pbo, NULL};
+                wined3d_texture_bind_and_dirtify(volume->container, context,
+                        location == WINED3D_LOCATION_TEXTURE_SRGB);
+                wined3d_volume_upload_data(volume, context, &data);
+            }
+            else if (volume->locations & WINED3D_LOCATION_TEXTURE_RGB)
+            {
+                wined3d_volume_srgb_transfer(volume, context, TRUE);
+            }
+            else if (volume->locations & WINED3D_LOCATION_TEXTURE_SRGB)
+            {
+                wined3d_volume_srgb_transfer(volume, context, FALSE);
+            }
+            else
+            {
+                FIXME("Implement texture loading from %s.\n", wined3d_debug_location(volume->locations));
+                return;
+            }
+            wined3d_volume_validate_location(volume, location);
+#endif /* STAGING_CSMT */
 
             if (wined3d_volume_can_evict(volume))
                 wined3d_volume_evict_sysmem(volume);
@@ -246,11 +370,24 @@
             if (!volume->resource.heap_memory)
                 ERR("Trying to load WINED3D_LOCATION_SYSMEM without setting it up first.\n");
 
+#if defined(STAGING_CSMT)
             if (volume->resource.locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
             {
                 struct wined3d_bo_address data = {0, volume->resource.heap_memory};
 
                 if (volume->resource.locations & WINED3D_LOCATION_TEXTURE_RGB)
+#else  /* STAGING_CSMT */
+            if (volume->locations & WINED3D_LOCATION_DISCARDED)
+            {
+                TRACE("Volume previously discarded, nothing to do.\n");
+                wined3d_volume_invalidate_location(volume, WINED3D_LOCATION_DISCARDED);
+            }
+            else if (volume->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
+            {
+                struct wined3d_bo_address data = {0, volume->resource.heap_memory};
+
+                if (volume->locations & WINED3D_LOCATION_TEXTURE_RGB)
+#endif /* STAGING_CSMT */
                     wined3d_texture_bind_and_dirtify(volume->container, context, FALSE);
                 else
                     wined3d_texture_bind_and_dirtify(volume->container, context, TRUE);
@@ -261,6 +398,7 @@
             else
             {
                 FIXME("Implement WINED3D_LOCATION_SYSMEM loading from %s.\n",
+#if defined(STAGING_CSMT)
                         wined3d_debug_location(volume->resource.locations));
                 return;
             }
@@ -276,6 +414,28 @@
                 struct wined3d_bo_address data = {volume->resource.buffer->name, NULL};
 
                 if (volume->resource.locations & WINED3D_LOCATION_TEXTURE_RGB)
+#else  /* STAGING_CSMT */
+                        wined3d_debug_location(volume->locations));
+                return;
+            }
+            wined3d_volume_validate_location(volume, WINED3D_LOCATION_SYSMEM);
+            break;
+
+        case WINED3D_LOCATION_BUFFER:
+            if (!volume->pbo)
+                ERR("Trying to load WINED3D_LOCATION_BUFFER without setting it up first.\n");
+
+            if (volume->locations & WINED3D_LOCATION_DISCARDED)
+            {
+                TRACE("Volume previously discarded, nothing to do.\n");
+                wined3d_volume_invalidate_location(volume, WINED3D_LOCATION_DISCARDED);
+            }
+            else if (volume->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
+            {
+                struct wined3d_bo_address data = {volume->pbo, NULL};
+
+                if (volume->locations & WINED3D_LOCATION_TEXTURE_RGB)
+#endif /* STAGING_CSMT */
                     wined3d_texture_bind_and_dirtify(volume->container, context, FALSE);
                 else
                     wined3d_texture_bind_and_dirtify(volume->container, context, TRUE);
@@ -285,6 +445,7 @@
             else
             {
                 FIXME("Implement WINED3D_LOCATION_BUFFER loading from %s.\n",
+#if defined(STAGING_CSMT)
                         wined3d_debug_location(volume->resource.locations));
                 return;
             }
@@ -294,6 +455,17 @@
         default:
             FIXME("Implement %s loading from %s.\n", wined3d_debug_location(location),
                     wined3d_debug_location(volume->resource.locations));
+#else  /* STAGING_CSMT */
+                        wined3d_debug_location(volume->locations));
+                return;
+            }
+            wined3d_volume_validate_location(volume, WINED3D_LOCATION_BUFFER);
+            break;
+
+        default:
+            FIXME("Implement %s loading from %s.\n", wined3d_debug_location(location),
+                    wined3d_debug_location(volume->locations));
+#endif /* STAGING_CSMT */
     }
 }
 
@@ -301,6 +473,7 @@
 void wined3d_volume_load(struct wined3d_volume *volume, struct wined3d_context *context, BOOL srgb_mode)
 {
     wined3d_texture_prepare_texture(volume->container, context, srgb_mode);
+#if defined(STAGING_CSMT)
     wined3d_resource_load_location(&volume->resource, context,
             srgb_mode ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB);
 }
@@ -313,6 +486,51 @@
     resource_cleanup(&volume->resource);
     volume->resource.parent_ops->wined3d_object_destroyed(volume->resource.parent);
     wined3d_cs_emit_volume_cleanup(device->cs, volume);
+#else  /* STAGING_CSMT */
+    wined3d_volume_load_location(volume, context,
+            srgb_mode ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB);
+}
+
+/* Context activation is done by the caller. */
+static void wined3d_volume_prepare_pbo(struct wined3d_volume *volume, struct wined3d_context *context)
+{
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+
+    if (volume->pbo)
+        return;
+
+    GL_EXTCALL(glGenBuffers(1, &volume->pbo));
+    GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, volume->pbo));
+    GL_EXTCALL(glBufferData(GL_PIXEL_UNPACK_BUFFER, volume->resource.size, NULL, GL_STREAM_DRAW));
+    GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
+    checkGLcall("Create PBO");
+
+    TRACE("Created PBO %u for volume %p.\n", volume->pbo, volume);
+}
+
+static void wined3d_volume_free_pbo(struct wined3d_volume *volume)
+{
+    struct wined3d_context *context = context_acquire(volume->resource.device, NULL);
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+
+    TRACE("Deleting PBO %u belonging to volume %p.\n", volume->pbo, volume);
+    GL_EXTCALL(glDeleteBuffers(1, &volume->pbo));
+    checkGLcall("glDeleteBuffers");
+    volume->pbo = 0;
+    context_release(context);
+}
+
+void wined3d_volume_destroy(struct wined3d_volume *volume)
+{
+    TRACE("volume %p.\n", volume);
+
+    if (volume->pbo)
+        wined3d_volume_free_pbo(volume);
+
+    resource_cleanup(&volume->resource);
+    volume->resource.parent_ops->wined3d_object_destroyed(volume->resource.parent);
+    HeapFree(GetProcessHeap(), 0, volume);
+#endif /* STAGING_CSMT */
 }
 
 static void volume_unload(struct wined3d_resource *resource)
@@ -326,6 +544,7 @@
 
     TRACE("texture %p.\n", resource);
 
+#if defined(STAGING_CSMT)
     if (wined3d_resource_prepare_system_memory(&volume->resource))
     {
         context = context_acquire(device, NULL);
@@ -338,6 +557,29 @@
         ERR("Out of memory when unloading volume %p.\n", volume);
         wined3d_resource_validate_location(&volume->resource, WINED3D_LOCATION_DISCARDED);
         wined3d_resource_invalidate_location(&volume->resource, ~WINED3D_LOCATION_DISCARDED);
+#else  /* STAGING_CSMT */
+    if (volume_prepare_system_memory(volume))
+    {
+        context = context_acquire(device, NULL);
+        wined3d_volume_load_location(volume, context, WINED3D_LOCATION_SYSMEM);
+        context_release(context);
+        wined3d_volume_invalidate_location(volume, ~WINED3D_LOCATION_SYSMEM);
+    }
+    else
+    {
+        ERR("Out of memory when unloading volume %p.\n", volume);
+        wined3d_volume_validate_location(volume, WINED3D_LOCATION_DISCARDED);
+        wined3d_volume_invalidate_location(volume, ~WINED3D_LOCATION_DISCARDED);
+    }
+
+    if (volume->pbo)
+    {
+        /* Should not happen because only dynamic default pool volumes
+         * have a buffer, and those are not evicted by device_evit_managed_resources
+         * and must be freed before a non-ex device reset. */
+        ERR("Unloading a volume with a buffer\n");
+        wined3d_volume_free_pbo(volume);
+#endif /* STAGING_CSMT */
     }
 
     /* The texture name is managed by the container. */
@@ -345,6 +587,36 @@
     resource_unload(resource);
 }
 
+#if !defined(STAGING_CSMT)
+static BOOL volume_check_block_align(const struct wined3d_volume *volume,
+        const struct wined3d_box *box)
+{
+    UINT width_mask, height_mask;
+    const struct wined3d_format *format = volume->resource.format;
+
+    if (!box)
+        return TRUE;
+
+    /* This assumes power of two block sizes, but NPOT block sizes would be
+     * silly anyway.
+     *
+     * This also assumes that the format's block depth is 1. */
+    width_mask = format->block_width - 1;
+    height_mask = format->block_height - 1;
+
+    if (box->left & width_mask)
+        return FALSE;
+    if (box->top & height_mask)
+        return FALSE;
+    if (box->right & width_mask && box->right != volume->resource.width)
+        return FALSE;
+    if (box->bottom & height_mask && box->bottom != volume->resource.height)
+        return FALSE;
+
+    return TRUE;
+}
+
+#endif /* STAGING_CSMT */
 static BOOL wined3d_volume_check_box_dimensions(const struct wined3d_volume *volume,
         const struct wined3d_box *box)
 {
@@ -370,6 +642,7 @@
 HRESULT wined3d_volume_map(struct wined3d_volume *volume,
         struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags)
 {
+#if defined(STAGING_CSMT)
     HRESULT hr;
     const struct wined3d_format *format = volume->resource.format;
     const unsigned int fmt_flags = volume->container->resource.format_flags;
@@ -410,6 +683,177 @@
     if (hr == WINEDDERR_NOTLOCKED)
         return WINED3DERR_INVALIDCALL;
     return hr;
+#else  /* STAGING_CSMT */
+    struct wined3d_device *device = volume->resource.device;
+    struct wined3d_context *context;
+    const struct wined3d_gl_info *gl_info;
+    BYTE *base_memory;
+    const struct wined3d_format *format = volume->resource.format;
+    const unsigned int fmt_flags = volume->container->resource.format_flags;
+
+    TRACE("volume %p, map_desc %p, box %p, flags %#x.\n",
+            volume, map_desc, box, flags);
+
+    map_desc->data = NULL;
+    if (!(volume->resource.access_flags & WINED3D_RESOURCE_ACCESS_CPU))
+    {
+        WARN("Volume %p is not CPU accessible.\n", volume);
+        return WINED3DERR_INVALIDCALL;
+    }
+    if (volume->resource.map_count)
+    {
+        WARN("Volume is already mapped.\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+    if (!wined3d_volume_check_box_dimensions(volume, box))
+    {
+        WARN("Map box is invalid.\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+    if ((fmt_flags & WINED3DFMT_FLAG_BLOCKS) && !volume_check_block_align(volume, box))
+    {
+        WARN("Map box is misaligned for %ux%u blocks.\n",
+                format->block_width, format->block_height);
+        return WINED3DERR_INVALIDCALL;
+    }
+
+    flags = wined3d_resource_sanitize_map_flags(&volume->resource, flags);
+
+    if (volume->resource.map_binding == WINED3D_LOCATION_BUFFER)
+    {
+        context = context_acquire(device, NULL);
+        gl_info = context->gl_info;
+
+        wined3d_volume_prepare_pbo(volume, context);
+        if (flags & WINED3D_MAP_DISCARD)
+            wined3d_volume_validate_location(volume, WINED3D_LOCATION_BUFFER);
+        else
+            wined3d_volume_load_location(volume, context, WINED3D_LOCATION_BUFFER);
+
+        GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, volume->pbo));
+
+        if (gl_info->supported[ARB_MAP_BUFFER_RANGE])
+        {
+            GLbitfield mapflags = wined3d_resource_gl_map_flags(flags);
+            mapflags &= ~GL_MAP_FLUSH_EXPLICIT_BIT;
+            base_memory = GL_EXTCALL(glMapBufferRange(GL_PIXEL_UNPACK_BUFFER,
+                    0, volume->resource.size, mapflags));
+        }
+        else
+        {
+            GLenum access = wined3d_resource_gl_legacy_map_flags(flags);
+            base_memory = GL_EXTCALL(glMapBuffer(GL_PIXEL_UNPACK_BUFFER, access));
+        }
+
+        GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
+        checkGLcall("Map PBO");
+
+        context_release(context);
+    }
+    else
+    {
+        if (!volume_prepare_system_memory(volume))
+        {
+            WARN("Out of memory.\n");
+            map_desc->data = NULL;
+            return E_OUTOFMEMORY;
+        }
+
+        if (flags & WINED3D_MAP_DISCARD)
+        {
+            wined3d_volume_validate_location(volume, WINED3D_LOCATION_SYSMEM);
+        }
+        else if (!(volume->locations & WINED3D_LOCATION_SYSMEM))
+        {
+            context = context_acquire(device, NULL);
+            wined3d_volume_load_location(volume, context, WINED3D_LOCATION_SYSMEM);
+            context_release(context);
+        }
+        base_memory = volume->resource.heap_memory;
+    }
+
+    TRACE("Base memory pointer %p.\n", base_memory);
+
+    if (fmt_flags & WINED3DFMT_FLAG_BROKEN_PITCH)
+    {
+        map_desc->row_pitch = volume->resource.width * format->byte_count;
+        map_desc->slice_pitch = map_desc->row_pitch * volume->resource.height;
+    }
+    else
+    {
+        wined3d_volume_get_pitch(volume, &map_desc->row_pitch, &map_desc->slice_pitch);
+    }
+
+    if (!box)
+    {
+        TRACE("No box supplied - all is ok\n");
+        map_desc->data = base_memory;
+    }
+    else
+    {
+        TRACE("Lock Box (%p) = l %u, t %u, r %u, b %u, fr %u, ba %u\n",
+                box, box->left, box->top, box->right, box->bottom, box->front, box->back);
+
+        if ((fmt_flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
+        {
+            /* Compressed textures are block based, so calculate the offset of
+             * the block that contains the top-left pixel of the locked rectangle. */
+            map_desc->data = base_memory
+                    + (box->front * map_desc->slice_pitch)
+                    + ((box->top / format->block_height) * map_desc->row_pitch)
+                    + ((box->left / format->block_width) * format->block_byte_count);
+        }
+        else
+        {
+            map_desc->data = base_memory
+                    + (map_desc->slice_pitch * box->front)
+                    + (map_desc->row_pitch * box->top)
+                    + (box->left * volume->resource.format->byte_count);
+        }
+    }
+
+    if (!(flags & (WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY)))
+    {
+        wined3d_texture_set_dirty(volume->container);
+        wined3d_volume_invalidate_location(volume, ~volume->resource.map_binding);
+    }
+
+    volume->resource.map_count++;
+
+    TRACE("Returning memory %p, row pitch %d, slice pitch %d.\n",
+            map_desc->data, map_desc->row_pitch, map_desc->slice_pitch);
+
+    return WINED3D_OK;
+}
+
+HRESULT wined3d_volume_unmap(struct wined3d_volume *volume)
+{
+    TRACE("volume %p.\n", volume);
+
+    if (!volume->resource.map_count)
+    {
+        WARN("Trying to unlock an unlocked volume %p.\n", volume);
+        return WINED3DERR_INVALIDCALL;
+    }
+
+    if (volume->resource.map_binding == WINED3D_LOCATION_BUFFER)
+    {
+        struct wined3d_device *device = volume->resource.device;
+        struct wined3d_context *context = context_acquire(device, NULL);
+        const struct wined3d_gl_info *gl_info = context->gl_info;
+
+        GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, volume->pbo));
+        GL_EXTCALL(glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER));
+        GL_EXTCALL(glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0));
+        checkGLcall("Unmap PBO");
+
+        context_release(context);
+    }
+
+    volume->resource.map_count--;
+
+    return WINED3D_OK;
+#endif /* STAGING_CSMT */
 }
 
 static ULONG volume_resource_incref(struct wined3d_resource *resource)
@@ -420,11 +864,13 @@
     return wined3d_texture_incref(volume->container);
 }
 
+#if defined(STAGING_CSMT)
 void wined3d_volume_cleanup_cs(struct wined3d_volume *volume)
 {
     HeapFree(GetProcessHeap(), 0, volume);
 }
 
+#endif /* STAGING_CSMT */
 static ULONG volume_resource_decref(struct wined3d_resource *resource)
 {
     struct wined3d_volume *volume = volume_from_resource(resource);
@@ -446,6 +892,7 @@
     return WINED3DERR_INVALIDCALL;
 }
 
+#if defined(STAGING_CSMT)
 static void wined3d_volume_location_invalidated(struct wined3d_resource *resource, DWORD location)
 {
     struct wined3d_volume *volume = volume_from_resource(resource);
@@ -454,6 +901,7 @@
         wined3d_texture_set_dirty(volume->container);
 }
 
+#endif /* STAGING_CSMT */
 static const struct wined3d_resource_ops volume_resource_ops =
 {
     volume_resource_incref,
@@ -461,8 +909,10 @@
     volume_unload,
     volume_resource_sub_resource_map,
     volume_resource_sub_resource_unmap,
+#if defined(STAGING_CSMT)
     wined3d_volume_location_invalidated,
     wined3d_volume_load_location,
+#endif /* STAGING_CSMT */
 };
 
 static HRESULT volume_init(struct wined3d_volume *volume, struct wined3d_texture *container,
@@ -494,7 +944,11 @@
     }
 
     volume->texture_level = level;
+#if defined(STAGING_CSMT)
     volume->resource.locations = WINED3D_LOCATION_DISCARDED;
+#else  /* STAGING_CSMT */
+    volume->locations = WINED3D_LOCATION_DISCARDED;
+#endif /* STAGING_CSMT */
 
     if (desc->pool == WINED3D_POOL_DEFAULT && desc->usage & WINED3DUSAGE_DYNAMIC
             && gl_info->supported[ARB_PIXEL_BUFFER_OBJECT]
@@ -502,7 +956,9 @@
     {
         wined3d_resource_free_sysmem(&volume->resource);
         volume->resource.map_binding = WINED3D_LOCATION_BUFFER;
+#if defined(STAGING_CSMT)
         volume->resource.map_heap_memory = NULL;
+#endif /* STAGING_CSMT */
     }
 
     volume->container = container;
diff --git a/dlls/wined3d/wined3d_main.c b/dlls/wined3d/wined3d_main.c
--- a/dlls/wined3d/wined3d_main.c
+++ b/dlls/wined3d/wined3d_main.c
@@ -87,8 +87,10 @@
     ~0U,            /* No GS shader model limit by default. */
     ~0U,            /* No PS shader model limit by default. */
     FALSE,          /* 3D support enabled by default. */
+#if defined(STAGING_CSMT)
     TRUE,           /* Multithreaded CS by default. */
     FALSE,          /* Do not ignore render target maps. */
+#endif /* STAGING_CSMT */
 };
 
 struct wined3d * CDECL wined3d_create(DWORD flags)
@@ -328,6 +330,7 @@
             TRACE("Disabling 3D support.\n");
             wined3d_settings.no_3d = TRUE;
         }
+#if defined(STAGING_CSMT)
         if (!get_config_key(hkey, appkey, "CSMT", buffer, size)
                 && !strcmp(buffer,"disabled"))
         {
@@ -344,6 +347,9 @@
 
     FIXME_(winediag)("Experimental wined3d CSMT feature is currently %s.\n",
         wined3d_settings.cs_multithreaded ? "enabled" : "disabled");
+#else  /* STAGING_CSMT */
+    }
+#endif /* STAGING_CSMT */
 
     if (appkey) RegCloseKey( appkey );
     if (hkey) RegCloseKey( hkey );
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1,3 +1,4 @@
+#if defined(STAGING_CSMT)
 /*
  * Direct3D wine internal private include file
  *
@@ -21,6 +22,31 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
+#else  /* STAGING_CSMT */
+/*
+ * Direct3D wine internal private include file
+ *
+ * Copyright 2002-2003 The wine-d3d team
+ * Copyright 2002-2003 Raphael Junqueira
+ * Copyright 2002-2003, 2004 Jason Edmeades
+ * Copyright 2005 Oliver Stieber
+ * Copyright 2006-2011, 2013 Stefan Dösinger for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#endif /* STAGING_CSMT */
 
 #ifndef __WINE_WINED3D_PRIVATE_H
 #define __WINE_WINED3D_PRIVATE_H
@@ -31,7 +57,9 @@
 #define WINE_GLAPI
 #endif
 
+#if defined(STAGING_CSMT)
 #include <assert.h>
+#endif /* STAGING_CSMT */
 #include <stdarg.h>
 #include <math.h>
 #include <limits.h>
@@ -284,8 +312,10 @@
     unsigned int max_sm_gs;
     unsigned int max_sm_ps;
     BOOL no_3d;
+#if defined(STAGING_CSMT)
     BOOL cs_multithreaded;
     BOOL ignore_rt_map;
+#endif /* STAGING_CSMT */
 };
 
 extern struct wined3d_settings wined3d_settings DECLSPEC_HIDDEN;
@@ -1038,9 +1068,14 @@
     WORD use_map; /* MAX_ATTRIBS, 16 */
 };
 
+#if defined(STAGING_CSMT)
 void draw_primitive(struct wined3d_device *device, const struct wined3d_state *state,
         UINT start_idx, UINT index_count, UINT start_instance, UINT instance_count,
         BOOL indexed) DECLSPEC_HIDDEN;
+#else  /* STAGING_CSMT */
+void draw_primitive(struct wined3d_device *device, UINT start_idx, UINT index_count,
+        UINT start_instance, UINT instance_count, BOOL indexed) DECLSPEC_HIDDEN;
+#endif /* STAGING_CSMT */
 DWORD get_flexible_vertex_size(DWORD d3dvtVertexType) DECLSPEC_HIDDEN;
 
 #define eps 1e-8f
@@ -1128,8 +1163,10 @@
     struct list entry;
     GLuint id;
     struct wined3d_context *context;
+#if defined(STAGING_CSMT)
     DWORD samples;
     BOOL started;
+#endif /* STAGING_CSMT */
 };
 
 union wined3d_gl_query_object
@@ -1165,6 +1202,7 @@
     struct list entry;
     GLuint id;
     struct wined3d_context *context;
+#if defined(STAGING_CSMT)
     UINT64 timestamp;
 };
 
@@ -1200,6 +1238,12 @@
     for (i = 0; i < min(dst->rt_size, src->rt_size); i++)
         dst->render_targets[i] = src->render_targets[i];
 }
+#else  /* STAGING_CSMT */
+};
+
+void context_alloc_timestamp_query(struct wined3d_context *context, struct wined3d_timestamp_query *query) DECLSPEC_HIDDEN;
+void context_free_timestamp_query(struct wined3d_timestamp_query *query) DECLSPEC_HIDDEN;
+#endif /* STAGING_CSMT */
 
 struct wined3d_context
 {
@@ -1215,7 +1259,9 @@
     DWORD                   dirtyArray[STATE_HIGHEST + 1]; /* Won't get bigger than that, a state is never marked dirty 2 times */
     DWORD                   numDirtyEntries;
     DWORD isStateDirty[STATE_HIGHEST / (sizeof(DWORD) * CHAR_BIT) + 1]; /* Bitmap to find out quickly if a state is dirty */
+#if defined(STAGING_CSMT)
     struct wined3d_fb_state current_fb;
+#endif /* STAGING_CSMT */
 
     struct wined3d_swapchain *swapchain;
     struct wined3d_surface *current_rt;
@@ -1313,8 +1359,17 @@
     GLfloat                 fog_coord_value;
     GLfloat                 color[4], fogstart, fogend, fogcolor[4];
     GLuint                  dummy_arbfp_prog;
+#if defined(STAGING_CSMT)
 
     GLenum                  offscreenBuffer;
+#else  /* STAGING_CSMT */
+};
+
+struct wined3d_fb_state
+{
+    struct wined3d_rendertarget_view **render_targets;
+    struct wined3d_rendertarget_view *depth_stencil;
+#endif /* STAGING_CSMT */
 };
 
 typedef void (*APPLYSTATEFUNC)(struct wined3d_context *ctx, const struct wined3d_state *state, DWORD state_id);
@@ -1457,8 +1512,12 @@
 void context_apply_blit_state(struct wined3d_context *context, const struct wined3d_device *device) DECLSPEC_HIDDEN;
 BOOL context_apply_clear_state(struct wined3d_context *context, const struct wined3d_device *device,
         UINT rt_count, const struct wined3d_fb_state *fb) DECLSPEC_HIDDEN;
+#if defined(STAGING_CSMT)
 BOOL context_apply_draw_state(struct wined3d_context *context, const struct wined3d_device *device,
         const struct wined3d_state *state) DECLSPEC_HIDDEN;
+#else  /* STAGING_CSMT */
+BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_device *device) DECLSPEC_HIDDEN;
+#endif /* STAGING_CSMT */
 void context_apply_fbo_state_blit(struct wined3d_context *context, GLenum target,
         struct wined3d_surface *render_target, struct wined3d_surface *depth_stencil, DWORD location) DECLSPEC_HIDDEN;
 void context_active_texture(struct wined3d_context *context, const struct wined3d_gl_info *gl_info,
@@ -2041,7 +2100,11 @@
 struct wined3d_state
 {
     DWORD flags;
+#if defined(STAGING_CSMT)
     struct wined3d_fb_state fb;
+#else  /* STAGING_CSMT */
+    const struct wined3d_fb_state *fb;
+#endif /* STAGING_CSMT */
 
     struct wined3d_vertex_declaration *vertex_declaration;
     struct wined3d_stream_output stream_output[MAX_STREAM_OUT];
@@ -2086,6 +2149,7 @@
     DWORD render_states[WINEHIGHEST_RENDER_STATE + 1];
 };
 
+#if defined(STAGING_CSMT)
 struct wined3d_gl_bo
 {
     GLuint name;
@@ -2094,6 +2158,7 @@
     UINT size;
 };
 
+#endif /* STAGING_CSMT */
 #define WINED3D_UNMAPPED_STAGE ~0U
 
 /* Multithreaded flag. Removed from the public header to signal that
@@ -2149,11 +2214,23 @@
     struct wined3d_rendertarget_view *back_buffer_view;
     struct wined3d_swapchain **swapchains;
     UINT swapchain_count;
+#if defined(STAGING_CSMT)
     struct wined3d_rendertarget_view *auto_depth_stencil_view;
 
     struct list             resources; /* a linked list to track resources created by the device */
     struct list             shaders;   /* a linked list to track shaders (pixel and vertex)      */
     struct wine_rb_tree samplers;
+#else  /* STAGING_CSMT */
+
+    struct list             resources; /* a linked list to track resources created by the device */
+    struct list             shaders;   /* a linked list to track shaders (pixel and vertex)      */
+    struct wine_rb_tree samplers;
+
+    /* Render Target Support */
+    struct wined3d_fb_state fb;
+    struct wined3d_surface *onscreen_depth_stencil;
+    struct wined3d_rendertarget_view *auto_depth_stencil_view;
+#endif /* STAGING_CSMT */
 
     /* For rendering to a texture using glCopyTexImage */
     GLuint                  depth_blt_texture;
@@ -2164,6 +2241,9 @@
     UINT                    xScreenSpace;
     UINT                    yScreenSpace;
     UINT                    cursorWidth, cursorHeight;
+#if !defined(STAGING_CSMT)
+    struct wined3d_texture *cursor_texture;
+#endif /* STAGING_CSMT */
     HCURSOR                 hardwareCursor;
 
     /* The Wine logo texture */
@@ -2198,6 +2278,7 @@
         UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc) DECLSPEC_HIDDEN;
 void device_resource_add(struct wined3d_device *device, struct wined3d_resource *resource) DECLSPEC_HIDDEN;
 void device_resource_released(struct wined3d_device *device, struct wined3d_resource *resource) DECLSPEC_HIDDEN;
+#if defined(STAGING_CSMT)
 void device_invalidate_state(const struct wined3d_device *device, DWORD state) DECLSPEC_HIDDEN;
 void device_invalidate_shader_constants(const struct wined3d_device *device, DWORD mask) DECLSPEC_HIDDEN;
 void device_exec_update_texture(struct wined3d_context *context, struct wined3d_texture *src_texture,
@@ -2210,6 +2291,11 @@
 void device_create_default_sampler(struct wined3d_device *device);
 void device_delete_opengl_contexts_cs(struct wined3d_device *device,
         struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
+#else  /* STAGING_CSMT */
+void device_switch_onscreen_ds(struct wined3d_device *device, struct wined3d_context *context,
+        struct wined3d_surface *depth_stencil) DECLSPEC_HIDDEN;
+void device_invalidate_state(const struct wined3d_device *device, DWORD state) DECLSPEC_HIDDEN;
+#endif /* STAGING_CSMT */
 
 static inline BOOL isStateDirty(const struct wined3d_context *context, DWORD state)
 {
@@ -2229,9 +2315,11 @@
     HRESULT (*resource_sub_resource_map)(struct wined3d_resource *resource, unsigned int sub_resource_idx,
             struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags);
     HRESULT (*resource_sub_resource_unmap)(struct wined3d_resource *resource, unsigned int sub_resource_idx);
+#if defined(STAGING_CSMT)
     void (*resource_location_invalidated)(struct wined3d_resource *resource, DWORD location);
     void (*resource_load_location)(struct wined3d_resource *resource,
             struct wined3d_context *context, DWORD location);
+#endif /* STAGING_CSMT */
 };
 
 struct wined3d_resource
@@ -2256,6 +2344,7 @@
     UINT depth;
     UINT size;
     DWORD priority;
+#if defined(STAGING_CSMT)
     void *heap_memory, *map_heap_memory, *user_memory, *bitmap_data;
     UINT custom_row_pitch, custom_slice_pitch;
     struct wined3d_gl_bo *buffer, *map_buffer;
@@ -2263,6 +2352,10 @@
     DWORD locations;
     LONG access_fence;
     BOOL unmap_dirtify;
+#else  /* STAGING_CSMT */
+    void *heap_memory;
+    struct list resource_list_entry;
+#endif /* STAGING_CSMT */
 
     void *parent;
     const struct wined3d_parent_ops *parent_ops;
@@ -2287,6 +2380,7 @@
         void *parent, const struct wined3d_parent_ops *parent_ops,
         const struct wined3d_resource_ops *resource_ops) DECLSPEC_HIDDEN;
 void resource_unload(struct wined3d_resource *resource) DECLSPEC_HIDDEN;
+#if defined(STAGING_CSMT)
 DWORD wined3d_resource_access_from_location(DWORD location) DECLSPEC_HIDDEN;
 BOOL wined3d_resource_allocate_sysmem(struct wined3d_resource *resource) DECLSPEC_HIDDEN;
 void wined3d_resource_changed(struct wined3d_resource *resource,
@@ -2335,6 +2429,15 @@
 {
     while(InterlockedCompareExchange(&resource->access_fence, 0, 0));
 }
+#else  /* STAGING_CSMT */
+BOOL wined3d_resource_allocate_sysmem(struct wined3d_resource *resource) DECLSPEC_HIDDEN;
+void wined3d_resource_free_sysmem(struct wined3d_resource *resource) DECLSPEC_HIDDEN;
+GLbitfield wined3d_resource_gl_map_flags(DWORD d3d_flags) DECLSPEC_HIDDEN;
+GLenum wined3d_resource_gl_legacy_map_flags(DWORD d3d_flags) DECLSPEC_HIDDEN;
+BOOL wined3d_resource_is_offscreen(struct wined3d_resource *resource) DECLSPEC_HIDDEN;
+DWORD wined3d_resource_sanitize_map_flags(const struct wined3d_resource *resource, DWORD flags) DECLSPEC_HIDDEN;
+void wined3d_resource_update_draw_binding(struct wined3d_resource *resource) DECLSPEC_HIDDEN;
+#endif /* STAGING_CSMT */
 
 /* Tests show that the start address of resources is 32 byte aligned */
 #define RESOURCE_ALIGNMENT 16
@@ -2419,7 +2522,9 @@
 
 void wined3d_texture_apply_sampler_desc(struct wined3d_texture *texture,
         const struct wined3d_sampler_desc *sampler_desc, const struct wined3d_gl_info *gl_info) DECLSPEC_HIDDEN;
+#if defined(STAGING_CSMT)
 void wined3d_texture_cleanup_cs(struct wined3d_texture *texture) DECLSPEC_HIDDEN;
+#endif /* STAGING_CSMT */
 void wined3d_texture_bind(struct wined3d_texture *texture,
         struct wined3d_context *context, BOOL srgb) DECLSPEC_HIDDEN;
 void wined3d_texture_bind_and_dirtify(struct wined3d_texture *texture,
@@ -2451,8 +2556,15 @@
     struct wined3d_resource resource;
     struct wined3d_texture *container;
 
+#if defined(STAGING_CSMT)
+    GLint texture_level;
+    DWORD download_count;
+#else  /* STAGING_CSMT */
+    DWORD locations;
     GLint texture_level;
     DWORD download_count;
+    GLuint pbo;
+#endif /* STAGING_CSMT */
 };
 
 static inline struct wined3d_volume *volume_from_resource(struct wined3d_resource *resource)
@@ -2460,6 +2572,7 @@
     return CONTAINING_RECORD(resource, struct wined3d_volume, resource);
 }
 
+#if defined(STAGING_CSMT)
 HRESULT wined3d_volume_create(struct wined3d_texture *container, const struct wined3d_resource_desc *desc,
         unsigned int level, struct wined3d_volume **volume) DECLSPEC_HIDDEN;
 void wined3d_volume_destroy(struct wined3d_volume *volume) DECLSPEC_HIDDEN;
@@ -2475,6 +2588,27 @@
 struct wined3d_surface_dib
 {
     HBITMAP DIBsection;
+#else  /* STAGING_CSMT */
+BOOL volume_prepare_system_memory(struct wined3d_volume *volume) DECLSPEC_HIDDEN;
+HRESULT wined3d_volume_create(struct wined3d_texture *container, const struct wined3d_resource_desc *desc,
+        unsigned int level, struct wined3d_volume **volume) DECLSPEC_HIDDEN;
+void wined3d_volume_destroy(struct wined3d_volume *volume) DECLSPEC_HIDDEN;
+void wined3d_volume_get_pitch(const struct wined3d_volume *volume, UINT *row_pitch, UINT *slice_pitch) DECLSPEC_HIDDEN;
+void wined3d_volume_load(struct wined3d_volume *volume, struct wined3d_context *context,
+        BOOL srgb_mode) DECLSPEC_HIDDEN;
+void wined3d_volume_invalidate_location(struct wined3d_volume *volume, DWORD location) DECLSPEC_HIDDEN;
+HRESULT wined3d_volume_map(struct wined3d_volume *volume,
+        struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags) DECLSPEC_HIDDEN;
+void wined3d_volume_validate_location(struct wined3d_volume *volume, DWORD location) DECLSPEC_HIDDEN;
+HRESULT wined3d_volume_unmap(struct wined3d_volume *volume) DECLSPEC_HIDDEN;
+void wined3d_volume_upload_data(struct wined3d_volume *volume, const struct wined3d_context *context,
+        const struct wined3d_const_bo_address *data) DECLSPEC_HIDDEN;
+
+struct wined3d_surface_dib
+{
+    HBITMAP DIBsection;
+    void *bitmap_data;
+#endif /* STAGING_CSMT */
     UINT bitmap_size;
 };
 
@@ -2500,7 +2634,11 @@
 struct wined3d_surface_ops
 {
     HRESULT (*surface_private_setup)(struct wined3d_surface *surface);
+#if defined(STAGING_CSMT)
     void (*surface_frontbuffer_updated)(struct wined3d_surface *surface);
+#else  /* STAGING_CSMT */
+    void (*surface_unmap)(struct wined3d_surface *surface);
+#endif /* STAGING_CSMT */
 };
 
 struct wined3d_surface
@@ -2508,12 +2646,26 @@
     struct wined3d_resource resource;
     const struct wined3d_surface_ops *surface_ops;
     struct wined3d_texture *container;
+#if defined(STAGING_CSMT)
 
     DWORD flags;
 
     UINT pow2Width;
     UINT pow2Height;
 
+#else  /* STAGING_CSMT */
+    void *user_memory;
+    DWORD locations;
+
+    DWORD flags;
+
+    UINT pitch;
+    UINT pow2Width;
+    UINT pow2Height;
+
+    /* PBO */
+    GLuint                    pbo;
+#endif /* STAGING_CSMT */
     GLuint rb_multisample;
     GLuint rb_resolved;
     GLenum texture_target;
@@ -2557,11 +2709,22 @@
 GLenum surface_get_gl_buffer(const struct wined3d_surface *surface) DECLSPEC_HIDDEN;
 void surface_get_drawable_size(const struct wined3d_surface *surface, const struct wined3d_context *context,
         unsigned int *width, unsigned int *height) DECLSPEC_HIDDEN;
+#if defined(STAGING_CSMT)
 void surface_load(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb) DECLSPEC_HIDDEN;
 void surface_load_ds_location(struct wined3d_surface *surface,
         struct wined3d_context *context, DWORD location) DECLSPEC_HIDDEN;
 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb,
         struct wined3d_context *context) DECLSPEC_HIDDEN;
+#else  /* STAGING_CSMT */
+void surface_invalidate_location(struct wined3d_surface *surface, DWORD location) DECLSPEC_HIDDEN;
+void surface_load(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb) DECLSPEC_HIDDEN;
+void surface_load_ds_location(struct wined3d_surface *surface,
+        struct wined3d_context *context, DWORD location) DECLSPEC_HIDDEN;
+void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb,
+        struct wined3d_context *context) DECLSPEC_HIDDEN;
+HRESULT surface_load_location(struct wined3d_surface *surface,
+        struct wined3d_context *context, DWORD location) DECLSPEC_HIDDEN;
+#endif /* STAGING_CSMT */
 void surface_modify_ds_location(struct wined3d_surface *surface, DWORD location, UINT w, UINT h) DECLSPEC_HIDDEN;
 void wined3d_surface_prepare(struct wined3d_surface *surface, struct wined3d_context *context,
         DWORD location) DECLSPEC_HIDDEN;
@@ -2573,6 +2736,7 @@
         const struct wined3d_gl_info *gl_info, void *mem, unsigned int pitch) DECLSPEC_HIDDEN;
 HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
         struct wined3d_surface *src_surface, const RECT *src_rect) DECLSPEC_HIDDEN;
+#if defined(STAGING_CSMT)
 HRESULT wined3d_surface_create(struct wined3d_texture *container, const struct wined3d_resource_desc *desc,
         GLenum target, unsigned int level, unsigned int layer, DWORD flags,
         struct wined3d_surface **surface) DECLSPEC_HIDDEN;
@@ -2587,6 +2751,17 @@
 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;
+#else  /* STAGING_CSMT */
+void surface_validate_location(struct wined3d_surface *surface, DWORD location) DECLSPEC_HIDDEN;
+HRESULT wined3d_surface_create(struct wined3d_texture *container, const struct wined3d_resource_desc *desc,
+        GLenum target, unsigned int level, unsigned int layer, DWORD flags,
+        struct wined3d_surface **surface) DECLSPEC_HIDDEN;
+void wined3d_surface_destroy(struct wined3d_surface *surface) DECLSPEC_HIDDEN;
+void surface_prepare_map_memory(struct wined3d_surface *surface) DECLSPEC_HIDDEN;
+void wined3d_surface_upload_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
+        const struct wined3d_format *format, const RECT *src_rect, UINT src_pitch, const POINT *dst_point,
+        BOOL srgb, const struct wined3d_const_bo_address *data) DECLSPEC_HIDDEN;
+#endif /* STAGING_CSMT */
 
 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;
@@ -2607,8 +2782,10 @@
     GLuint name;
 };
 
+#if defined(STAGING_CSMT)
 void wined3d_sampler_destroy(struct wined3d_sampler *sampler) DECLSPEC_HIDDEN;
 
+#endif /* STAGING_CSMT */
 struct wined3d_vertex_declaration_element
 {
     const struct wined3d_format *format;
@@ -2637,8 +2814,10 @@
     BOOL half_float_conv_needed;
 };
 
+#if defined(STAGING_CSMT)
 void wined3d_vertex_declaration_destroy(struct wined3d_vertex_declaration *declaration) DECLSPEC_HIDDEN;
 
+#endif /* STAGING_CSMT */
 struct wined3d_saved_states
 {
     DWORD transform[(HIGHEST_TRANSFORMSTATE >> 5) + 1];
@@ -2706,6 +2885,7 @@
 void stateblock_init_contained_states(struct wined3d_stateblock *stateblock) DECLSPEC_HIDDEN;
 
 void state_cleanup(struct wined3d_state *state) DECLSPEC_HIDDEN;
+#if defined(STAGING_CSMT)
 HRESULT state_init(struct wined3d_state *state, const struct wined3d_gl_info *gl_info,
         const struct wined3d_d3d_info *d3d_info, DWORD flags) DECLSPEC_HIDDEN;
 void state_unbind_resources(struct wined3d_state *state) DECLSPEC_HIDDEN;
@@ -2756,6 +2936,32 @@
 void wined3d_cs_destroy(struct wined3d_cs *cs) DECLSPEC_HIDDEN;
 void wined3d_cs_switch_onscreen_ds(struct wined3d_cs *cs, struct wined3d_context *context,
         struct wined3d_surface *depth_stencil) DECLSPEC_HIDDEN;
+#else  /* STAGING_CSMT */
+HRESULT state_init(struct wined3d_state *state, struct wined3d_fb_state *fb,
+        const struct wined3d_gl_info *gl_info, const struct wined3d_d3d_info *d3d_info,
+        DWORD flags) DECLSPEC_HIDDEN;
+void state_unbind_resources(struct wined3d_state *state) DECLSPEC_HIDDEN;
+
+struct wined3d_cs_ops
+{
+    void *(*require_space)(struct wined3d_cs *cs, size_t size);
+    void (*submit)(struct wined3d_cs *cs);
+};
+
+struct wined3d_cs
+{
+    const struct wined3d_cs_ops *ops;
+    struct wined3d_device *device;
+    struct wined3d_fb_state fb;
+    struct wined3d_state state;
+
+    size_t data_size;
+    void *data;
+};
+
+struct wined3d_cs *wined3d_cs_create(struct wined3d_device *device) DECLSPEC_HIDDEN;
+void wined3d_cs_destroy(struct wined3d_cs *cs) DECLSPEC_HIDDEN;
+#endif /* STAGING_CSMT */
 
 void wined3d_cs_emit_clear(struct wined3d_cs *cs, DWORD rect_count, const RECT *rects,
         DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil) DECLSPEC_HIDDEN;
@@ -2805,6 +3011,7 @@
 void wined3d_cs_emit_set_vertex_declaration(struct wined3d_cs *cs,
         struct wined3d_vertex_declaration *declaration) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_set_viewport(struct wined3d_cs *cs, const struct wined3d_viewport *viewport) DECLSPEC_HIDDEN;
+#if defined(STAGING_CSMT)
 void wined3d_cs_emit_set_consts_f(struct wined3d_cs *cs, UINT start_register, const float *constants,
         UINT vector4f_count, enum wined3d_shader_type type) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_set_consts_b(struct wined3d_cs *cs, UINT start_register,
@@ -2868,6 +3075,7 @@
 void wined3d_cs_emit_update_sub_resource(struct wined3d_cs *cs, struct wined3d_resource *resource,
         unsigned int sub_resource_idx, const struct wined3d_box *box, const void *data, unsigned int row_pitch,
         unsigned int depth_pitch) DECLSPEC_HIDDEN;
+#endif /* STAGING_CSMT */
 
 /* 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
@@ -2882,8 +3090,12 @@
 struct wined3d_query_ops
 {
     HRESULT (*query_get_data)(struct wined3d_query *query, void *data, DWORD data_size, DWORD flags);
+#if defined(STAGING_CSMT)
     BOOL (*query_poll)(struct wined3d_query *query);
     BOOL (*query_issue)(struct wined3d_query *query, DWORD flags);
+#else  /* STAGING_CSMT */
+    HRESULT (*query_issue)(struct wined3d_query *query, DWORD flags);
+#endif /* STAGING_CSMT */
 };
 
 struct wined3d_query
@@ -2897,12 +3109,16 @@
     enum wined3d_query_type type;
     DWORD data_size;
     void                     *extendedData;
+#if defined(STAGING_CSMT)
 
     LONG                     counter_main, counter_retrieved;
     struct list              poll_list_entry;
 };
 
 void wined3d_query_destroy(struct wined3d_query *query) DECLSPEC_HIDDEN;
+#else  /* STAGING_CSMT */
+};
+#endif /* STAGING_CSMT */
 
 /* TODO: Add tests and support for FLOAT16_4 POSITIONT, D3DCOLOR position, other
  * fixed function semantics as D3DCOLOR or FLOAT16 */
@@ -2929,7 +3145,9 @@
     GLenum buffer_object_usage;
     GLenum buffer_type_hint;
     DWORD flags;
+#if defined(STAGING_CSMT)
     BOOL ignore_discard;
+#endif /* STAGING_CSMT */
     void *map_ptr;
 
     struct wined3d_map_range *maps;
@@ -2954,11 +3172,15 @@
 BYTE *buffer_get_sysmem(struct wined3d_buffer *This, struct wined3d_context *context) DECLSPEC_HIDDEN;
 void buffer_internal_preload(struct wined3d_buffer *buffer, struct wined3d_context *context,
         const struct wined3d_state *state) DECLSPEC_HIDDEN;
+#if defined(STAGING_CSMT)
 void buffer_invalidate_bo_range(struct wined3d_buffer *This, UINT offset, UINT size) DECLSPEC_HIDDEN;
 void buffer_swap_mem(struct wined3d_buffer *buffer, BYTE *mem) DECLSPEC_HIDDEN;
 void buffer_create_buffer_object(struct wined3d_buffer *This,
         struct wined3d_context *context) DECLSPEC_HIDDEN;
 void wined3d_buffer_cleanup_cs(struct wined3d_buffer *buffer) DECLSPEC_HIDDEN;
+#else  /* STAGING_CSMT */
+void buffer_mark_used(struct wined3d_buffer *buffer) DECLSPEC_HIDDEN;
+#endif /* STAGING_CSMT */
 HRESULT wined3d_buffer_upload_data(struct wined3d_buffer *buffer,
         const struct wined3d_box *box, const void *data) DECLSPEC_HIDDEN;
 
@@ -2999,8 +3221,10 @@
     return surface_from_resource(resource);
 }
 
+#if defined(STAGING_CSMT)
 void wined3d_rendertarget_view_destroy(struct wined3d_rendertarget_view *view) DECLSPEC_HIDDEN;
 
+#endif /* STAGING_CSMT */
 struct wined3d_shader_resource_view
 {
     LONG refcount;
@@ -3013,8 +3237,12 @@
 struct wined3d_swapchain_ops
 {
     void (*swapchain_present)(struct wined3d_swapchain *swapchain, const RECT *src_rect,
+#if defined(STAGING_CSMT)
             const RECT *dst_rect, const RGNDATA *dirty_region, DWORD flags,
             struct wined3d_surface *depth_stencil);
+#else  /* STAGING_CSMT */
+            const RECT *dst_rect, const RGNDATA *dirty_region, DWORD flags);
+#endif /* STAGING_CSMT */
 };
 
 struct wined3d_swapchain
@@ -3053,8 +3281,10 @@
 void swapchain_destroy_contexts(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
 HDC swapchain_get_backup_dc(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
 void swapchain_update_draw_bindings(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
+#if defined(STAGING_CSMT)
 HRESULT swapchain_create_context_cs(struct wined3d_device *device,
         struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
+#endif /* STAGING_CSMT */
 
 /*****************************************************************************
  * Utility function prototypes
@@ -3258,7 +3488,9 @@
 void shader_generate_main(const struct wined3d_shader *shader, struct wined3d_string_buffer *buffer,
         const struct wined3d_shader_reg_maps *reg_maps, const DWORD *byte_code, void *backend_ctx) DECLSPEC_HIDDEN;
 BOOL shader_match_semantic(const char *semantic_name, enum wined3d_decl_usage usage) DECLSPEC_HIDDEN;
+#if defined(STAGING_CSMT)
 void shader_cleanup(struct wined3d_shader *shader) DECLSPEC_HIDDEN;
+#endif /* STAGING_CSMT */
 
 static inline BOOL shader_is_scalar(const struct wined3d_shader_register *reg)
 {
diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c
--- a/dlls/winex11.drv/opengl.c
+++ b/dlls/winex11.drv/opengl.c
@@ -1980,7 +1980,9 @@
     escape.code = X11DRV_FLUSH_GL_DRAWABLE;
     escape.gl_drawable = 0;
 
+#if defined(STAGING_CSMT)
     ERR("glFinish\n");
+#endif /* STAGING_CSMT */
     if ((gl = get_gl_drawable( WindowFromDC( ctx->hdc ), 0 )))
     {
         switch (gl->type)
@@ -2006,7 +2008,9 @@
     escape.code = X11DRV_FLUSH_GL_DRAWABLE;
     escape.gl_drawable = 0;
 
+#if defined(STAGING_CSMT)
     ERR("glFlush\n");
+#endif /* STAGING_CSMT */
     if ((gl = get_gl_drawable( WindowFromDC( ctx->hdc ), 0 )))
     {
         switch (gl->type)
