diff options
author | Hans-Kristian Arntzen <post@arntzen-software.no> | 2021-11-29 14:38:42 +0300 |
---|---|---|
committer | Arkadiusz Hiler <ahiler@codeweavers.com> | 2021-12-20 12:59:12 +0300 |
commit | daf8732546b1538e4882dcfab9fcff9a479f7d67 (patch) | |
tree | 5d5fddaf677ab49b9d3c52fbce1b70ee3d007732 | |
parent | c0a3fa8adc589454a05ee2dd28430cae73b67890 (diff) |
vkd3d: Workaround broken barriers in DEATHLOOP.deathloop-broken-barriers-workaround
In DEATHLOOP, there is a render pass which renders out a simple image,
which is then directly followed by a compute dispatch, reading that
image. The image is still in RENDER_TARGET state, and color buffers are
*not* flushed properly on at least RADV, manifesting as a very
distracting glitch pattern. This is a game bug, but for the time being,
we have to workaround it, *sigh*.
For a simple workaround, we can detect patterns where we see these
events in succession:
- Color RT is started
- StateBefore == RENDER_TARGET is not observed
- Dispatch()
In particular, when entering the options menu, highly distracting
glitches are observed in the background.
Signed-off-by: Hans-Kristian Arntzen <post@arntzen-software.no>
-rw-r--r-- | include/vkd3d.h | 1 | ||||
-rw-r--r-- | libs/vkd3d/command.c | 34 | ||||
-rw-r--r-- | libs/vkd3d/device.c | 4 | ||||
-rw-r--r-- | libs/vkd3d/vkd3d_private.h | 8 |
4 files changed, 46 insertions, 1 deletions
diff --git a/include/vkd3d.h b/include/vkd3d.h index 274ab301..07a5ea7e 100644 --- a/include/vkd3d.h +++ b/include/vkd3d.h @@ -76,6 +76,7 @@ enum vkd3d_config_flags VKD3D_CONFIG_FLAG_FORCE_HOST_CACHED = 0x00002000, VKD3D_CONFIG_FLAG_DXR11 = 0x00004000, VKD3D_CONFIG_FLAG_FORCE_NO_INVARIANT_POSITION = 0x00008000, + VKD3D_CONFIG_FLAG_WORKAROUND_MISSING_COLOR_COMPUTE_BARRIERS = 0x00010000, }; typedef HRESULT (*PFN_vkd3d_signal_event)(HANDLE event); diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index f14ca3ec..0956ab07 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -2891,6 +2891,8 @@ static void d3d12_command_list_emit_render_pass_transition(struct d3d12_command_ stage_mask |= new_stages; j++; } + + list->workaround_state.has_pending_color_write = true; } dsv = &list->dsv; @@ -4287,6 +4289,8 @@ static void d3d12_command_list_reset_api_state(struct d3d12_command_list *list, list->cbv_srv_uav_descriptors = NULL; list->vrs_image = NULL; + list->workaround_state.has_pending_color_write = false; + ID3D12GraphicsCommandList_SetPipelineState(iface, initial_pipeline_state); } @@ -5528,6 +5532,31 @@ static void STDMETHODCALLTYPE d3d12_command_list_DrawIndexedInstanced(d3d12_comm VK_CALL(vkCmdDrawIndexedIndirect(list->vk_command_buffer, scratch.buffer, scratch.offset, 1, 0)); } +static void d3d12_command_list_workaround_handle_missing_color_compute_barriers(struct d3d12_command_list *list) +{ + const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs; + VkMemoryBarrier barrier; + + if (list->workaround_state.has_pending_color_write && + (vkd3d_config_flags & VKD3D_CONFIG_FLAG_WORKAROUND_MISSING_COLOR_COMPUTE_BARRIERS)) + { + /* Very specifically, every render pass which writes color sets + * has_pending_color_write = true. + * If we observe a StateBefore == RENDER_TARGET, clear the flag. + * If we come to a plain dispatch with this flag set, + * insert a simple memory barrier. The image will still have wrong layout, + * but this is good enough to workaround the game bug. */ + barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + barrier.pNext = NULL; + barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, 0, NULL, 0, NULL)); + list->workaround_state.has_pending_color_write = false; + WARN("Injecting workaround barrier!\n"); + } +} + static void STDMETHODCALLTYPE d3d12_command_list_Dispatch(d3d12_command_list_iface *iface, UINT x, UINT y, UINT z) { @@ -5554,6 +5583,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_Dispatch(d3d12_command_list_ifa return; } + d3d12_command_list_workaround_handle_missing_color_compute_barriers(list); + if (!list->predicate_va) VK_CALL(vkCmdDispatch(list->vk_command_buffer, x, y, z)); else @@ -6952,6 +6983,9 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(d3d12_command_l VkImageLayout old_layout = VK_IMAGE_LAYOUT_UNDEFINED; VkImageLayout new_layout = VK_IMAGE_LAYOUT_UNDEFINED; + if (transition->StateBefore == D3D12_RESOURCE_STATE_RENDER_TARGET) + list->workaround_state.has_pending_color_write = false; + if (!is_valid_resource_state(transition->StateBefore)) { d3d12_command_list_mark_as_invalid(list, diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index 2b7ae2e5..e4f0c6fc 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -478,7 +478,9 @@ struct vkd3d_instance_application_meta static const struct vkd3d_instance_application_meta application_override[] = { /* MSVC fails to compile empty array. */ { VKD3D_STRING_COMPARE_EXACT, "GravityMark.exe", VKD3D_CONFIG_FLAG_FORCE_MINIMUM_SUBGROUP_SIZE, 0 }, - { VKD3D_STRING_COMPARE_EXACT, "Deathloop.exe", VKD3D_CONFIG_FLAG_IGNORE_RTV_HOST_VISIBLE, 0 }, + /* The game forgets to do a barrier when going from render pass to compute. */ + { VKD3D_STRING_COMPARE_EXACT, "Deathloop.exe", + VKD3D_CONFIG_FLAG_IGNORE_RTV_HOST_VISIBLE | VKD3D_CONFIG_FLAG_WORKAROUND_MISSING_COLOR_COMPUTE_BARRIERS, 0 }, /* Shadow of the Tomb Raider (750920). * Invariant workarounds actually cause more issues than they resolve on NV. * RADV already has workarounds by default. diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 5e1d650b..e9e117bb 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -1973,6 +1973,14 @@ struct d3d12_command_list size_t dsv_resource_tracking_count; size_t dsv_resource_tracking_size; + /* Hackery needed for game workarounds. */ + struct + { + /* Used to keep track of COLOR write -> COMPUTE where game forget to insert barrier + * before the dispatch. */ + bool has_pending_color_write; + } workaround_state; + struct vkd3d_private_store private_store; }; |