[PATCH 3/3] wined3d: Track SRV to RTV aliasing on sub resource level.

Paul Gofman pgofman at codeweavers.com
Tue Sep 22 14:11:22 CDT 2020


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 dlls/d3d11/tests/d3d11.c       | 70 ++++++++++++++++++++++---
 dlls/wined3d/device.c          | 30 +++++++++--
 dlls/wined3d/stateblock.c      |  2 +-
 dlls/wined3d/wined3d_private.h | 96 ++++++++++++++++++++++++++++++++++
 4 files changed, 186 insertions(+), 12 deletions(-)

diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c
index 67d843ae9e5..afdb3a085c7 100644
--- a/dlls/d3d11/tests/d3d11.c
+++ b/dlls/d3d11/tests/d3d11.c
@@ -29453,12 +29453,13 @@ static void test_desktop_window(void)
 
 static void test_sample_attached_rtv(void)
 {
-    ID3D11ShaderResourceView *srv, *srv_test, *srv_ds;
+    ID3D11ShaderResourceView *srv, *srv2, *srv_test, *srv_ds;
+    D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc, srvds_desc;
     ID3D11Texture2D *texture, *texture2, *dstexture;
-    D3D11_SHADER_RESOURCE_VIEW_DESC srvds_desc;
+    ID3D11RenderTargetView *rtv, *rtv2, *rtvs[2];
     D3D11_DEPTH_STENCIL_VIEW_DESC dsview_desc;
     struct d3d11_test_context test_context;
-    ID3D11RenderTargetView *rtv, *rtvs[2];
+    D3D11_RENDER_TARGET_VIEW_DESC rtv_desc;
     D3D11_TEXTURE2D_DESC texture_desc;
     D3D_FEATURE_LEVEL feature_level;
     D3D11_SAMPLER_DESC sampler_desc;
@@ -29472,6 +29473,7 @@ static void test_sample_attached_rtv(void)
     ID3D11Device *device;
     unsigned int x, y;
     unsigned int i;
+    D3D11_BOX box;
     DWORD color;
     HRESULT hr;
 
@@ -29574,7 +29576,7 @@ static void test_sample_attached_rtv(void)
 
     texture_desc.Width = 64;
     texture_desc.Height = 64;
-    texture_desc.MipLevels = 1;
+    texture_desc.MipLevels = 2;
     texture_desc.ArraySize = 1;
     texture_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
 
@@ -29598,7 +29600,15 @@ static void test_sample_attached_rtv(void)
 
     ID3D11DeviceContext_ClearRenderTargetView(context, test_context.backbuffer_rtv, red);
 
-    hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)texture2, NULL, &rtv);
+    memset(&rtv_desc, 0, sizeof(rtv_desc));
+    rtv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+    rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+    U(rtv_desc).Texture2D.MipSlice = 0;
+
+    hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)texture2, &rtv_desc, &rtv);
+    ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+    U(rtv_desc).Texture2D.MipSlice = 1;
+    hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)texture2, &rtv_desc, &rtv2);
     ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
 
     rtvs[0] = test_context.backbuffer_rtv;
@@ -29606,12 +29616,20 @@ static void test_sample_attached_rtv(void)
 
     ID3D11DeviceContext_OMSetRenderTargets(context, 2, rtvs, NULL);
 
-    hr = ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource *)texture, NULL, &srv);
+    memset(&srv_desc, 0, sizeof(srv_desc));
+    srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+    srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+    U(srv_desc).Texture2D.MipLevels = 1;
+
+    hr = ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource *)texture, &srv_desc, &srv);
     ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
     ID3D11DeviceContext_PSSetShaderResources(context, 0, 1, &srv);
 
     draw_quad(&test_context);
 
+    set_box(&box, 0, 0, 0, 320, 240, 1);
+    ID3D11DeviceContext_CopySubresourceRegion(context, (ID3D11Resource *)texture2, 1, 0, 0, 0, (ID3D11Resource *)texture2, 0, &box);
+
     get_texture_readback(texture2, 0, &rb);
     for (y = 0; y < 4; ++y)
     {
@@ -29623,12 +29641,29 @@ static void test_sample_attached_rtv(void)
         }
     }
     release_resource_readback(&rb);
+    get_texture_readback(texture2, 1, &rb);
+    for (y = 0; y < 4; ++y)
+    {
+        for (x = 0; x < 4; ++x)
+        {
+            color = get_readback_color(&rb, 40 + x * 80, 30 + y * 60, 0);
+            ok(compare_color(color, 0x40404040, 2),
+                    "Got unexpected color 0x%08x at (%u, %u).\n", color, x, y);
+        }
+    }
+    release_resource_readback(&rb);
 
     ID3D11ShaderResourceView_Release(srv);
+    ID3D11DeviceContext_OMSetRenderTargets(context, 2, rtvs, NULL);
 
     ID3D11DeviceContext_ClearRenderTargetView(context, rtv, red);
 
-    hr = ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource *)texture2, NULL, &srv);
+    hr = ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource *)texture2, &srv_desc, &srv);
+    ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+    U(srv_desc).Texture2D.MostDetailedMip = 1;
+    U(srv_desc).Texture2D.MipLevels = 1;
+    hr = ID3D11Device_CreateShaderResourceView(device, (ID3D11Resource *)texture2, &srv_desc, &srv2);
     ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
 
     memset(&blend_desc, 0, sizeof(blend_desc));
@@ -29705,6 +29740,25 @@ static void test_sample_attached_rtv(void)
     ID3D11DeviceContext_PSGetShaderResources(context, 0, 1, &srv_test);
     ok(!srv_test, "Unexpected SRV %p.\n", srv_test);
 
+    ID3D11DeviceContext_PSSetShaderResources(context, 0, 1, &srv2);
+    ID3D11DeviceContext_OMSetRenderTargets(context, 2, rtvs, NULL);
+    ID3D11DeviceContext_PSGetShaderResources(context, 0, 1, &srv_test);
+    ok(!!srv_test, "Unexpected SRV %p.\n", srv_test);
+    ID3D11ShaderResourceView_Release(srv_test);
+
+    draw_quad(&test_context);
+    get_texture_readback(test_context.backbuffer, 0, &rb);
+    for (y = 0; y < 4; ++y)
+    {
+        for (x = 0; x < 4; ++x)
+        {
+            color = get_readback_color(&rb, 80 + x * 160, 60 + y * 120, 0);
+            ok(compare_color(color, 0x80808080, 2),
+                    "Got unexpected color 0x%08x at (%u, %u).\n", color, x, y);
+        }
+    }
+    release_resource_readback(&rb);
+
     texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DEPTH_STENCIL;
     memset(&dsview_desc, 0, sizeof(dsview_desc));
     dsview_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
@@ -29762,7 +29816,9 @@ static void test_sample_attached_rtv(void)
 
     ID3D11DeviceContext_OMSetRenderTargets(context, 2, rtvs, NULL);
 
+    ID3D11RenderTargetView_Release(rtv2);
     ID3D11RenderTargetView_Release(rtv);
+    ID3D11ShaderResourceView_Release(srv2);
     ID3D11ShaderResourceView_Release(srv);
     ID3D11SamplerState_Release(sampler);
     ID3D11PixelShader_Release(ps);
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 8327ef17dc8..6828c20acc0 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -1965,7 +1965,7 @@ static void wined3d_device_set_shader_resource_view(struct wined3d_device *devic
     if (view == prev)
         return;
 
-    if (view && (view->resource->rtv_bind_count_device
+    if (view && (wined3d_is_srv_rtv_bound(view)
             || ((dsv = device->state.fb.depth_stencil)
             && dsv->resource == view->resource && wined3d_dsv_srv_conflict(dsv, view->format))))
     {
@@ -1976,14 +1976,14 @@ static void wined3d_device_set_shader_resource_view(struct wined3d_device *devic
     if (view)
     {
         wined3d_shader_resource_view_incref(view);
-        ++view->resource->srv_bind_count_device;
+        wined3d_inc_srv_bind_count(view);
     }
 
     device->state.shader_resource_view[type][idx] = view;
     wined3d_cs_emit_set_shader_resource_view(device->cs, type, idx, view);
     if (prev)
     {
-        --prev->resource->srv_bind_count_device;
+        wined3d_dec_srv_bind_count(prev);
         wined3d_shader_resource_view_decref(prev);
     }
 }
@@ -4817,19 +4817,41 @@ struct wined3d_rendertarget_view * CDECL wined3d_device_get_depth_stencil_view(c
 static void wined3d_unbind_srv_for_rtv(struct wined3d_device *device,
         const struct wined3d_rendertarget_view *view, BOOL dsv)
 {
-    if (view && view->resource->srv_bind_count_device)
+    if (view && wined3d_is_rtv_srv_bound(view))
     {
         const struct wined3d_resource *resource = view->resource;
         const struct wined3d_shader_resource_view *srv;
+        unsigned int level, start_layer, layer_count;
         unsigned int i, j;
 
         WARN("Application sets bound resource as render target.\n");
 
+        if (resource->type != WINED3D_RTYPE_BUFFER)
+        {
+            struct wined3d_texture *texture = texture_from_resource(view->resource);
+
+            level = view->sub_resource_idx % texture->level_count;
+            start_layer = view->sub_resource_idx / texture->level_count;
+            layer_count = view->layer_count;
+        }
+        else
+        {
+            level = start_layer = layer_count = 0;
+        }
+
         for (i = 0; i < WINED3D_SHADER_TYPE_COUNT; ++i)
             for (j = 0; j < MAX_SHADER_RESOURCE_VIEWS; ++j)
                 if ((srv = device->state.shader_resource_view[i][j]) && srv->resource == resource
                         && (!dsv || wined3d_dsv_srv_conflict(view, srv->format)))
+                {
+                    if (resource->type != WINED3D_RTYPE_BUFFER && (level < srv->desc.u.texture.level_idx
+                            || level >= srv->desc.u.texture.level_idx + srv->desc.u.texture.level_count
+                            || start_layer >= srv->desc.u.texture.layer_idx + srv->desc.u.texture.layer_count
+                            || start_layer + layer_count <= srv->desc.u.texture.layer_idx))
+                        continue;
+
                     wined3d_device_set_shader_resource_view(device, i, j, NULL);
+                }
     }
 }
 
diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c
index e7deb2464db..e83f43dd354 100644
--- a/dlls/wined3d/stateblock.c
+++ b/dlls/wined3d/stateblock.c
@@ -450,7 +450,7 @@ void state_unbind_resources(struct wined3d_state *state)
             if ((srv = state->shader_resource_view[i][j]))
             {
                 state->shader_resource_view[i][j] = NULL;
-                --srv->resource->srv_bind_count_device;
+                wined3d_dec_srv_bind_count(srv);
                 wined3d_shader_resource_view_decref(srv);
             }
         }
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 05ac6949ca3..f895da00d63 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -4152,6 +4152,8 @@ struct wined3d_texture
         struct wined3d_bo_gl bo;
 
         void *user_memory;
+        LONG srv_bind_count_device;
+        LONG rtv_bind_count_device;
     } *sub_resources;
 };
 
@@ -5997,14 +5999,108 @@ static inline BOOL wined3d_dsv_srv_conflict(const struct wined3d_rendertarget_vi
             || (srv_format->green_size && !(dsv->desc.flags & WINED3D_VIEW_READ_ONLY_STENCIL));
 }
 
+static inline void wined3d_inc_srv_bind_count(struct wined3d_shader_resource_view *srv)
+{
+    struct wined3d_texture *texture;
+    unsigned int level, layer;
+
+    ++srv->resource->srv_bind_count_device;
+
+    if (srv->resource->type == WINED3D_RTYPE_BUFFER)
+        return;
+
+    texture = texture_from_resource(srv->resource);
+
+    for (layer = 0; layer < srv->desc.u.texture.layer_count; ++layer)
+        for (level = 0; level < srv->desc.u.texture.level_count; ++level)
+            ++texture->sub_resources[(layer + srv->desc.u.texture.layer_idx) * texture->level_count
+                    + srv->desc.u.texture.level_idx + level].srv_bind_count_device;
+}
+
+static inline void wined3d_dec_srv_bind_count(struct wined3d_shader_resource_view *srv)
+{
+    struct wined3d_texture *texture;
+    unsigned int level, layer;
+
+    --srv->resource->srv_bind_count_device;
+
+    if (srv->resource->type == WINED3D_RTYPE_BUFFER)
+        return;
+
+    texture = texture_from_resource(srv->resource);
+
+    for (layer = 0; layer < srv->desc.u.texture.layer_count; ++layer)
+        for (level = 0; level < srv->desc.u.texture.level_count; ++level)
+            --texture->sub_resources[(layer + srv->desc.u.texture.layer_idx) * texture->level_count
+                    + srv->desc.u.texture.level_idx + level].srv_bind_count_device;
+}
+
 static inline void wined3d_inc_rtv_bind_count(struct wined3d_rendertarget_view *rt)
 {
+    struct wined3d_texture *texture;
+    unsigned int layer;
+
     ++rt->resource->rtv_bind_count_device;
+
+    if (rt->resource->type == WINED3D_RTYPE_BUFFER)
+        return;
+
+    texture = texture_from_resource(rt->resource);
+
+    for (layer = 0; layer < rt->layer_count; ++layer)
+        ++texture->sub_resources[rt->sub_resource_idx + layer * texture->level_count].rtv_bind_count_device;
 }
 
 static inline void wined3d_dec_rtv_bind_count(struct wined3d_rendertarget_view *rt)
 {
+    struct wined3d_texture *texture;
+    unsigned int layer;
+
     --rt->resource->rtv_bind_count_device;
+
+    if (rt->resource->type == WINED3D_RTYPE_BUFFER)
+        return;
+
+    texture = texture_from_resource(rt->resource);
+
+    for (layer = 0; layer < rt->layer_count; ++layer)
+        --texture->sub_resources[rt->sub_resource_idx + layer * texture->level_count].rtv_bind_count_device;
+}
+
+static inline BOOL wined3d_is_srv_rtv_bound(const struct wined3d_shader_resource_view *srv)
+{
+    struct wined3d_texture *texture;
+    unsigned int level, layer;
+
+    if (!srv->resource->rtv_bind_count_device || srv->resource->type == WINED3D_RTYPE_BUFFER)
+        return srv->resource->rtv_bind_count_device;
+
+    texture = texture_from_resource(srv->resource);
+
+    for (layer = 0; layer < srv->desc.u.texture.layer_count; ++layer)
+        for (level = 0; level < srv->desc.u.texture.level_count; ++level)
+            if (texture->sub_resources[(layer + srv->desc.u.texture.layer_idx) * texture->level_count
+                    + srv->desc.u.texture.level_idx + level].rtv_bind_count_device)
+                return TRUE;
+
+    return FALSE;
+}
+
+static inline BOOL wined3d_is_rtv_srv_bound(const struct wined3d_rendertarget_view *rt)
+{
+    struct wined3d_texture *texture;
+    unsigned int layer;
+
+    if (!rt->resource->srv_bind_count_device || rt->resource->type == WINED3D_RTYPE_BUFFER)
+        return rt->resource->srv_bind_count_device;
+
+    texture = texture_from_resource(rt->resource);
+
+    for (layer = 0; layer < rt->layer_count; ++layer)
+        if (texture->sub_resources[rt->sub_resource_idx + layer * texture->level_count].srv_bind_count_device)
+            return TRUE;
+
+    return FALSE;
 }
 
 static inline void wined3d_viewport_get_z_range(const struct wined3d_viewport *vp, float *min_z, float *max_z)
-- 
2.26.2




More information about the wine-devel mailing list