[PATCH 3/5] d3d9: Handle D3DUSAGE_AUTOGENMIPMAP textures entirely in d3d9.

Matteo Bruni mbruni at codeweavers.com
Tue Feb 6 12:36:15 CST 2018


Signed-off-by: Matteo Bruni <mbruni at codeweavers.com>
---
 dlls/d3d9/d3d9_private.h |  25 ++++-
 dlls/d3d9/device.c       |  75 +++++++++++++
 dlls/d3d9/surface.c      |   4 +
 dlls/d3d9/tests/device.c |   5 +-
 dlls/d3d9/texture.c      | 270 ++++++++++++++++++++++++++++++++++++-----------
 5 files changed, 313 insertions(+), 66 deletions(-)

diff --git a/dlls/d3d9/d3d9_private.h b/dlls/d3d9/d3d9_private.h
index 5a1aac81ed1..ce76c71e029 100644
--- a/dlls/d3d9/d3d9_private.h
+++ b/dlls/d3d9/d3d9_private.h
@@ -39,8 +39,16 @@
 #include "d3d9.h"
 #include "wine/wined3d.h"
 
+#define D3D9_MAX_VERTEX_SHADER_CONSTANTF 256
+#define D3D9_MAX_TEXTURE_UNITS 20
+#define D3D9_MAX_SIMULTANEOUS_RENDERTARGETS 4
+
 #define D3DPRESENTFLAGS_MASK 0x00000fffu
 
+#define D3D9_TEXTURE_MIPMAP_DIRTY 0x1
+
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
+
 extern const struct wined3d_parent_ops d3d9_null_wined3d_parent_ops DECLSPEC_HIDDEN;
 
 HRESULT vdecl_convert_fvf(DWORD FVF, D3DVERTEXELEMENT9 **ppVertexElements) DECLSPEC_HIDDEN;
@@ -92,6 +100,9 @@ struct d3d9_device
     UINT index_buffer_size;
     UINT index_buffer_pos;
 
+    struct d3d9_texture *textures[D3D9_MAX_TEXTURE_UNITS];
+    struct d3d9_surface *render_targets[D3D9_MAX_SIMULTANEOUS_RENDERTARGETS];
+
     LONG device_state;
     BOOL in_destruction;
     BOOL in_scene;
@@ -198,6 +209,10 @@ struct d3d9_texture
     struct wined3d_texture *wined3d_texture;
     IDirect3DDevice9Ex *parent_device;
     struct list rtv_list;
+    DWORD usage;
+    BOOL flags;
+    struct wined3d_shader_resource_view *wined3d_srv;
+    D3DTEXTUREFILTERTYPE autogen_filter_type;
 };
 
 HRESULT cubetexture_init(struct d3d9_texture *texture, struct d3d9_device *device,
@@ -207,6 +222,8 @@ HRESULT texture_init(struct d3d9_texture *texture, struct d3d9_device *device,
 HRESULT volumetexture_init(struct d3d9_texture *texture, struct d3d9_device *device,
         UINT width, UINT height, UINT depth, UINT levels, DWORD usage, D3DFORMAT format, D3DPOOL pool) DECLSPEC_HIDDEN;
 struct d3d9_texture *unsafe_impl_from_IDirect3DBaseTexture9(IDirect3DBaseTexture9 *iface) DECLSPEC_HIDDEN;
+void d3d9_texture_flag_auto_gen_mipmap(struct d3d9_texture *texture) DECLSPEC_HIDDEN;
+void d3d9_texture_gen_auto_mipmap(struct d3d9_texture *texture) DECLSPEC_HIDDEN;
 
 struct d3d9_stateblock
 {
@@ -247,9 +264,6 @@ HRESULT vertexshader_init(struct d3d9_vertexshader *shader,
         struct d3d9_device *device, const DWORD *byte_code) DECLSPEC_HIDDEN;
 struct d3d9_vertexshader *unsafe_impl_from_IDirect3DVertexShader9(IDirect3DVertexShader9 *iface) DECLSPEC_HIDDEN;
 
-#define D3D9_MAX_VERTEX_SHADER_CONSTANTF 256
-#define D3D9_MAX_SIMULTANEOUS_RENDERTARGETS 4
-
 struct d3d9_pixelshader
 {
     IDirect3DPixelShader9 IDirect3DPixelShader9_iface;
@@ -315,4 +329,9 @@ static inline unsigned int wined3daccess_from_d3dpool(D3DPOOL pool)
     }
 }
 
+static inline DWORD wined3dusage_from_d3dusage(unsigned int usage)
+{
+    return usage & WINED3DUSAGE_MASK & ~WINED3DUSAGE_AUTOGENMIPMAP;
+}
+
 #endif /* __WINE_D3D9_PRIVATE_H */
diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c
index 954f3faa30d..d2766c72a54 100644
--- a/dlls/d3d9/device.c
+++ b/dlls/d3d9/device.c
@@ -816,6 +816,8 @@ static HRESULT d3d9_device_reset(struct d3d9_device *device,
     BOOL extended = device->d3d_parent->extended;
     struct wined3d_swapchain_desc swapchain_desc;
     struct wined3d_display_mode wined3d_mode;
+    struct wined3d_rendertarget_view *rtv;
+    unsigned int i;
     HRESULT hr;
 
     if (!extended && device->device_state == D3D9_DEVICE_STATE_LOST)
@@ -877,6 +879,15 @@ static HRESULT d3d9_device_reset(struct d3d9_device *device,
 
             device->device_state = D3D9_DEVICE_STATE_OK;
         }
+
+        if (!device->d3d_parent->extended)
+            for (i = 0; i < ARRAY_SIZE(device->textures); ++i)
+                device->textures[i] = NULL;
+
+        rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0);
+        device->render_targets[0] = wined3d_rendertarget_view_get_sub_resource_parent(rtv);
+        for (i = 1; i < ARRAY_SIZE(device->render_targets); ++i)
+            device->render_targets[i] = NULL;
     }
     else if (!extended)
     {
@@ -1431,6 +1442,9 @@ static HRESULT WINAPI d3d9_device_UpdateSurface(IDirect3DDevice9Ex *iface,
             wined3d_texture_get_resource(dst->wined3d_texture), dst->sub_resource_idx, dst_point ? dst_point->x : 0,
             dst_point ? dst_point->y : 0, 0, wined3d_texture_get_resource(src->wined3d_texture),
             src->sub_resource_idx, &src_box);
+    if (SUCCEEDED(hr) && dst->texture)
+        d3d9_texture_flag_auto_gen_mipmap(dst->texture);
+
     wined3d_mutex_unlock();
 
     if (FAILED(hr))
@@ -1454,6 +1468,8 @@ static HRESULT WINAPI d3d9_device_UpdateTexture(IDirect3DDevice9Ex *iface,
     wined3d_mutex_lock();
     hr = wined3d_device_update_texture(device->wined3d_device,
             src_impl->wined3d_texture, dst_impl->wined3d_texture);
+    if (SUCCEEDED(hr))
+        d3d9_texture_flag_auto_gen_mipmap(dst_impl);
     wined3d_mutex_unlock();
 
     return hr;
@@ -1572,6 +1588,8 @@ static HRESULT WINAPI d3d9_device_StretchRect(IDirect3DDevice9Ex *iface, IDirect
             src->wined3d_texture, src->sub_resource_idx, src_rect, 0, NULL, filter);
     if (hr == WINEDDERR_INVALIDRECT)
         hr = D3DERR_INVALIDCALL;
+    if (SUCCEEDED(hr) && dst->texture)
+        d3d9_texture_flag_auto_gen_mipmap(dst->texture);
 
 done:
     wined3d_mutex_unlock();
@@ -1628,6 +1646,8 @@ static HRESULT WINAPI d3d9_device_ColorFill(IDirect3DDevice9Ex *iface,
     hr = wined3d_device_clear_rendertarget_view(device->wined3d_device,
             rtv, rect, WINED3DCLEAR_TARGET, &c, 0.0f, 0);
     d3d9_surface_release_rendertarget_view(surface_impl, rtv);
+    if (SUCCEEDED(hr) && surface_impl->texture)
+        d3d9_texture_flag_auto_gen_mipmap(surface_impl->texture);
 
     wined3d_mutex_unlock();
 
@@ -1710,6 +1730,8 @@ static HRESULT WINAPI d3d9_device_SetRenderTarget(IDirect3DDevice9Ex *iface, DWO
     rtv = surface_impl ? d3d9_surface_acquire_rendertarget_view(surface_impl) : NULL;
     hr = wined3d_device_set_rendertarget_view(device->wined3d_device, idx, rtv, TRUE);
     d3d9_surface_release_rendertarget_view(surface_impl, rtv);
+    if (SUCCEEDED(hr))
+        device->render_targets[idx] = surface_impl;
     wined3d_mutex_unlock();
 
     return hr;
@@ -1830,6 +1852,19 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_EndScene(IDirect3DDevice9Ex
     return hr;
 }
 
+static void d3d9_rts_flag_auto_gen_mipmap(struct d3d9_device *device)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(device->render_targets); ++i)
+    {
+        struct d3d9_surface *surface = device->render_targets[i];
+
+        if (surface && surface->texture)
+            d3d9_texture_flag_auto_gen_mipmap(surface->texture);
+    }
+}
+
 static HRESULT WINAPI d3d9_device_Clear(IDirect3DDevice9Ex *iface, DWORD rect_count,
         const D3DRECT *rects, DWORD flags, D3DCOLOR color, float z, DWORD stencil)
 {
@@ -1854,6 +1889,8 @@ static HRESULT WINAPI d3d9_device_Clear(IDirect3DDevice9Ex *iface, DWORD rect_co
 
     wined3d_mutex_lock();
     hr = wined3d_device_clear(device->wined3d_device, rect_count, (const RECT *)rects, flags, &c, z, stencil);
+    if (SUCCEEDED(hr))
+        d3d9_rts_flag_auto_gen_mipmap(device);
     wined3d_mutex_unlock();
 
     return hr;
@@ -2251,6 +2288,13 @@ static HRESULT WINAPI d3d9_device_SetTexture(IDirect3DDevice9Ex *iface, DWORD st
     wined3d_mutex_lock();
     hr = wined3d_device_set_texture(device->wined3d_device, stage,
             texture_impl ? texture_impl->wined3d_texture : NULL);
+    if (SUCCEEDED(hr))
+    {
+        unsigned int i = stage >= D3DVERTEXTEXTURESAMPLER0 ? stage - D3DVERTEXTEXTURESAMPLER0 + 16 : stage;
+
+        if (stage < ARRAY_SIZE(device->textures))
+            device->textures[i] = texture_impl;
+    }
     wined3d_mutex_unlock();
 
     return hr;
@@ -2491,6 +2535,16 @@ static float WINAPI d3d9_device_GetNPatchMode(IDirect3DDevice9Ex *iface)
     return ret;
 }
 
+/* wined3d critical section must be taken by the caller. */
+static void d3d9_generate_auto_mipmaps(struct d3d9_device *device)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(device->textures); ++i)
+        if (device->textures[i])
+            d3d9_texture_gen_auto_mipmap(device->textures[i]);
+}
+
 static HRESULT WINAPI d3d9_device_DrawPrimitive(IDirect3DDevice9Ex *iface,
         D3DPRIMITIVETYPE primitive_type, UINT start_vertex, UINT primitive_count)
 {
@@ -2507,9 +2561,12 @@ static HRESULT WINAPI d3d9_device_DrawPrimitive(IDirect3DDevice9Ex *iface,
         WARN("Called without a valid vertex declaration set.\n");
         return D3DERR_INVALIDCALL;
     }
+    d3d9_generate_auto_mipmaps(device);
     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
     hr = wined3d_device_draw_primitive(device->wined3d_device, start_vertex,
             vertex_count_from_primitive_count(primitive_type, primitive_count));
+    if (SUCCEEDED(hr))
+        d3d9_rts_flag_auto_gen_mipmap(device);
     wined3d_mutex_unlock();
 
     return hr;
@@ -2534,10 +2591,13 @@ static HRESULT WINAPI d3d9_device_DrawIndexedPrimitive(IDirect3DDevice9Ex *iface
         WARN("Called without a valid vertex declaration set.\n");
         return D3DERR_INVALIDCALL;
     }
+    d3d9_generate_auto_mipmaps(device);
     wined3d_device_set_base_vertex_index(device->wined3d_device, base_vertex_idx);
     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
     hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, start_idx,
             vertex_count_from_primitive_count(primitive_type, primitive_count));
+    if (SUCCEEDED(hr))
+        d3d9_rts_flag_auto_gen_mipmap(device);
     wined3d_mutex_unlock();
 
     return hr;
@@ -2629,9 +2689,12 @@ static HRESULT WINAPI d3d9_device_DrawPrimitiveUP(IDirect3DDevice9Ex *iface,
     if (FAILED(hr))
         goto done;
 
+    d3d9_generate_auto_mipmaps(device);
     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
     hr = wined3d_device_draw_primitive(device->wined3d_device, vb_pos / stride, vtx_count);
     wined3d_device_set_stream_source(device->wined3d_device, 0, NULL, 0, 0);
+    if (SUCCEEDED(hr))
+        d3d9_rts_flag_auto_gen_mipmap(device);
 
 done:
     wined3d_mutex_unlock();
@@ -2752,6 +2815,7 @@ static HRESULT WINAPI d3d9_device_DrawIndexedPrimitiveUP(IDirect3DDevice9Ex *ifa
     if (FAILED(hr))
         goto done;
 
+    d3d9_generate_auto_mipmaps(device);
     wined3d_device_set_index_buffer(device->wined3d_device, device->index_buffer,
             wined3dformat_from_d3dformat(index_format), 0);
     wined3d_device_set_base_vertex_index(device->wined3d_device, vb_pos / vertex_stride - min_vertex_idx);
@@ -2763,6 +2827,9 @@ static HRESULT WINAPI d3d9_device_DrawIndexedPrimitiveUP(IDirect3DDevice9Ex *ifa
     wined3d_device_set_index_buffer(device->wined3d_device, NULL, WINED3DFMT_UNKNOWN, 0);
     wined3d_device_set_base_vertex_index(device->wined3d_device, 0);
 
+    if (SUCCEEDED(hr))
+        d3d9_rts_flag_auto_gen_mipmap(device);
+
 done:
     wined3d_mutex_unlock();
     return hr;
@@ -4147,6 +4214,14 @@ HRESULT device_init(struct d3d9_device *device, struct d3d9 *parent, struct wine
         return E_OUTOFMEMORY;
     }
 
+    /* We could also simply ignore the initial rendertarget since it's known
+     * not to be a texture (we currently use these only for automatic mipmap
+     * generation). */
+    wined3d_mutex_lock();
+    device->render_targets[0] = wined3d_rendertarget_view_get_sub_resource_parent(
+            wined3d_device_get_rendertarget_view(device->wined3d_device, 0));
+    wined3d_mutex_unlock();
+
     IDirect3D9Ex_AddRef(&parent->IDirect3D9Ex_iface);
     device->d3d_parent = parent;
 
diff --git a/dlls/d3d9/surface.c b/dlls/d3d9/surface.c
index 8c42a8c630d..a38cbb4d816 100644
--- a/dlls/d3d9/surface.c
+++ b/dlls/d3d9/surface.c
@@ -270,6 +270,8 @@ static HRESULT WINAPI d3d9_surface_UnlockRect(IDirect3DSurface9 *iface)
 
     wined3d_mutex_lock();
     hr = wined3d_resource_unmap(wined3d_texture_get_resource(surface->wined3d_texture), surface->sub_resource_idx);
+    if (SUCCEEDED(hr) && surface->texture)
+        d3d9_texture_flag_auto_gen_mipmap(surface->texture);
     wined3d_mutex_unlock();
 
     if (hr == WINEDDERR_NOTLOCKED)
@@ -307,6 +309,8 @@ static HRESULT WINAPI d3d9_surface_ReleaseDC(IDirect3DSurface9 *iface, HDC dc)
 
     wined3d_mutex_lock();
     hr = wined3d_texture_release_dc(surface->wined3d_texture, surface->sub_resource_idx, dc);
+    if (SUCCEEDED(hr) && surface->texture)
+        d3d9_texture_flag_auto_gen_mipmap(surface->texture);
     wined3d_mutex_unlock();
 
     return hr;
diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c
index a9fd4e4d30f..71cfdf49219 100644
--- a/dlls/d3d9/tests/device.c
+++ b/dlls/d3d9/tests/device.c
@@ -7124,10 +7124,9 @@ static void test_mipmap_gen(void)
     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
 
     filter_type = IDirect3DTexture9_GetAutoGenFilterType(texture);
-    ok(filter_type == D3DTEXF_LINEAR /* || broken(filter_type == D3DTEXF_POINT)*/,
-            "Got unexpected filter_type %#x.\n", filter_type);
+    ok(filter_type == D3DTEXF_LINEAR, "Got unexpected filter_type %#x.\n", filter_type);
     hr = IDirect3DTexture9_SetAutoGenFilterType(texture, D3DTEXF_NONE);
-    todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#x.\n", hr);
+    ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#x.\n", hr);
     hr = IDirect3DTexture9_SetAutoGenFilterType(texture, D3DTEXF_ANISOTROPIC);
     ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
     filter_type = IDirect3DTexture9_GetAutoGenFilterType(texture);
diff --git a/dlls/d3d9/texture.c b/dlls/d3d9/texture.c
index a1c52591c1b..e51c6fc6e58 100644
--- a/dlls/d3d9/texture.c
+++ b/dlls/d3d9/texture.c
@@ -38,6 +38,62 @@ static inline struct d3d9_texture *impl_from_IDirect3DVolumeTexture9(IDirect3DVo
     return CONTAINING_RECORD(iface, struct d3d9_texture, IDirect3DBaseTexture9_iface);
 }
 
+static void STDMETHODCALLTYPE srv_wined3d_object_destroyed(void *parent)
+{
+    struct d3d9_texture *texture = parent;
+
+    texture->wined3d_srv = NULL;
+}
+
+static const struct wined3d_parent_ops d3d9_srv_wined3d_parent_ops =
+{
+    srv_wined3d_object_destroyed,
+};
+
+/* wined3d critical section must be taken by the caller. */
+static struct wined3d_shader_resource_view *d3d9_texture_acquire_shader_resource_view(struct d3d9_texture *texture)
+{
+    struct wined3d_sub_resource_desc sr_desc;
+    struct wined3d_view_desc desc;
+    HRESULT hr;
+
+    if (texture->wined3d_srv)
+        return texture->wined3d_srv;
+
+    wined3d_texture_get_sub_resource_desc(texture->wined3d_texture, 0, &sr_desc);
+    desc.format_id = sr_desc.format;
+    desc.flags = 0;
+    desc.u.texture.level_idx = 0;
+    desc.u.texture.level_count = wined3d_texture_get_level_count(texture->wined3d_texture);
+    desc.u.texture.layer_idx = 0;
+    desc.u.texture.layer_count = sr_desc.usage & WINED3DUSAGE_LEGACY_CUBEMAP ? 6 : 1;
+    if (FAILED(hr = wined3d_shader_resource_view_create(&desc,
+            wined3d_texture_get_resource(texture->wined3d_texture), texture,
+            &d3d9_srv_wined3d_parent_ops, &texture->wined3d_srv)))
+    {
+        ERR("Failed to create shader resource view, hr %#x.\n", hr);
+        return NULL;
+    }
+
+    return texture->wined3d_srv;
+}
+
+/* wined3d critical section must be taken by the caller. */
+void d3d9_texture_gen_auto_mipmap(struct d3d9_texture *texture)
+{
+    if (!(texture->flags & D3D9_TEXTURE_MIPMAP_DIRTY))
+        return;
+    d3d9_texture_acquire_shader_resource_view(texture);
+    wined3d_shader_resource_view_generate_mipmaps(texture->wined3d_srv);
+    texture->flags &= ~D3D9_TEXTURE_MIPMAP_DIRTY;
+}
+
+void d3d9_texture_flag_auto_gen_mipmap(struct d3d9_texture *texture)
+{
+    if (texture->usage & D3DUSAGE_AUTOGENMIPMAP)
+        texture->flags |= D3D9_TEXTURE_MIPMAP_DIRTY;
+}
+
 static HRESULT WINAPI d3d9_texture_2d_QueryInterface(IDirect3DTexture9 *iface, REFIID riid, void **out)
 {
     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
@@ -95,6 +151,8 @@ static ULONG WINAPI d3d9_texture_2d_Release(IDirect3DTexture9 *iface)
         struct d3d9_surface *surface;
 
         wined3d_mutex_lock();
+        if (texture->wined3d_srv)
+            wined3d_shader_resource_view_decref(texture->wined3d_srv);
         LIST_FOR_EACH_ENTRY(surface, &texture->rtv_list, struct d3d9_surface, rtv_entry)
         {
             wined3d_rendertarget_view_decref(surface->wined3d_rtv);
@@ -235,6 +293,9 @@ static DWORD WINAPI d3d9_texture_2d_GetLevelCount(IDirect3DTexture9 *iface)
 
     TRACE("iface %p.\n", iface);
 
+    if (texture->usage & D3DUSAGE_AUTOGENMIPMAP)
+        return 1;
+
     wined3d_mutex_lock();
     ret = wined3d_texture_get_level_count(texture->wined3d_texture);
     wined3d_mutex_unlock();
@@ -245,35 +306,44 @@ static DWORD WINAPI d3d9_texture_2d_GetLevelCount(IDirect3DTexture9 *iface)
 static HRESULT WINAPI d3d9_texture_2d_SetAutoGenFilterType(IDirect3DTexture9 *iface, D3DTEXTUREFILTERTYPE filter_type)
 {
     struct d3d9_texture *texture = impl_from_IDirect3DTexture9(iface);
-    HRESULT hr;
 
     TRACE("iface %p, filter_type %#x.\n", iface, filter_type);
 
-    wined3d_mutex_lock();
-    hr = wined3d_texture_set_autogen_filter_type(texture->wined3d_texture,
-            (enum wined3d_texture_filter_type)filter_type);
-    wined3d_mutex_unlock();
+    if (filter_type == D3DTEXF_NONE)
+    {
+        WARN("Invalid filter type D3DTEXF_NONE specified.\n");
+        return D3DERR_INVALIDCALL;
+    }
+    if (!(texture->usage & D3DUSAGE_AUTOGENMIPMAP))
+        WARN("Called on a texture without the D3DUSAGE_AUTOGENMIPMAP flag.\n");
+    else if (filter_type != D3DTEXF_LINEAR)
+        FIXME("Unsupported filter type %u.\n", filter_type);
 
-    return hr;
+    texture->autogen_filter_type = filter_type;
+    return D3D_OK;
 }
 
 static D3DTEXTUREFILTERTYPE WINAPI d3d9_texture_2d_GetAutoGenFilterType(IDirect3DTexture9 *iface)
 {
     struct d3d9_texture *texture = impl_from_IDirect3DTexture9(iface);
-    D3DTEXTUREFILTERTYPE ret;
 
     TRACE("iface %p.\n", iface);
 
-    wined3d_mutex_lock();
-    ret = (D3DTEXTUREFILTERTYPE)wined3d_texture_get_autogen_filter_type(texture->wined3d_texture);
-    wined3d_mutex_unlock();
+    if (!(texture->usage & D3DUSAGE_AUTOGENMIPMAP))
+        WARN("Called on a texture without the D3DUSAGE_AUTOGENMIPMAP flag.\n");
 
-    return ret;
+    return texture->autogen_filter_type;
 }
 
 static void WINAPI d3d9_texture_2d_GenerateMipSubLevels(IDirect3DTexture9 *iface)
 {
+    struct d3d9_texture *texture = impl_from_IDirect3DTexture9(iface);
+
     TRACE("iface %p.\n", iface);
+
+    wined3d_mutex_lock();
+    d3d9_texture_gen_auto_mipmap(texture);
+    wined3d_mutex_unlock();
 }
 
 static HRESULT WINAPI d3d9_texture_2d_GetLevelDesc(IDirect3DTexture9 *iface, UINT level, D3DSURFACE_DESC *desc)
@@ -284,12 +354,18 @@ static HRESULT WINAPI d3d9_texture_2d_GetLevelDesc(IDirect3DTexture9 *iface, UIN
 
     TRACE("iface %p, level %u, desc %p.\n", iface, level, desc);
 
+    if (texture->usage & D3DUSAGE_AUTOGENMIPMAP && level)
+    {
+        WARN("D3DUSAGE_AUTOGENMIPMAP textures have only one accessible level.\n");
+        return D3DERR_INVALIDCALL;
+    }
+
     wined3d_mutex_lock();
     if (SUCCEEDED(hr = wined3d_texture_get_sub_resource_desc(texture->wined3d_texture, level, &wined3d_desc)))
     {
         desc->Format = d3dformat_from_wined3dformat(wined3d_desc.format);
         desc->Type = D3DRTYPE_SURFACE;
-        desc->Usage = d3dusage_from_wined3dusage(wined3d_desc.usage);
+        desc->Usage = texture->usage;
         desc->Pool = d3dpool_from_wined3daccess(wined3d_desc.access, wined3d_desc.usage);
         desc->MultiSampleType = wined3d_desc.multisample_type;
         desc->MultiSampleQuality = wined3d_desc.multisample_quality;
@@ -309,6 +385,12 @@ static HRESULT WINAPI d3d9_texture_2d_GetSurfaceLevel(IDirect3DTexture9 *iface,
 
     TRACE("iface %p, level %u, surface %p.\n", iface, level, surface);
 
+    if (texture->usage & D3DUSAGE_AUTOGENMIPMAP && level)
+    {
+        WARN("D3DUSAGE_AUTOGENMIPMAP textures have only one accessible level.\n");
+        return D3DERR_INVALIDCALL;
+    }
+
     wined3d_mutex_lock();
     if (!(surface_impl = wined3d_texture_get_sub_resource_parent(texture->wined3d_texture, level)))
     {
@@ -333,6 +415,12 @@ static HRESULT WINAPI d3d9_texture_2d_LockRect(IDirect3DTexture9 *iface,
     TRACE("iface %p, level %u, locked_rect %p, rect %p, flags %#x.\n",
             iface, level, locked_rect, rect, flags);
 
+    if (texture->usage & D3DUSAGE_AUTOGENMIPMAP && level)
+    {
+        WARN("D3DUSAGE_AUTOGENMIPMAP textures have only one accessible level.\n");
+        return D3DERR_INVALIDCALL;
+    }
+
     wined3d_mutex_lock();
     if (!(surface_impl = wined3d_texture_get_sub_resource_parent(texture->wined3d_texture, level)))
         hr = D3DERR_INVALIDCALL;
@@ -351,6 +439,12 @@ static HRESULT WINAPI d3d9_texture_2d_UnlockRect(IDirect3DTexture9 *iface, UINT
 
     TRACE("iface %p, level %u.\n", iface, level);
 
+    if (texture->usage & D3DUSAGE_AUTOGENMIPMAP && level)
+    {
+        WARN("D3DUSAGE_AUTOGENMIPMAP textures have only one accessible level.\n");
+        return D3DERR_INVALIDCALL;
+    }
+
     wined3d_mutex_lock();
     if (!(surface_impl = wined3d_texture_get_sub_resource_parent(texture->wined3d_texture, level)))
         hr = D3DERR_INVALIDCALL;
@@ -473,6 +567,8 @@ static ULONG WINAPI d3d9_texture_cube_Release(IDirect3DCubeTexture9 *iface)
         TRACE("Releasing child %p.\n", texture->wined3d_texture);
 
         wined3d_mutex_lock();
+        if (texture->wined3d_srv)
+            wined3d_shader_resource_view_decref(texture->wined3d_srv);
         LIST_FOR_EACH_ENTRY(surface, &texture->rtv_list, struct d3d9_surface, rtv_entry)
         {
             wined3d_rendertarget_view_decref(surface->wined3d_rtv);
@@ -613,6 +709,9 @@ static DWORD WINAPI d3d9_texture_cube_GetLevelCount(IDirect3DCubeTexture9 *iface
 
     TRACE("iface %p.\n", iface);
 
+    if (texture->usage & D3DUSAGE_AUTOGENMIPMAP)
+        return 1;
+
     wined3d_mutex_lock();
     ret = wined3d_texture_get_level_count(texture->wined3d_texture);
     wined3d_mutex_unlock();
@@ -624,35 +723,44 @@ static HRESULT WINAPI d3d9_texture_cube_SetAutoGenFilterType(IDirect3DCubeTextur
         D3DTEXTUREFILTERTYPE filter_type)
 {
     struct d3d9_texture *texture = impl_from_IDirect3DCubeTexture9(iface);
-    HRESULT hr;
 
     TRACE("iface %p, filter_type %#x.\n", iface, filter_type);
 
-    wined3d_mutex_lock();
-    hr = wined3d_texture_set_autogen_filter_type(texture->wined3d_texture,
-            (enum wined3d_texture_filter_type)filter_type);
-    wined3d_mutex_unlock();
+    if (filter_type == D3DTEXF_NONE)
+    {
+        WARN("Invalid filter type D3DTEXF_NONE specified.\n");
+        return D3DERR_INVALIDCALL;
+    }
+    if (!(texture->usage & D3DUSAGE_AUTOGENMIPMAP))
+        WARN("Called on a texture without the D3DUSAGE_AUTOGENMIPMAP flag.\n");
+    else if (filter_type != D3DTEXF_LINEAR)
+        FIXME("Unsupported filter type %u.\n", filter_type);
 
-    return hr;
+    texture->autogen_filter_type = filter_type;
+    return D3D_OK;
 }
 
 static D3DTEXTUREFILTERTYPE WINAPI d3d9_texture_cube_GetAutoGenFilterType(IDirect3DCubeTexture9 *iface)
 {
     struct d3d9_texture *texture = impl_from_IDirect3DCubeTexture9(iface);
-    D3DTEXTUREFILTERTYPE ret;
 
     TRACE("iface %p.\n", iface);
 
-    wined3d_mutex_lock();
-    ret = (D3DTEXTUREFILTERTYPE)wined3d_texture_get_autogen_filter_type(texture->wined3d_texture);
-    wined3d_mutex_unlock();
+    if (!(texture->usage & D3DUSAGE_AUTOGENMIPMAP))
+        WARN("Called on a texture without the D3DUSAGE_AUTOGENMIPMAP flag.\n");
 
-    return ret;
+    return texture->autogen_filter_type;
 }
 
 static void WINAPI d3d9_texture_cube_GenerateMipSubLevels(IDirect3DCubeTexture9 *iface)
 {
+    struct d3d9_texture *texture = impl_from_IDirect3DCubeTexture9(iface);
+
     TRACE("iface %p.\n", iface);
+
+    wined3d_mutex_lock();
+    d3d9_texture_gen_auto_mipmap(texture);
+    wined3d_mutex_unlock();
 }
 
 static HRESULT WINAPI d3d9_texture_cube_GetLevelDesc(IDirect3DCubeTexture9 *iface, UINT level, D3DSURFACE_DESC *desc)
@@ -664,6 +772,12 @@ static HRESULT WINAPI d3d9_texture_cube_GetLevelDesc(IDirect3DCubeTexture9 *ifac
 
     TRACE("iface %p, level %u, desc %p.\n", iface, level, desc);
 
+    if (texture->usage & D3DUSAGE_AUTOGENMIPMAP && level)
+    {
+        WARN("D3DUSAGE_AUTOGENMIPMAP textures have only one accessible level.\n");
+        return D3DERR_INVALIDCALL;
+    }
+
     wined3d_mutex_lock();
     level_count = wined3d_texture_get_level_count(texture->wined3d_texture);
     if (level >= level_count)
@@ -676,7 +790,7 @@ static HRESULT WINAPI d3d9_texture_cube_GetLevelDesc(IDirect3DCubeTexture9 *ifac
     {
         desc->Format = d3dformat_from_wined3dformat(wined3d_desc.format);
         desc->Type = D3DRTYPE_SURFACE;
-        desc->Usage = d3dusage_from_wined3dusage(wined3d_desc.usage);
+        desc->Usage = texture->usage;
         desc->Pool = d3dpool_from_wined3daccess(wined3d_desc.access, wined3d_desc.usage);
         desc->MultiSampleType = wined3d_desc.multisample_type;
         desc->MultiSampleQuality = wined3d_desc.multisample_quality;
@@ -698,6 +812,12 @@ static HRESULT WINAPI d3d9_texture_cube_GetCubeMapSurface(IDirect3DCubeTexture9
 
     TRACE("iface %p, face %#x, level %u, surface %p.\n", iface, face, level, surface);
 
+    if (texture->usage & D3DUSAGE_AUTOGENMIPMAP && level)
+    {
+        WARN("D3DUSAGE_AUTOGENMIPMAP textures have only one accessible level.\n");
+        return D3DERR_INVALIDCALL;
+    }
+
     wined3d_mutex_lock();
     level_count = wined3d_texture_get_level_count(texture->wined3d_texture);
     if (level >= level_count)
@@ -732,6 +852,12 @@ static HRESULT WINAPI d3d9_texture_cube_LockRect(IDirect3DCubeTexture9 *iface,
     TRACE("iface %p, face %#x, level %u, locked_rect %p, rect %p, flags %#x.\n",
             iface, face, level, locked_rect, rect, flags);
 
+    if (texture->usage & D3DUSAGE_AUTOGENMIPMAP && level)
+    {
+        WARN("D3DUSAGE_AUTOGENMIPMAP textures have only one accessible level.\n");
+        return D3DERR_INVALIDCALL;
+    }
+
     wined3d_mutex_lock();
     sub_resource_idx = wined3d_texture_get_level_count(texture->wined3d_texture) * face + level;
     if (!(surface_impl = wined3d_texture_get_sub_resource_parent(texture->wined3d_texture, sub_resource_idx)))
@@ -753,6 +879,12 @@ static HRESULT WINAPI d3d9_texture_cube_UnlockRect(IDirect3DCubeTexture9 *iface,
 
     TRACE("iface %p, face %#x, level %u.\n", iface, face, level);
 
+    if (texture->usage & D3DUSAGE_AUTOGENMIPMAP && level)
+    {
+        WARN("D3DUSAGE_AUTOGENMIPMAP textures have only one accessible level.\n");
+        return D3DERR_INVALIDCALL;
+    }
+
     wined3d_mutex_lock();
     sub_resource_idx = wined3d_texture_get_level_count(texture->wined3d_texture) * face + level;
     if (!(surface_impl = wined3d_texture_get_sub_resource_parent(texture->wined3d_texture, sub_resource_idx)))
@@ -1014,31 +1146,16 @@ static DWORD WINAPI d3d9_texture_3d_GetLevelCount(IDirect3DVolumeTexture9 *iface
 static HRESULT WINAPI d3d9_texture_3d_SetAutoGenFilterType(IDirect3DVolumeTexture9 *iface,
         D3DTEXTUREFILTERTYPE filter_type)
 {
-    struct d3d9_texture *texture = impl_from_IDirect3DVolumeTexture9(iface);
-    HRESULT hr;
-
     TRACE("iface %p, filter_type %#x.\n", iface, filter_type);
 
-    wined3d_mutex_lock();
-    hr = wined3d_texture_set_autogen_filter_type(texture->wined3d_texture,
-            (enum wined3d_texture_filter_type)filter_type);
-    wined3d_mutex_unlock();
-
-    return hr;
+    return D3DERR_INVALIDCALL;
 }
 
 static D3DTEXTUREFILTERTYPE WINAPI d3d9_texture_3d_GetAutoGenFilterType(IDirect3DVolumeTexture9 *iface)
 {
-    struct d3d9_texture *texture = impl_from_IDirect3DVolumeTexture9(iface);
-    D3DTEXTUREFILTERTYPE filter_type;
-
     TRACE("iface %p.\n", iface);
 
-    wined3d_mutex_lock();
-    filter_type = (D3DTEXTUREFILTERTYPE)wined3d_texture_get_autogen_filter_type(texture->wined3d_texture);
-    wined3d_mutex_unlock();
-
-    return filter_type;
+    return D3DTEXF_NONE;
 }
 
 static void WINAPI d3d9_texture_3d_GenerateMipSubLevels(IDirect3DVolumeTexture9 *iface)
@@ -1059,7 +1176,7 @@ static HRESULT WINAPI d3d9_texture_3d_GetLevelDesc(IDirect3DVolumeTexture9 *ifac
     {
         desc->Format = d3dformat_from_wined3dformat(wined3d_desc.format);
         desc->Type = D3DRTYPE_VOLUME;
-        desc->Usage = d3dusage_from_wined3dusage(wined3d_desc.usage);
+        desc->Usage = texture->usage;
         desc->Pool = d3dpool_from_wined3daccess(wined3d_desc.access, wined3d_desc.usage);
         desc->Width = wined3d_desc.width;
         desc->Height = wined3d_desc.height;
@@ -1213,12 +1330,13 @@ HRESULT texture_init(struct d3d9_texture *texture, struct d3d9_device *device,
     texture->IDirect3DBaseTexture9_iface.lpVtbl = (const IDirect3DBaseTexture9Vtbl *)&d3d9_texture_2d_vtbl;
     d3d9_resource_init(&texture->resource);
     list_init(&texture->rtv_list);
+    texture->usage = usage;
 
     desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
     desc.format = wined3dformat_from_d3dformat(format);
     desc.multisample_type = WINED3D_MULTISAMPLE_NONE;
     desc.multisample_quality = 0;
-    desc.usage = usage & WINED3DUSAGE_MASK;
+    desc.usage = wined3dusage_from_d3dusage(usage);
     desc.usage |= WINED3DUSAGE_TEXTURE;
     if (pool == D3DPOOL_SCRATCH)
         desc.usage |= WINED3DUSAGE_SCRATCH;
@@ -1234,13 +1352,28 @@ HRESULT texture_init(struct d3d9_texture *texture, struct d3d9_device *device,
     if (is_gdi_compat_wined3dformat(desc.format))
         flags |= WINED3D_TEXTURE_CREATE_GET_DC;
 
-    if (!levels)
+    if (usage & D3DUSAGE_AUTOGENMIPMAP)
+    {
+        if (pool == D3DPOOL_SYSTEMMEM)
+        {
+            WARN("D3DUSAGE_AUTOGENMIPMAP texture can't be in D3DPOOL_SYSTEMMEM, returning D3DERR_INVALIDCALL.\n");
+            return D3DERR_INVALIDCALL;
+        }
+        if (levels && levels != 1)
+        {
+            WARN("D3DUSAGE_AUTOGENMIPMAP texture with %u levels, returning D3DERR_INVALIDCALL.\n", levels);
+            return D3DERR_INVALIDCALL;
+        }
+        flags |= WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS;
+        texture->autogen_filter_type = D3DTEXF_LINEAR;
+        levels = 0;
+    }
+    else
     {
-        if (usage & D3DUSAGE_AUTOGENMIPMAP)
-            levels = 1;
-        else
-            levels = wined3d_log2i(max(width, height)) + 1;
+        texture->autogen_filter_type = D3DTEXF_NONE;
     }
+    if (!levels)
+        levels = wined3d_log2i(max(width, height)) + 1;
 
     wined3d_mutex_lock();
     hr = wined3d_texture_create(device->wined3d_device, &desc, 1, levels, flags,
@@ -1268,12 +1401,13 @@ HRESULT cubetexture_init(struct d3d9_texture *texture, struct d3d9_device *devic
     texture->IDirect3DBaseTexture9_iface.lpVtbl = (const IDirect3DBaseTexture9Vtbl *)&d3d9_texture_cube_vtbl;
     d3d9_resource_init(&texture->resource);
     list_init(&texture->rtv_list);
+    texture->usage = usage;
 
     desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
     desc.format = wined3dformat_from_d3dformat(format);
     desc.multisample_type = WINED3D_MULTISAMPLE_NONE;
     desc.multisample_quality = 0;
-    desc.usage = usage & WINED3DUSAGE_MASK;
+    desc.usage = wined3dusage_from_d3dusage(usage);
     desc.usage |= WINED3DUSAGE_LEGACY_CUBEMAP | WINED3DUSAGE_TEXTURE;
     if (pool == D3DPOOL_SCRATCH)
         desc.usage |= WINED3DUSAGE_SCRATCH;
@@ -1289,13 +1423,28 @@ HRESULT cubetexture_init(struct d3d9_texture *texture, struct d3d9_device *devic
     if (is_gdi_compat_wined3dformat(desc.format))
         flags |= WINED3D_TEXTURE_CREATE_GET_DC;
 
-    if (!levels)
+    if (usage & D3DUSAGE_AUTOGENMIPMAP)
     {
-        if (usage & D3DUSAGE_AUTOGENMIPMAP)
-            levels = 1;
-        else
-            levels = wined3d_log2i(edge_length) + 1;
+        if (pool == D3DPOOL_SYSTEMMEM)
+        {
+            WARN("D3DUSAGE_AUTOGENMIPMAP texture can't be in D3DPOOL_SYSTEMMEM, returning D3DERR_INVALIDCALL.\n");
+            return D3DERR_INVALIDCALL;
+        }
+        if (levels && levels != 1)
+        {
+            WARN("D3DUSAGE_AUTOGENMIPMAP texture with %u levels, returning D3DERR_INVALIDCALL.\n", levels);
+            return D3DERR_INVALIDCALL;
+        }
+        flags |= WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS;
+        texture->autogen_filter_type = D3DTEXF_LINEAR;
+        levels = 0;
     }
+    else
+    {
+        texture->autogen_filter_type = D3DTEXF_NONE;
+    }
+    if (!levels)
+        levels = wined3d_log2i(edge_length) + 1;
 
     wined3d_mutex_lock();
     hr = wined3d_texture_create(device->wined3d_device, &desc, 6, levels, flags,
@@ -1322,12 +1471,13 @@ HRESULT volumetexture_init(struct d3d9_texture *texture, struct d3d9_device *dev
     texture->IDirect3DBaseTexture9_iface.lpVtbl = (const IDirect3DBaseTexture9Vtbl *)&d3d9_texture_3d_vtbl;
     d3d9_resource_init(&texture->resource);
     list_init(&texture->rtv_list);
+    texture->usage = usage;
 
     desc.resource_type = WINED3D_RTYPE_TEXTURE_3D;
     desc.format = wined3dformat_from_d3dformat(format);
     desc.multisample_type = WINED3D_MULTISAMPLE_NONE;
     desc.multisample_quality = 0;
-    desc.usage = usage & WINED3DUSAGE_MASK;
+    desc.usage = wined3dusage_from_d3dusage(usage);
     desc.usage |= WINED3DUSAGE_TEXTURE;
     if (pool == D3DPOOL_SCRATCH)
         desc.usage |= WINED3DUSAGE_SCRATCH;
@@ -1337,13 +1487,13 @@ HRESULT volumetexture_init(struct d3d9_texture *texture, struct d3d9_device *dev
     desc.depth = depth;
     desc.size = 0;
 
-    if (!levels)
+    if (usage & D3DUSAGE_AUTOGENMIPMAP)
     {
-        if (usage & D3DUSAGE_AUTOGENMIPMAP)
-            levels = 1;
-        else
-            levels = wined3d_log2i(max(max(width, height), depth)) + 1;
+        WARN("D3DUSAGE_AUTOGENMIPMAP volume texture is not supported, returning D3DERR_INVALIDCALL.\n");
+        return D3DERR_INVALIDCALL;
     }
+    if (!levels)
+        levels = wined3d_log2i(max(max(width, height), depth)) + 1;
 
     wined3d_mutex_lock();
     hr = wined3d_texture_create(device->wined3d_device, &desc, 1, levels, 0,
-- 
2.13.6




More information about the wine-devel mailing list