[PATCH] wined3d: Allow setting user memory for mipmapped textures in wined3d_texture_update_desc().

Henri Verbeet hverbeet at codeweavers.com
Thu May 14 10:25:44 CDT 2020


From: Paul Gofman <pgofman at codeweavers.com>

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49105
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
This supersedes patch 185204.

Do not modify the texture pitch when only setting user memory for the texture.
This is perhaps not immediately obvious, but setting an explicit pitch
overrides it for all sub-resources. That fine's for textures that only have a
single level, but not for mip-mapped textures.

 dlls/ddraw/tests/ddraw7.c |  96 +++++++++++++++++++++++++++++---
 dlls/wined3d/texture.c    | 113 ++++++++++++++++++++++----------------
 2 files changed, 155 insertions(+), 54 deletions(-)

diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c
index 53e47250e3d..c85f0201118 100644
--- a/dlls/ddraw/tests/ddraw7.c
+++ b/dlls/ddraw/tests/ddraw7.c
@@ -7126,6 +7126,64 @@ static void test_set_surface_desc(void)
 
     IDirectDrawSurface7_Release(surface);
 
+    /* Test mipmap texture. */
+    reset_ddsd(&ddsd);
+    ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_MIPMAPCOUNT;
+    ddsd.dwWidth = 8;
+    ddsd.dwHeight = 8;
+    U2(ddsd).dwMipMapCount = 3;
+    ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
+
+    hr = IDirectDraw7_CreateSurface(ddraw, &ddsd, &surface, NULL);
+    ok(hr == DD_OK || hr == DDERR_NODIRECTDRAWHW || hr == E_NOINTERFACE, "Got unexpected hr %#x.\n", hr);
+
+    if (FAILED(hr))
+    {
+        skip("Mipmaps are not supported.\n");
+    }
+    else
+    {
+        /* Changing surface desc for mipmap fails even without changing any
+         * parameters. */
+        hr = IDirectDrawSurface7_SetSurfaceDesc(surface, &ddsd, 0);
+        ok(hr == DDERR_INVALIDSURFACETYPE, "Got unexpected hr %#x.\n", hr);
+        IDirectDrawSurface7_Release(surface);
+    }
+
+    /* Test surface created with DDSD_LPSURFACE. */
+    reset_ddsd(&ddsd);
+    ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_LPSURFACE | DDSD_PITCH;
+    ddsd.dwWidth = 8;
+    ddsd.dwHeight = 8;
+    ddsd.lpSurface = data;
+    U1(ddsd).lPitch = 8 * 4;
+    ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
+    hr = IDirectDraw7_CreateSurface(ddraw, &ddsd, &surface, NULL);
+    ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_SetSurfaceDesc(surface, &ddsd, 0);
+    ok(hr == DDERR_INVALIDCAPS, "Got unexpected hr %#x.\n", hr);
+
+    reset_ddsd(&ddsd);
+    ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT;
+    ddsd.dwWidth = 8;
+    ddsd.dwHeight = 8;
+    /* Cannot reset lpSurface. */
+    hr = IDirectDrawSurface7_SetSurfaceDesc(surface, &ddsd, 0);
+    ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
+
+    reset_ddsd(&ddsd);
+    ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_LPSURFACE | DDSD_PITCH;
+    ddsd.dwWidth = 4;
+    ddsd.dwHeight = 4;
+    ddsd.lpSurface = data;
+    U1(ddsd).lPitch = 8 * 4;
+    /* Can change the parameters of surface created with DDSD_LPSURFACE. */
+    hr = IDirectDrawSurface7_SetSurfaceDesc(surface, &ddsd, 0);
+    ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+
+    IDirectDrawSurface7_Release(surface);
+
     /* SetSurfaceDesc needs systemmemory surfaces.
      *
      * As a sidenote, fourcc surfaces aren't allowed in sysmem, thus testing
@@ -13347,14 +13405,14 @@ static void test_display_mode_surface_pixel_format(void)
 
     surface_desc.dwSize = sizeof(surface_desc);
     hr = IDirectDraw7_GetDisplayMode(ddraw, &surface_desc);
-    ok(SUCCEEDED(hr), "Failed to get display mode, hr %#x.\n", hr);
+    ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
     width = surface_desc.dwWidth;
     height = surface_desc.dwHeight;
 
     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
             0, 0, width, height, NULL, NULL, NULL, NULL);
     hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
-    ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
+    ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
 
     bpp = 0;
     if (SUCCEEDED(IDirectDraw7_SetDisplayMode(ddraw, width, height, 16, 0, 0)))
@@ -13367,7 +13425,7 @@ static void test_display_mode_surface_pixel_format(void)
 
     surface_desc.dwSize = sizeof(surface_desc);
     hr = IDirectDraw7_GetDisplayMode(ddraw, &surface_desc);
-    ok(SUCCEEDED(hr), "Failed to get display mode, hr %#x.\n", hr);
+    ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
     ok(surface_desc.dwWidth == width, "Got width %u, expected %u.\n", surface_desc.dwWidth, width);
     ok(surface_desc.dwHeight == height, "Got height %u, expected %u.\n", surface_desc.dwHeight, height);
     ok(U1(U4(surface_desc).ddpfPixelFormat).dwRGBBitCount == bpp, "Got bpp %u, expected %u.\n",
@@ -13379,9 +13437,9 @@ static void test_display_mode_surface_pixel_format(void)
     U5(surface_desc).dwBackBufferCount = 1;
     surface_desc.ddsCaps.dwCaps = DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_PRIMARYSURFACE;
     hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface, NULL);
-    ok(hr == D3D_OK, "Failed to create surface, hr %#x.\n", hr);
+    ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
     hr = IDirectDrawSurface7_GetSurfaceDesc(surface, &surface_desc);
-    ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
+    ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
     ok(surface_desc.dwWidth == width, "Got width %u, expected %u.\n", surface_desc.dwWidth, width);
     ok(surface_desc.dwHeight == height, "Got height %u, expected %u.\n", surface_desc.dwHeight, height);
     ok(U4(surface_desc).ddpfPixelFormat.dwFlags == DDPF_RGB, "Got unexpected pixel format flags %#x.\n",
@@ -13397,15 +13455,39 @@ static void test_display_mode_surface_pixel_format(void)
     surface_desc.dwHeight = height;
     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
     hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface, NULL);
-    ok(hr == D3D_OK, "Failed to create surface, hr %#x.\n", hr);
+    ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
     hr = IDirectDrawSurface7_GetSurfaceDesc(surface, &surface_desc);
-    ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
+    ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
     ok(U4(surface_desc).ddpfPixelFormat.dwFlags == DDPF_RGB, "Got unexpected pixel format flags %#x.\n",
             U4(surface_desc).ddpfPixelFormat.dwFlags);
     ok(U1(U4(surface_desc).ddpfPixelFormat).dwRGBBitCount == bpp, "Got bpp %u, expected %u.\n",
             U1(U4(surface_desc).ddpfPixelFormat).dwRGBBitCount, bpp);
     IDirectDrawSurface7_Release(surface);
 
+    /* Test compatibility mode mipmap texture creation. */
+    hr = IDirectDraw7_SetDisplayMode(ddraw, width, height, 16, 0, 0);
+    ok(hr == DD_OK || hr == E_NOTIMPL, "Got unexpected hr %#x.\n", hr);
+    if (FAILED(hr))
+    {
+        win_skip("SetDisplayMode failed, skipping test.");
+        goto done;
+    }
+    bpp = 16;
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_MIPMAPCOUNT | DDSD_PITCH;
+    U2(surface_desc).dwMipMapCount = 2;
+    surface_desc.dwWidth = 4;
+    surface_desc.dwHeight = 4;
+    U1(surface_desc).lPitch = surface_desc.dwWidth * bpp / 8;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP | DDSCAPS_VIDEOMEMORY;
+    hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface, NULL);
+    ok(hr == DD_OK || hr == DDERR_NODIRECTDRAWHW, "Got unexpected hr %#x.\n", hr);
+    if (surface)
+        IDirectDrawSurface7_Release(surface);
+
+done:
     refcount = IDirectDraw7_Release(ddraw);
     ok(!refcount, "DirectDraw has %u references left.\n", refcount);
     DestroyWindow(window);
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index 49373eb58ac..de6999105d1 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -1748,11 +1748,13 @@ HRESULT CDECL wined3d_texture_update_desc(struct wined3d_texture *texture, UINT
     const struct wined3d_d3d_info *d3d_info;
     const struct wined3d_gl_info *gl_info;
     const struct wined3d_format *format;
-    const struct wined3d *d3d;
     struct wined3d_device *device;
     unsigned int resource_size;
+    const struct wined3d *d3d;
+    unsigned int slice_pitch;
     DWORD valid_location = 0;
-    BOOL create_dib = FALSE;
+    bool update_memory_only;
+    bool create_dib = false;
 
     TRACE("texture %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u, "
             "mem %p, pitch %u.\n",
@@ -1765,10 +1767,27 @@ HRESULT CDECL wined3d_texture_update_desc(struct wined3d_texture *texture, UINT
     format = wined3d_get_format(device->adapter, format_id, texture->resource.bind_flags);
     resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height, 1);
 
+    update_memory_only = width == texture->resource.width && height == texture->resource.height
+            && format_id == texture->resource.format->id && multisample_type == texture->resource.multisample_type
+            && multisample_quality == texture->resource.multisample_quality;
+
+    if (pitch)
+        slice_pitch = height * pitch;
+    else
+        wined3d_format_calculate_pitch(format, 1, width, height, &pitch, &slice_pitch);
+
+    if (update_memory_only)
+    {
+        unsigned int current_row_pitch, current_slice_pitch;
+
+        wined3d_texture_get_pitch(texture, 0, &current_row_pitch, &current_slice_pitch);
+        update_memory_only = pitch == current_row_pitch && slice_pitch == current_slice_pitch;
+    }
+
     if (!resource_size)
         return WINED3DERR_INVALIDCALL;
 
-    if (texture->level_count * texture->layer_count > 1)
+    if (texture->level_count * texture->layer_count > 1 && !update_memory_only)
     {
         WARN("Texture has multiple sub-resources, not supported.\n");
         return WINED3DERR_INVALIDCALL;
@@ -1803,67 +1822,67 @@ HRESULT CDECL wined3d_texture_update_desc(struct wined3d_texture *texture, UINT
         wined3d_cs_emit_unload_resource(device->cs, &texture->resource);
     wined3d_resource_wait_idle(&texture->resource);
 
-    sub_resource = &texture->sub_resources[0];
     if (texture->dc_info && texture->dc_info[0].dc)
     {
         struct wined3d_texture_idx texture_idx = {texture, 0};
 
         wined3d_cs_destroy_object(device->cs, wined3d_texture_destroy_dc, &texture_idx);
         wined3d_cs_finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
-        create_dib = TRUE;
+        create_dib = true;
     }
 
     wined3d_resource_free_sysmem(&texture->resource);
 
-    if ((texture->row_pitch = pitch))
-        texture->slice_pitch = height * pitch;
-    else
-        /* User memory surfaces don't have the regular surface alignment. */
-        wined3d_format_calculate_pitch(format, 1, width, height,
-                &texture->row_pitch, &texture->slice_pitch);
-
-    texture->resource.format = format;
-    texture->resource.multisample_type = multisample_type;
-    texture->resource.multisample_quality = multisample_quality;
-    texture->resource.width = width;
-    texture->resource.height = height;
-    if (!(texture->resource.access & WINED3D_RESOURCE_ACCESS_CPU) && d3d->flags & WINED3D_VIDMEM_ACCOUNTING)
-        adapter_adjust_memory(device->adapter,  (INT64)texture->slice_pitch - texture->resource.size);
-    texture->resource.size = texture->slice_pitch;
-    sub_resource->size = texture->slice_pitch;
-    sub_resource->locations = WINED3D_LOCATION_DISCARDED;
-
-    if (texture->texture_ops == &texture_gl_ops)
-    {
-        if (multisample_type && gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
+    if (!update_memory_only)
+    {
+        sub_resource = &texture->sub_resources[0];
+
+        texture->row_pitch = pitch;
+        texture->slice_pitch = slice_pitch;
+
+        texture->resource.format = format;
+        texture->resource.multisample_type = multisample_type;
+        texture->resource.multisample_quality = multisample_quality;
+        texture->resource.width = width;
+        texture->resource.height = height;
+        if (!(texture->resource.access & WINED3D_RESOURCE_ACCESS_CPU) && d3d->flags & WINED3D_VIDMEM_ACCOUNTING)
+            adapter_adjust_memory(device->adapter,  (INT64)texture->slice_pitch - texture->resource.size);
+        texture->resource.size = texture->slice_pitch;
+        sub_resource->size = texture->slice_pitch;
+        sub_resource->locations = WINED3D_LOCATION_DISCARDED;
+
+        if (texture->texture_ops == &texture_gl_ops)
         {
-            wined3d_texture_gl(texture)->target = GL_TEXTURE_2D_MULTISAMPLE;
-            texture->flags &= ~WINED3D_TEXTURE_DOWNLOADABLE;
+            if (multisample_type && gl_info->supported[ARB_TEXTURE_MULTISAMPLE])
+            {
+                wined3d_texture_gl(texture)->target = GL_TEXTURE_2D_MULTISAMPLE;
+                texture->flags &= ~WINED3D_TEXTURE_DOWNLOADABLE;
+            }
+            else
+            {
+                wined3d_texture_gl(texture)->target = GL_TEXTURE_2D;
+                texture->flags |= WINED3D_TEXTURE_DOWNLOADABLE;
+            }
+        }
+
+        if (((width & (width - 1)) || (height & (height - 1))) && !d3d_info->texture_npot
+                && !d3d_info->texture_npot_conditional)
+        {
+            texture->flags |= WINED3D_TEXTURE_COND_NP2_EMULATED;
+            texture->pow2_width = texture->pow2_height = 1;
+            while (texture->pow2_width < width)
+                texture->pow2_width <<= 1;
+            while (texture->pow2_height < height)
+                texture->pow2_height <<= 1;
         }
         else
         {
-            wined3d_texture_gl(texture)->target = GL_TEXTURE_2D;
-            texture->flags |= WINED3D_TEXTURE_DOWNLOADABLE;
+            texture->flags &= ~WINED3D_TEXTURE_COND_NP2_EMULATED;
+            texture->pow2_width = width;
+            texture->pow2_height = height;
         }
     }
 
-    if (((width & (width - 1)) || (height & (height - 1))) && !d3d_info->texture_npot
-            && !d3d_info->texture_npot_conditional)
-    {
-        texture->flags |= WINED3D_TEXTURE_COND_NP2_EMULATED;
-        texture->pow2_width = texture->pow2_height = 1;
-        while (texture->pow2_width < width)
-            texture->pow2_width <<= 1;
-        while (texture->pow2_height < height)
-            texture->pow2_height <<= 1;
-    }
-    else
-    {
-        texture->flags &= ~WINED3D_TEXTURE_COND_NP2_EMULATED;
-        texture->pow2_width = width;
-        texture->pow2_height = height;
-    }
-
     if ((texture->user_memory = mem))
     {
         texture->resource.map_binding = WINED3D_LOCATION_USER_MEMORY;
-- 
2.20.1




More information about the wine-devel mailing list