From: Paul Gofman Subject: [PATCH 3/3] wined3d: Track SRV to RTV aliasing on sub resource level. Message-Id: <20200922191122.728183-3-pgofman@codeweavers.com> Date: Tue, 22 Sep 2020 22:11:22 +0300 In-Reply-To: <20200922191122.728183-1-pgofman@codeweavers.com> References: <20200922191122.728183-1-pgofman@codeweavers.com> Signed-off-by: Paul Gofman --- 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