From 589330d01be6e2555b395b0914012248b1bff069 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20D=C3=B6singer?= <stefan@codeweavers.com>
Date: Fri, 27 Sep 2013 19:24:21 +0200
Subject: wined3d: Implement DISCARD resource maps with heap memory.

---
 dlls/wined3d/buffer.c          |  1 +
 dlls/wined3d/cs.c              |  6 ++++--
 dlls/wined3d/resource.c        | 40 +++++++++++++++++++++++++++++++++++-----
 dlls/wined3d/surface.c         |  3 +++
 dlls/wined3d/volume.c          |  2 ++
 dlls/wined3d/wined3d_private.h |  6 +++---
 6 files changed, 48 insertions(+), 10 deletions(-)

diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c
index 7187114..c9b2ae7b2 100644
--- a/dlls/wined3d/buffer.c
+++ b/dlls/wined3d/buffer.c
@@ -493,6 +493,7 @@ BYTE *buffer_get_sysmem(struct wined3d_buffer *This, struct wined3d_context *con
 
     if (!wined3d_resource_allocate_sysmem(&This->resource))
         ERR("Failed to allocate system memory.\n");
+    This->resource.heap_memory = This->resource.map_heap_memory;
 
     if (This->buffer_type_hint == GL_ELEMENT_ARRAY_BUFFER_ARB)
         context_invalidate_state(context, STATE_INDEXBUFFER);
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index d86aa59..9307246 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -371,6 +371,7 @@ struct wined3d_cs_resource_changed
     enum wined3d_cs_op opcode;
     struct wined3d_resource *resource;
     struct wined3d_gl_bo *swap_buffer;
+    void *swap_heap_memory;
 };
 
 struct wined3d_cs_skip
@@ -1817,13 +1818,13 @@ static UINT wined3d_cs_exec_resource_changed(struct wined3d_cs *cs, const void *
     const struct wined3d_cs_resource_changed *op = data;
     struct wined3d_resource *resource = op->resource;
 
-    wined3d_resource_changed(resource, op->swap_buffer);
+    wined3d_resource_changed(resource, op->swap_buffer, op->swap_heap_memory);
 
     return sizeof(*op);
 }
 
 void wined3d_cs_emit_resource_changed(struct wined3d_cs *cs, struct wined3d_resource *resource,
-        struct wined3d_gl_bo *swap_buffer)
+        struct wined3d_gl_bo *swap_buffer, void *swap_heap_memory)
 {
     struct wined3d_cs_resource_changed *op;
 
@@ -1831,6 +1832,7 @@ void wined3d_cs_emit_resource_changed(struct wined3d_cs *cs, struct wined3d_reso
     op->opcode = WINED3D_CS_OP_RESOURCE_CHANGED;
     op->resource = resource;
     op->swap_buffer = swap_buffer;
+    op->swap_heap_memory = swap_heap_memory;
 
     cs->ops->submit(cs, sizeof(*op));
 }
diff --git a/dlls/wined3d/resource.c b/dlls/wined3d/resource.c
index 69dd95a..b7aa587 100644
--- a/dlls/wined3d/resource.c
+++ b/dlls/wined3d/resource.c
@@ -119,6 +119,7 @@ HRESULT resource_init(struct wined3d_resource *resource, struct wined3d_device *
             ERR("Failed to allocate system memory.\n");
             return E_OUTOFMEMORY;
         }
+        resource->heap_memory = resource->map_heap_memory;
     }
     else
     {
@@ -172,6 +173,7 @@ void resource_cleanup(struct wined3d_resource *resource)
         wined3d_resource_free_bo(resource);
 
     wined3d_resource_free_sysmem(resource);
+    resource->map_heap_memory = NULL;
 
     device_resource_released(resource->device, resource);
 }
@@ -246,7 +248,7 @@ BOOL wined3d_resource_allocate_sysmem(struct wined3d_resource *resource)
     p = (void **)(((ULONG_PTR)mem + align) & ~(RESOURCE_ALIGNMENT - 1)) - 1;
     *p = mem;
 
-    resource->heap_memory = ++p;
+    resource->map_heap_memory = ++p;
 
     return TRUE;
 }
@@ -559,7 +561,7 @@ BYTE *wined3d_resource_get_map_ptr(const struct wined3d_resource *resource,
             return ptr;
 
         case WINED3D_LOCATION_SYSMEM:
-            return resource->heap_memory;
+            return resource->map_heap_memory;
 
         case WINED3D_LOCATION_DIB:
             return resource->bitmap_data;
@@ -621,6 +623,7 @@ BOOL wined3d_resource_prepare_system_memory(struct wined3d_resource *resource)
         ERR("Failed to allocate system memory.\n");
         return FALSE;
     }
+    resource->heap_memory = resource->map_heap_memory;
     return TRUE;
 }
 
@@ -705,6 +708,10 @@ void *wined3d_resource_map_internal(struct wined3d_resource *resource, DWORD fla
                         GL_STREAM_DRAW, GL_PIXEL_UNPACK_BUFFER, context);
                 break;
 
+            case WINED3D_LOCATION_SYSMEM:
+                wined3d_resource_allocate_sysmem(resource);
+                break;
+
             default:
                 if (resource->access_fence)
                     ERR("Location %s does not support DISCARD maps.\n",
@@ -773,7 +780,21 @@ HRESULT wined3d_resource_map(struct wined3d_resource *resource,
     if (flags & WINED3D_MAP_NOOVERWRITE)
         FIXME("WINED3D_MAP_NOOVERWRITE are not implemented yet.\n");
 
-    if (!(flags & WINED3D_MAP_DISCARD) || resource->map_binding != WINED3D_LOCATION_BUFFER)
+    if (flags & WINED3D_MAP_DISCARD)
+    {
+        switch (resource->map_binding)
+        {
+            case WINED3D_LOCATION_BUFFER:
+            case WINED3D_LOCATION_SYSMEM:
+                break;
+
+            default:
+                FIXME("Implement discard maps with %s map binding.\n",
+                        wined3d_debug_location(resource->map_binding));
+                wined3d_resource_sync(resource);
+        }
+    }
+    else
         wined3d_resource_sync(resource);
 
     base_memory = wined3d_cs_emit_resource_map(device->cs, resource, flags);
@@ -860,7 +881,10 @@ HRESULT wined3d_resource_unmap(struct wined3d_resource *resource)
     wined3d_cs_emit_resource_unmap(device->cs, resource);
 
     if (resource->unmap_dirtify)
-        wined3d_cs_emit_resource_changed(device->cs, resource, resource->map_buffer);
+    {
+        wined3d_cs_emit_resource_changed(device->cs, resource,
+                resource->map_buffer, resource->map_heap_memory);
+    }
     resource->unmap_dirtify = FALSE;
 
     resource->map_count--;
@@ -868,7 +892,8 @@ HRESULT wined3d_resource_unmap(struct wined3d_resource *resource)
     return WINED3D_OK;
 }
 
-void wined3d_resource_changed(struct wined3d_resource *resource, struct wined3d_gl_bo *swap_buffer)
+void wined3d_resource_changed(struct wined3d_resource *resource, struct wined3d_gl_bo *swap_buffer,
+        void *swap_heap_memory)
 {
     struct wined3d_device *device = resource->device;
 
@@ -879,6 +904,11 @@ void wined3d_resource_changed(struct wined3d_resource *resource, struct wined3d_
         context_release(context);
         resource->buffer = swap_buffer;
     }
+    if (swap_heap_memory && swap_heap_memory != resource->heap_memory)
+    {
+        wined3d_resource_free_sysmem(resource);
+        resource->heap_memory = swap_heap_memory;
+    }
 
     wined3d_resource_invalidate_location(resource, ~resource->map_binding);
 }
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 90fa582..f56bb6b 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -487,6 +487,7 @@ static void surface_evict_sysmem(struct wined3d_surface *surface)
         return;
 
     wined3d_resource_free_sysmem(&surface->resource);
+    surface->resource.map_heap_memory = NULL;
     wined3d_resource_invalidate_location(&surface->resource, WINED3D_LOCATION_SYSMEM);
 }
 
@@ -1997,6 +1998,7 @@ HRESULT wined3d_surface_update_desc(struct wined3d_surface *surface,
 
     surface->resource.locations = 0;
     wined3d_resource_free_sysmem(&surface->resource);
+    surface->resource.map_heap_memory = NULL;
 
     width = texture_resource->width;
     height = texture_resource->height;
@@ -5489,6 +5491,7 @@ static HRESULT surface_init(struct wined3d_surface *surface, struct wined3d_text
     if (surface->resource.map_binding == WINED3D_LOCATION_DIB)
     {
         wined3d_resource_free_sysmem(&surface->resource);
+        surface->resource.map_heap_memory = NULL;
         wined3d_resource_validate_location(&surface->resource, WINED3D_LOCATION_DIB);
         wined3d_resource_invalidate_location(&surface->resource, WINED3D_LOCATION_SYSMEM);
     }
diff --git a/dlls/wined3d/volume.c b/dlls/wined3d/volume.c
index 28985a4..d253a17 100644
--- a/dlls/wined3d/volume.c
+++ b/dlls/wined3d/volume.c
@@ -134,6 +134,7 @@ static void wined3d_volume_download_data(struct wined3d_volume *volume,
 static void wined3d_volume_evict_sysmem(struct wined3d_volume *volume)
 {
     wined3d_resource_free_sysmem(&volume->resource);
+    volume->resource.map_heap_memory = NULL;
     wined3d_resource_invalidate_location(&volume->resource, WINED3D_LOCATION_SYSMEM);
 }
 
@@ -516,6 +517,7 @@ static HRESULT volume_init(struct wined3d_volume *volume, struct wined3d_texture
     {
         wined3d_resource_free_sysmem(&volume->resource);
         volume->resource.map_binding = WINED3D_LOCATION_BUFFER;
+        volume->resource.map_heap_memory = NULL;
     }
 
     volume->container = container;
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index abf3ca2..ac4aeb3 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2137,7 +2137,7 @@ struct wined3d_resource
     UINT depth;
     UINT size;
     DWORD priority;
-    void *heap_memory, *user_memory, *bitmap_data;
+    void *heap_memory, *map_heap_memory, *user_memory, *bitmap_data;
     UINT custom_row_pitch, custom_slice_pitch;
     struct wined3d_gl_bo *buffer, *map_buffer;
     struct list resource_list_entry;
@@ -2171,7 +2171,7 @@ void resource_unload(struct wined3d_resource *resource) DECLSPEC_HIDDEN;
 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,
-        struct wined3d_gl_bo *swap_buffer) DECLSPEC_HIDDEN;
+        struct wined3d_gl_bo *swap_buffer, void *swap_heap_memory) DECLSPEC_HIDDEN;
 BOOL wined3d_resource_check_block_align(const struct wined3d_resource *resource,
         const struct wined3d_box *box) DECLSPEC_HIDDEN;
 void wined3d_resource_free_bo(struct wined3d_resource *resource) DECLSPEC_HIDDEN;
@@ -2695,7 +2695,7 @@ void wined3d_cs_emit_blt(struct wined3d_cs *cs, struct wined3d_surface *dst_surf
 void wined3d_cs_emit_clear_rtv(struct wined3d_cs *cs, struct wined3d_rendertarget_view *view,
         const RECT *rect, const struct wined3d_color *color) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_resource_changed(struct wined3d_cs *cs, struct wined3d_resource *resource,
-        struct wined3d_gl_bo *swap_buffer) DECLSPEC_HIDDEN;
+        struct wined3d_gl_bo *swap_buffer, void *swap_heap_memory) DECLSPEC_HIDDEN;
 void *wined3d_cs_emit_resource_map(struct wined3d_cs *cs, struct wined3d_resource *resource,
         DWORD flags) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_resource_unmap(struct wined3d_cs *cs, struct wined3d_resource *resource) DECLSPEC_HIDDEN;
-- 
2.2.1

