[PATCH 2/6] ddraw: Create a separate texture for drawing with bindable sysmem surfaces.

Paul Gofman pgofman at codeweavers.com
Thu Feb 25 16:22:57 CST 2021


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 dlls/ddraw/ddraw_private.h |  55 ++++++++++++
 dlls/ddraw/device.c        |  18 ++--
 dlls/ddraw/surface.c       | 167 +++++++++++++++++++++++++++++++------
 dlls/ddraw/tests/ddraw1.c  |   1 -
 dlls/ddraw/tests/ddraw2.c  |   1 -
 dlls/ddraw/tests/ddraw4.c  |   1 -
 dlls/ddraw/tests/ddraw7.c  |   7 +-
 7 files changed, 207 insertions(+), 43 deletions(-)

diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h
index f01468ce614..5e5856b5916 100644
--- a/dlls/ddraw/ddraw_private.h
+++ b/dlls/ddraw/ddraw_private.h
@@ -155,6 +155,9 @@ void DDRAW_Convert_DDSCAPS_1_To_2(const DDSCAPS *pIn, DDSCAPS2 *pOut) DECLSPEC_H
 void DDRAW_Convert_DDDEVICEIDENTIFIER_2_To_1(const DDDEVICEIDENTIFIER2 *pIn, DDDEVICEIDENTIFIER *pOut) DECLSPEC_HIDDEN;
 struct wined3d_vertex_declaration *ddraw_find_decl(struct ddraw *ddraw, DWORD fvf) DECLSPEC_HIDDEN;
 
+#define DDRAW_SURFACE_LOCATION_DEFAULT 0x00000001
+#define DDRAW_SURFACE_LOCATION_DRAW    0x00000002
+
 struct ddraw_surface
 {
     /* IUnknown fields */
@@ -175,7 +178,9 @@ struct ddraw_surface
 
     /* Connections to other Objects */
     struct ddraw *ddraw;
+    unsigned int texture_location;
     struct wined3d_texture *wined3d_texture;
+    struct wined3d_texture *draw_texture;
     unsigned int sub_resource_idx;
     struct wined3d_rendertarget_view *wined3d_rtv;
     struct wined3d_private_store private_store;
@@ -659,6 +664,56 @@ static inline BOOL ddraw_surface_can_be_lost(const struct ddraw_surface *surface
     return surface->sysmem_fallback;
 }
 
+#define DDRAW_SURFACE_READ   0x00000001
+#define DDRAW_SURFACE_WRITE  0x00000002
+#define DDRAW_SURFACE_RW (DDRAW_SURFACE_READ | DDRAW_SURFACE_WRITE)
+
+static inline struct wined3d_texture *ddraw_surface_get_default_texture(struct ddraw_surface *surface, unsigned int flags)
+{
+    if (surface->draw_texture)
+    {
+        if (flags & DDRAW_SURFACE_READ && !(surface->texture_location & DDRAW_SURFACE_LOCATION_DEFAULT))
+        {
+            wined3d_device_copy_sub_resource_region(surface->ddraw->wined3d_device,
+                    wined3d_texture_get_resource(surface->wined3d_texture), surface->sub_resource_idx, 0, 0, 0,
+                    wined3d_texture_get_resource(surface->draw_texture), surface->sub_resource_idx, NULL, 0);
+            surface->texture_location |= DDRAW_SURFACE_LOCATION_DEFAULT;
+        }
+
+        if (flags & DDRAW_SURFACE_WRITE)
+            surface->texture_location = DDRAW_SURFACE_LOCATION_DEFAULT;
+    }
+    return surface->wined3d_texture;
+}
+
+static inline struct wined3d_texture *ddraw_surface_get_draw_texture(struct ddraw_surface *surface, unsigned int flags)
+{
+    if (!surface->draw_texture)
+        return surface->wined3d_texture;
+
+    if (flags & DDRAW_SURFACE_READ && !(surface->texture_location & DDRAW_SURFACE_LOCATION_DRAW))
+    {
+        wined3d_device_copy_sub_resource_region(surface->ddraw->wined3d_device,
+                wined3d_texture_get_resource(surface->draw_texture), surface->sub_resource_idx, 0, 0, 0,
+                wined3d_texture_get_resource(surface->wined3d_texture), surface->sub_resource_idx, NULL, 0);
+        surface->texture_location |= DDRAW_SURFACE_LOCATION_DRAW;
+    }
+
+    if (flags & DDRAW_SURFACE_WRITE)
+        surface->texture_location = DDRAW_SURFACE_LOCATION_DRAW;
+
+    return surface->draw_texture;
+}
+
+static inline struct wined3d_texture *ddraw_surface_get_any_texture(struct ddraw_surface *surface, unsigned int flags)
+{
+    if (surface->texture_location & DDRAW_SURFACE_LOCATION_DEFAULT)
+        return ddraw_surface_get_default_texture(surface, flags);
+
+    assert(surface->texture_location & DDRAW_SURFACE_LOCATION_DRAW);
+    return ddraw_surface_get_draw_texture(surface, flags);
+}
+
 /* Used for generic dumping */
 struct flag_info
 {
diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c
index f91404c89f6..4fe75d36545 100644
--- a/dlls/ddraw/device.c
+++ b/dlls/ddraw/device.c
@@ -1908,7 +1908,7 @@ static HRESULT d3d_device7_SetRenderTarget(IDirect3DDevice7 *iface,
         return DDERR_INVALIDCAPS;
     }
 
-    if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
+    if (device->hardware_device && !(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
     {
         WARN("Surface %p is not in video memory.\n", target_impl);
         wined3d_mutex_unlock();
@@ -1984,7 +1984,7 @@ static HRESULT WINAPI d3d_device3_SetRenderTarget(IDirect3DDevice3 *iface,
         return DDERR_INVALIDPIXELFORMAT;
     }
 
-    if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
+    if (device->hardware_device && !(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
     {
         WARN("Surface %p is not in video memory.\n", target_impl);
         IDirectDrawSurface4_AddRef(target);
@@ -2033,7 +2033,7 @@ static HRESULT WINAPI d3d_device2_SetRenderTarget(IDirect3DDevice2 *iface,
         return DDERR_INVALIDPIXELFORMAT;
     }
 
-    if (!(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
+    if (device->hardware_device && !(target_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
     {
         WARN("Surface %p is not in video memory.\n", target_impl);
         IDirectDrawSurface_AddRef(target);
@@ -6961,6 +6961,12 @@ static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw, c
     device->hardware_device = IsEqualGUID(&IID_IDirect3DTnLHalDevice, guid)
             || IsEqualGUID(&IID_IDirect3DHALDevice, guid);
 
+    if (device->hardware_device && !(target->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
+    {
+        WARN("Surface %p is not in video memory.\n", target);
+        return D3DERR_SURFACENOTINVIDMEM;
+    }
+
     if (outer_unknown)
         device->outer_unknown = outer_unknown;
     else
@@ -7048,12 +7054,6 @@ HRESULT d3d_device_create(struct ddraw *ddraw, const GUID *guid, struct ddraw_su
         return DDERR_OUTOFMEMORY;
     }
 
-    if (!(target->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
-    {
-        WARN("Surface %p is not in video memory.\n", target);
-        return D3DERR_SURFACENOTINVIDMEM;
-    }
-
     if (ddraw->d3ddevice)
     {
         FIXME("Only one Direct3D device per DirectDraw object supported.\n");
diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c
index b910fb6817e..1e1a1a721c5 100644
--- a/dlls/ddraw/surface.c
+++ b/dlls/ddraw/surface.c
@@ -56,8 +56,8 @@ static BOOL ddraw_gdi_is_front(struct ddraw *ddraw)
 HRESULT ddraw_surface_update_frontbuffer(struct ddraw_surface *surface,
         const RECT *rect, BOOL read, unsigned int swap_interval)
 {
+    struct wined3d_texture *dst_texture, *src_texture;
     struct ddraw *ddraw = surface->ddraw;
-    struct wined3d_texture *dst_texture;
     HDC surface_dc, screen_dc;
     int x, y, w, h;
     HRESULT hr;
@@ -112,8 +112,9 @@ HRESULT ddraw_surface_update_frontbuffer(struct ddraw_surface *surface,
         else
             dst_texture = ddraw->wined3d_frontbuffer;
 
-        if (SUCCEEDED(hr = wined3d_texture_blt(dst_texture, 0, rect, surface->wined3d_texture,
-                surface->sub_resource_idx, rect, 0, NULL, WINED3D_TEXF_POINT)) && swap_interval)
+        if (SUCCEEDED(hr = wined3d_texture_blt(dst_texture, 0, rect,
+                ddraw_surface_get_any_texture(surface, DDRAW_SURFACE_READ), surface->sub_resource_idx, rect, 0,
+                NULL, WINED3D_TEXF_POINT)) && swap_interval)
         {
             hr = wined3d_swapchain_present(ddraw->wined3d_swapchain, rect, rect, NULL, swap_interval, 0);
             ddraw->flags |= DDRAW_SWAPPED;
@@ -121,7 +122,9 @@ HRESULT ddraw_surface_update_frontbuffer(struct ddraw_surface *surface,
         return hr;
     }
 
-    if (FAILED(hr = wined3d_texture_get_dc(surface->wined3d_texture, surface->sub_resource_idx, &surface_dc)))
+    src_texture = ddraw_surface_get_default_texture(surface, DDRAW_SURFACE_READ);
+
+    if (FAILED(hr = wined3d_texture_get_dc(src_texture, surface->sub_resource_idx, &surface_dc)))
     {
         ERR("Failed to get surface DC, hr %#x.\n", hr);
         return hr;
@@ -131,7 +134,7 @@ HRESULT ddraw_surface_update_frontbuffer(struct ddraw_surface *surface,
 
     if (!(screen_dc = GetDC(NULL)))
     {
-        wined3d_texture_release_dc(surface->wined3d_texture, surface->sub_resource_idx, surface_dc);
+        wined3d_texture_release_dc(src_texture, surface->sub_resource_idx, surface_dc);
         ERR("Failed to get screen DC.\n");
         return E_FAIL;
     }
@@ -144,7 +147,7 @@ HRESULT ddraw_surface_update_frontbuffer(struct ddraw_surface *surface,
                 surface_dc, x, y, SRCCOPY);
 
     ReleaseDC(NULL, screen_dc);
-    wined3d_texture_release_dc(surface->wined3d_texture, surface->sub_resource_idx, surface_dc);
+    wined3d_texture_release_dc(src_texture, surface->sub_resource_idx, surface_dc);
 
     if (!ret)
     {
@@ -1057,9 +1060,9 @@ static HRESULT surface_lock(struct ddraw_surface *surface,
     if (surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
         hr = ddraw_surface_update_frontbuffer(surface, rect, TRUE, 0);
     if (SUCCEEDED(hr))
-        hr = wined3d_resource_map(wined3d_texture_get_resource(surface->wined3d_texture),
-                surface->sub_resource_idx, &map_desc, rect ? &box : NULL,
-                wined3dmapflags_from_ddrawmapflags(flags));
+        hr = wined3d_resource_map(wined3d_texture_get_resource
+                (ddraw_surface_get_default_texture(surface, DDRAW_SURFACE_RW)), surface->sub_resource_idx,
+                &map_desc, rect ? &box : NULL, wined3dmapflags_from_ddrawmapflags(flags));
     if (FAILED(hr))
     {
         wined3d_mutex_unlock();
@@ -1235,7 +1238,8 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH ddraw_surface1_Unlock(IDirectDrawSurface
     TRACE("iface %p, data %p.\n", iface, data);
 
     wined3d_mutex_lock();
-    hr = wined3d_resource_unmap(wined3d_texture_get_resource(surface->wined3d_texture), surface->sub_resource_idx);
+    hr = wined3d_resource_unmap(wined3d_texture_get_resource
+            (ddraw_surface_get_default_texture(surface, 0)), surface->sub_resource_idx);
     if (SUCCEEDED(hr) && surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
         hr = ddraw_surface_update_frontbuffer(surface, &surface->ddraw->primary_lock, FALSE, 0);
     wined3d_mutex_unlock();
@@ -1307,7 +1311,7 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH ddraw_surface1_Flip(IDirectDrawSurface *
     struct ddraw_texture *dst_ddraw_texture, *src_ddraw_texture;
     struct wined3d_rendertarget_view *tmp_rtv, *src_rtv, *rtv;
     DDSCAPS caps = {DDSCAPS_FLIP};
-    struct wined3d_texture *texture;
+    struct wined3d_texture *texture, *draw_texture;
     IDirectDrawSurface *current;
     void *texture_memory;
     HRESULT hr;
@@ -1337,6 +1341,7 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH ddraw_surface1_Flip(IDirectDrawSurface *
     rtv = wined3d_device_get_rendertarget_view(dst_impl->ddraw->wined3d_device, 0);
     dst_ddraw_texture = wined3d_texture_get_parent(dst_impl->wined3d_texture);
     texture_memory = dst_ddraw_texture->texture_memory;
+    draw_texture = dst_impl->draw_texture;
 
     if (src_impl)
     {
@@ -1363,13 +1368,18 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH ddraw_surface1_Flip(IDirectDrawSurface *
         wined3d_rendertarget_view_set_parent(src_rtv, dst_impl);
         dst_impl->wined3d_rtv = src_rtv;
         wined3d_texture_set_sub_resource_parent(src_impl->wined3d_texture, 0, dst_impl);
+        if (src_impl->draw_texture)
+            wined3d_texture_set_sub_resource_parent(src_impl->draw_texture, 0, dst_impl);
         src_ddraw_texture = wined3d_texture_get_parent(src_impl->wined3d_texture);
         dst_ddraw_texture->texture_memory = src_ddraw_texture->texture_memory;
         wined3d_resource_set_parent(wined3d_texture_get_resource(src_impl->wined3d_texture), dst_ddraw_texture);
+        if (src_impl->draw_texture)
+            wined3d_resource_set_parent(wined3d_texture_get_resource(src_impl->draw_texture), dst_ddraw_texture);
         dst_ddraw_texture = src_ddraw_texture;
         if (src_impl->sub_resource_idx)
             ERR("Invalid sub-resource index %u on surface %p.\n", src_impl->sub_resource_idx, src_impl);
         dst_impl->wined3d_texture = src_impl->wined3d_texture;
+        dst_impl->draw_texture = src_impl->draw_texture;
     }
     else
     {
@@ -1395,13 +1405,18 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH ddraw_surface1_Flip(IDirectDrawSurface *
             wined3d_rendertarget_view_set_parent(src_rtv, dst_impl);
             dst_impl->wined3d_rtv = src_rtv;
             wined3d_texture_set_sub_resource_parent(src_impl->wined3d_texture, 0, dst_impl);
+            if (src_impl->draw_texture)
+                wined3d_texture_set_sub_resource_parent(src_impl->draw_texture, 0, dst_impl);
             src_ddraw_texture = wined3d_texture_get_parent(src_impl->wined3d_texture);
             dst_ddraw_texture->texture_memory = src_ddraw_texture->texture_memory;
             wined3d_resource_set_parent(wined3d_texture_get_resource(src_impl->wined3d_texture), dst_ddraw_texture);
+            if (src_impl->draw_texture)
+                wined3d_resource_set_parent(wined3d_texture_get_resource(src_impl->draw_texture), dst_ddraw_texture);
             dst_ddraw_texture = src_ddraw_texture;
             if (src_impl->sub_resource_idx)
                 ERR("Invalid sub-resource index %u on surface %p.\n", src_impl->sub_resource_idx, src_impl);
             dst_impl->wined3d_texture = src_impl->wined3d_texture;
+            dst_impl->draw_texture = src_impl->draw_texture;
             dst_impl = src_impl;
         }
     }
@@ -1413,9 +1428,14 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH ddraw_surface1_Flip(IDirectDrawSurface *
     wined3d_rendertarget_view_set_parent(tmp_rtv, src_impl);
     src_impl->wined3d_rtv = tmp_rtv;
     wined3d_texture_set_sub_resource_parent(texture, 0, src_impl);
+    if (draw_texture)
+        wined3d_texture_set_sub_resource_parent(draw_texture, 0, src_impl);
     dst_ddraw_texture->texture_memory = texture_memory;
     wined3d_resource_set_parent(wined3d_texture_get_resource(texture), dst_ddraw_texture);
+    if (draw_texture)
+        wined3d_resource_set_parent(wined3d_texture_get_resource(draw_texture), dst_ddraw_texture);
     src_impl->wined3d_texture = texture;
+    src_impl->draw_texture = draw_texture;
 
     if (flags & ~(DDFLIP_NOVSYNC | DDFLIP_INTERVAL2 | DDFLIP_INTERVAL3 | DDFLIP_INTERVAL4))
     {
@@ -1503,6 +1523,7 @@ static HRESULT ddraw_surface_blt(struct ddraw_surface *dst_surface, const RECT *
             return DDERR_INVALIDPARAMS;
 
         wined3d_device_apply_stateblock(wined3d_device, dst_surface->ddraw->state);
+        ddraw_surface_get_draw_texture(dst_surface, dst_rect ? DDRAW_SURFACE_RW : DDRAW_SURFACE_WRITE);
         return wined3d_device_clear_rendertarget_view(wined3d_device,
                 ddraw_surface_get_rendertarget_view(dst_surface),
                 dst_rect, wined3d_flags, &colour, 0.0f, 0);
@@ -1519,6 +1540,7 @@ static HRESULT ddraw_surface_blt(struct ddraw_surface *dst_surface, const RECT *
             return DDERR_INVALIDPARAMS;
 
         wined3d_device_apply_stateblock(wined3d_device, dst_surface->ddraw->state);
+        ddraw_surface_get_draw_texture(dst_surface, dst_rect ? DDRAW_SURFACE_RW : DDRAW_SURFACE_WRITE);
         return wined3d_device_clear_rendertarget_view(wined3d_device,
                 ddraw_surface_get_rendertarget_view(dst_surface),
                 dst_rect, wined3d_flags, NULL, colour.r, 0);
@@ -1534,8 +1556,9 @@ static HRESULT ddraw_surface_blt(struct ddraw_surface *dst_surface, const RECT *
     if (!(flags & DDBLT_ASYNC))
         wined3d_flags |= WINED3D_BLT_SYNCHRONOUS;
 
-    return wined3d_texture_blt(dst_surface->wined3d_texture, dst_surface->sub_resource_idx, dst_rect,
-            src_surface->wined3d_texture, src_surface->sub_resource_idx, src_rect, wined3d_flags, fx, filter);
+    return wined3d_texture_blt(ddraw_surface_get_any_texture(dst_surface, DDRAW_SURFACE_RW),
+            dst_surface->sub_resource_idx, dst_rect, ddraw_surface_get_any_texture(src_surface, DDRAW_SURFACE_READ),
+            src_surface->sub_resource_idx, src_rect, wined3d_flags, fx, filter);
 }
 
 static HRESULT ddraw_surface_blt_clipped(struct ddraw_surface *dst_surface, const RECT *dst_rect_in,
@@ -2305,7 +2328,7 @@ static HRESULT WINAPI ddraw_surface7_GetDC(IDirectDrawSurface7 *iface, HDC *dc)
     else if (surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
         hr = ddraw_surface_update_frontbuffer(surface, NULL, TRUE, 0);
     if (SUCCEEDED(hr))
-        hr = wined3d_texture_get_dc(surface->wined3d_texture, surface->sub_resource_idx, dc);
+        hr = wined3d_texture_get_dc(ddraw_surface_get_default_texture(surface, DDRAW_SURFACE_RW), surface->sub_resource_idx, dc);
 
     if (SUCCEEDED(hr))
     {
@@ -2401,7 +2424,8 @@ static HRESULT WINAPI ddraw_surface7_ReleaseDC(IDirectDrawSurface7 *iface, HDC h
     {
         hr = DDERR_NODC;
     }
-    else if (SUCCEEDED(hr = wined3d_texture_release_dc(surface->wined3d_texture, surface->sub_resource_idx, hdc)))
+    else if (SUCCEEDED(hr = wined3d_texture_release_dc(ddraw_surface_get_default_texture(surface, 0),
+            surface->sub_resource_idx, hdc)))
     {
         surface->dc = NULL;
         if (surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
@@ -2551,6 +2575,9 @@ static HRESULT WINAPI ddraw_surface7_SetPriority(IDirectDrawSurface7 *iface, DWO
     {
         resource = wined3d_texture_get_resource(surface->wined3d_texture);
         wined3d_resource_set_priority(resource, priority);
+        if (surface->draw_texture)
+            wined3d_resource_set_priority(wined3d_texture_get_resource(surface->draw_texture), priority);
+
         hr = DD_OK;
     }
     wined3d_mutex_unlock();
@@ -4267,6 +4294,8 @@ static HRESULT WINAPI ddraw_surface7_SetLOD(IDirectDrawSurface7 *iface, DWORD Ma
     }
 
     hr = wined3d_texture_set_lod(surface->wined3d_texture, MaxLOD);
+    if (SUCCEEDED(hr) && surface->draw_texture)
+        hr = wined3d_texture_set_lod(surface->draw_texture, MaxLOD);
     wined3d_mutex_unlock();
 
     return hr;
@@ -4376,8 +4405,9 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH ddraw_surface7_BltFast(IDirectDrawSurfac
     if (src_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
         hr = ddraw_surface_update_frontbuffer(src_impl, src_rect, TRUE, 0);
     if (SUCCEEDED(hr))
-        hr = wined3d_texture_blt(dst_impl->wined3d_texture, dst_impl->sub_resource_idx, &dst_rect,
-                src_impl->wined3d_texture, src_impl->sub_resource_idx, src_rect, flags, NULL, WINED3D_TEXF_POINT);
+        hr = wined3d_texture_blt(ddraw_surface_get_any_texture(dst_impl, DDRAW_SURFACE_RW),
+                dst_impl->sub_resource_idx, &dst_rect, ddraw_surface_get_any_texture(src_impl,DDRAW_SURFACE_READ),
+                src_impl->sub_resource_idx, src_rect, flags, NULL, WINED3D_TEXF_POINT);
     if (SUCCEEDED(hr) && (dst_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE))
         hr = ddraw_surface_update_frontbuffer(dst_impl, &dst_rect, FALSE, 0);
     wined3d_mutex_unlock();
@@ -4736,6 +4766,14 @@ static HRESULT WINAPI ddraw_surface7_SetSurfaceDesc(IDirectDrawSurface7 *iface,
         return hr_ddraw_from_wined3d(hr);
     }
 
+    if (surface->draw_texture && FAILED(hr = wined3d_texture_update_desc(surface->draw_texture,
+            surface->sub_resource_idx, width, height, format_id, WINED3D_MULTISAMPLE_NONE, 0, NULL, 0)))
+    {
+        ERR("Failed to update surface desc for draw_texture, hr %#x.\n", hr);
+        wined3d_mutex_unlock();
+        return hr_ddraw_from_wined3d(hr);
+    }
+
     if (DDSD->dwFlags & DDSD_WIDTH)
         surface->surface_desc.dwWidth = width;
     if (DDSD->dwFlags & DDSD_PITCH)
@@ -4842,6 +4880,18 @@ static HRESULT WINAPI ddraw_surface1_GetPalette(IDirectDrawSurface *iface, IDire
     return ddraw_surface7_GetPalette(&surface->IDirectDrawSurface7_iface, palette);
 }
 
+static HRESULT ddraw_surface_set_wined3d_textures_colour_key(struct ddraw_surface *surface, DWORD flags,
+        struct wined3d_color_key *color_key)
+{
+    HRESULT hr;
+
+    hr = wined3d_texture_set_color_key(surface->wined3d_texture, flags, color_key);
+    if (surface->draw_texture && SUCCEEDED(hr))
+        hr = wined3d_texture_set_color_key(surface->draw_texture, flags, color_key);
+
+    return hr;
+}
+
 static HRESULT ddraw_surface_set_color_key(struct ddraw_surface *surface, DWORD flags, DDCOLORKEY *color_key)
 {
     DDCOLORKEY fixed_color_key;
@@ -4916,7 +4966,7 @@ static HRESULT ddraw_surface_set_color_key(struct ddraw_surface *surface, DWORD
     }
 
     if (surface->is_complex_root)
-        hr = wined3d_texture_set_color_key(surface->wined3d_texture, flags,
+        hr = ddraw_surface_set_wined3d_textures_colour_key(surface, flags,
                 color_key ? (struct wined3d_color_key *)&fixed_color_key : NULL);
 
     wined3d_mutex_unlock();
@@ -5293,8 +5343,8 @@ static HRESULT WINAPI d3d_texture2_Load(IDirect3DTexture2 *iface, IDirect3DTextu
 
     wined3d_mutex_lock();
 
-    dst_resource = wined3d_texture_get_resource(dst_surface->wined3d_texture);
-    src_resource = wined3d_texture_get_resource(src_surface->wined3d_texture);
+    dst_resource = wined3d_texture_get_resource(ddraw_surface_get_default_texture(dst_surface, DDRAW_SURFACE_WRITE));
+    src_resource = wined3d_texture_get_resource(ddraw_surface_get_default_texture(src_surface, DDRAW_SURFACE_READ));
 
     if (((src_surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
             != (dst_surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP))
@@ -5832,6 +5882,9 @@ static void STDMETHODCALLTYPE ddraw_surface_wined3d_object_destroyed(void *paren
 
     wined3d_private_store_cleanup(&surface->private_store);
 
+    if (surface->draw_texture)
+        wined3d_texture_decref(surface->draw_texture);
+
     heap_free(surface);
 }
 
@@ -5902,6 +5955,65 @@ static HRESULT ddraw_surface_reserve_memory(struct wined3d_texture *wined3d_text
     return hr;
 }
 
+static void ddraw_surface_create_draw_texture(struct ddraw_surface *surface)
+{
+    DDSURFACEDESC2 *desc = &surface->surface_desc;
+    struct wined3d_resource *draw_texture_resource;
+    struct wined3d_resource_desc wined3d_desc;
+    unsigned int i, layer_count, level_count;
+    struct wined3d_texture *draw_texture;
+    struct ddraw_surface *parent;
+    unsigned int bind_flags;
+    HRESULT hr;
+
+    if (!(desc->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
+        return;
+
+    bind_flags = 0;
+    if ((desc->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
+            || (desc->ddsCaps.dwCaps & DDSCAPS_TEXTURE))
+        bind_flags |= WINED3D_BIND_SHADER_RESOURCE;
+
+    if (desc->ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
+        bind_flags |= WINED3D_BIND_DEPTH_STENCIL;
+    else if (desc->ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
+        bind_flags |= WINED3D_BIND_RENDER_TARGET;
+
+    if (!bind_flags)
+        return;
+
+    layer_count = surface->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP ? 6 : 1;
+    level_count = wined3d_texture_get_level_count(surface->wined3d_texture);
+
+    draw_texture_resource = wined3d_texture_get_resource(surface->wined3d_texture);
+    wined3d_resource_get_desc(draw_texture_resource, &wined3d_desc);
+
+    wined3d_desc.bind_flags = bind_flags;
+    wined3d_desc.access = WINED3D_RESOURCE_ACCESS_GPU;
+
+    if (FAILED(hr = wined3d_texture_create(surface->ddraw->wined3d_device, &wined3d_desc, layer_count,
+            level_count, 0, NULL, NULL,
+            &ddraw_null_wined3d_parent_ops, &draw_texture)))
+    {
+        WARN("Failed to create wined3d texture, hr %#x.\n", hr);
+        return;
+    }
+
+    wined3d_resource_set_parent(draw_texture_resource, wined3d_texture_get_parent(surface->wined3d_texture));
+
+    i = 0;
+    while ((parent = wined3d_texture_get_sub_resource_parent(surface->wined3d_texture, i)))
+    {
+        wined3d_texture_set_sub_resource_parent(draw_texture, i, parent);
+        wined3d_texture_incref(parent->draw_texture = draw_texture);
+        ++i;
+    }
+    assert(surface->draw_texture);
+
+    wined3d_texture_decref(draw_texture);
+    TRACE("Surface %p, created draw_texture %p.\n", surface, draw_texture);
+}
+
 HRESULT ddraw_surface_create(struct ddraw *ddraw, const DDSURFACEDESC2 *surface_desc,
         struct ddraw_surface **surface, IUnknown *outer_unknown, unsigned int version)
 {
@@ -6416,22 +6528,24 @@ HRESULT ddraw_surface_create(struct ddraw *ddraw, const DDSURFACEDESC2 *surface_
 
     root = wined3d_texture_get_sub_resource_parent(wined3d_texture, 0);
     wined3d_texture_decref(wined3d_texture);
+    ddraw_surface_create_draw_texture(root);
+
     root->is_complex_root = TRUE;
     root->sysmem_fallback = sysmem_fallback;
     texture->root = root;
     wined3d_device_incref(texture->wined3d_device = ddraw->wined3d_device);
 
     if (desc->dwFlags & DDSD_CKDESTOVERLAY)
-        wined3d_texture_set_color_key(wined3d_texture, DDCKEY_DESTOVERLAY,
+        ddraw_surface_set_wined3d_textures_colour_key(root, DDCKEY_DESTOVERLAY,
                 (struct wined3d_color_key *)&desc->u3.ddckCKDestOverlay);
     if (desc->dwFlags & DDSD_CKDESTBLT)
-        wined3d_texture_set_color_key(wined3d_texture, DDCKEY_DESTBLT,
+        ddraw_surface_set_wined3d_textures_colour_key(root, DDCKEY_DESTBLT,
                 (struct wined3d_color_key *)&desc->ddckCKDestBlt);
     if (desc->dwFlags & DDSD_CKSRCOVERLAY)
-        wined3d_texture_set_color_key(wined3d_texture, DDCKEY_SRCOVERLAY,
+        ddraw_surface_set_wined3d_textures_colour_key(root, DDCKEY_SRCOVERLAY,
                 (struct wined3d_color_key *)&desc->ddckCKSrcOverlay);
     if (desc->dwFlags & DDSD_CKSRCBLT)
-        wined3d_texture_set_color_key(wined3d_texture, DDCKEY_SRCBLT,
+        ddraw_surface_set_wined3d_textures_colour_key(root, DDCKEY_SRCBLT,
                 (struct wined3d_color_key *)&desc->ddckCKSrcBlt);
 
     for (i = 0; i < layers; ++i)
@@ -6573,7 +6687,7 @@ HRESULT ddraw_surface_create(struct ddraw *ddraw, const DDSURFACEDESC2 *surface_
                 hr = hr_ddraw_from_wined3d(hr);
                 goto fail;
             }
-
+            ddraw_surface_create_draw_texture(last);
             *attach = last;
             attach = &last->complex_array[0];
         }
@@ -6663,6 +6777,7 @@ void ddraw_surface_init(struct ddraw_surface *surface, struct ddraw *ddraw,
     wined3d_texture_incref(surface->wined3d_texture = wined3d_texture);
     surface->sub_resource_idx = sub_resource_idx;
     *parent_ops = &ddraw_surface_wined3d_parent_ops;
+    surface->texture_location = DDRAW_SURFACE_LOCATION_DEFAULT;
 
     wined3d_private_store_init(&surface->private_store);
 }
@@ -6695,7 +6810,7 @@ struct wined3d_rendertarget_view *ddraw_surface_get_rendertarget_view(struct ddr
     if (surface->wined3d_rtv)
         return surface->wined3d_rtv;
 
-    if (FAILED(hr = wined3d_rendertarget_view_create_from_sub_resource(surface->wined3d_texture,
+    if (FAILED(hr = wined3d_rendertarget_view_create_from_sub_resource(ddraw_surface_get_draw_texture(surface, 0),
             surface->sub_resource_idx, surface, &ddraw_view_wined3d_parent_ops, &surface->wined3d_rtv)))
     {
         ERR("Failed to create rendertarget view, hr %#x.\n", hr);
diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c
index 54eec89cedd..ded1d32d154 100644
--- a/dlls/ddraw/tests/ddraw1.c
+++ b/dlls/ddraw/tests/ddraw1.c
@@ -4580,7 +4580,6 @@ static void test_rt_caps(const GUID *device_guid)
         }
 
         hr = IDirectDrawSurface_QueryInterface(surface, device_guid, (void **)&device);
-        todo_wine_if(software_device && test_data[i].create_device_hr == D3DERR_SURFACENOTINVIDMEM)
         ok((!software_device && hr == test_data[i].create_device_hr)
                 || (software_device && (hr == (test_data[i].create_device_hr == D3DERR_SURFACENOTINVIDMEM
                 ? DD_OK : test_data[i].create_device_hr))),
diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c
index d2889aa05d7..b882589f2ad 100644
--- a/dlls/ddraw/tests/ddraw2.c
+++ b/dlls/ddraw/tests/ddraw2.c
@@ -5053,7 +5053,6 @@ static void test_rt_caps(const GUID *device_guid)
 
         hr = IDirect3D2_CreateDevice(d3d, device_guid, surface, &device);
 
-        todo_wine_if(software_device && test_data[i].create_device_hr == D3DERR_SURFACENOTINVIDMEM)
         ok((!software_device && hr == test_data[i].create_device_hr)
                 || (software_device && (hr == (test_data[i].create_device_hr == D3DERR_SURFACENOTINVIDMEM
                 ? DD_OK : test_data[i].create_device_hr))),
diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c
index 6e003fbfb7e..42936fd7c74 100644
--- a/dlls/ddraw/tests/ddraw4.c
+++ b/dlls/ddraw/tests/ddraw4.c
@@ -6706,7 +6706,6 @@ static void test_rt_caps(const GUID *device_guid)
 
         hr = IDirect3D3_CreateDevice(d3d, device_guid, surface, &device, NULL);
 
-        todo_wine_if(software_device && test_data[i].create_device_hr == D3DERR_SURFACENOTINVIDMEM)
         ok((!software_device && hr == test_data[i].create_device_hr)
                 || (software_device && (hr == (test_data[i].create_device_hr == D3DERR_SURFACENOTINVIDMEM
                 ? DD_OK : test_data[i].create_device_hr))),
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c
index 8d3860021e3..f1e7a99d778 100644
--- a/dlls/ddraw/tests/ddraw7.c
+++ b/dlls/ddraw/tests/ddraw7.c
@@ -6419,10 +6419,8 @@ static void test_rt_caps(const GUID *device_guid)
             expected_caps = test_data[i].caps_out[software_device]
                     ? test_data[i].caps_out[software_device] : test_data[i].caps_out[0];
 
-            todo_wine_if(test_data[i].caps_out[software_device]
-                    && surface_desc.ddsCaps.dwCaps == test_data[i].caps_out[0])
             ok(surface_desc.ddsCaps.dwCaps == expected_caps
-                    || broken(surface_desc.ddsCaps.dwCaps == test_data[i].caps_out[0]),
+                    || surface_desc.ddsCaps.dwCaps == test_data[i].caps_out[0],
                     "Got unexpected caps %#x, test %u, software_device %u.\n",
                     surface_desc.ddsCaps.dwCaps, i, software_device);
         }
@@ -6437,7 +6435,6 @@ static void test_rt_caps(const GUID *device_guid)
                 surface_desc.ddsCaps.dwCaps2, test_data[i].caps2_out, i, software_device);
 
         hr = IDirect3D7_CreateDevice(d3d, device_guid, surface, &device);
-        todo_wine_if(software_device && test_data[i].create_device_hr == D3DERR_SURFACENOTINVIDMEM)
         ok((!software_device && hr == test_data[i].create_device_hr)
                 || (software_device && (hr == (test_data[i].create_device_hr == D3DERR_SURFACENOTINVIDMEM
                 ? DD_OK : test_data[i].create_device_hr))),
@@ -6492,7 +6489,7 @@ static void test_rt_caps(const GUID *device_guid)
 
         hr = IDirect3DDevice7_SetRenderTarget(device, rt, 0);
         ok(hr == test_data[i].set_rt_hr || (software_device && hr == DDERR_NOPALETTEATTACHED)
-                || broken(hr == test_data[i].alternative_set_rt_hr),
+                || hr == test_data[i].alternative_set_rt_hr,
                 "Got unexpected hr %#x, test %u, software_device %u.\n",
                 hr, i, software_device);
         if (SUCCEEDED(hr) || hr == DDERR_INVALIDPIXELFORMAT)
-- 
2.29.2




More information about the wine-devel mailing list