vkd3d: Add barriers between render passes to the same image.

This commit is contained in:
Evan Tang
2025-10-20 14:27:59 -05:00
committed by Henri Verbeet
parent f47f712164
commit a5ac959cf5
Notes: Henri Verbeet 2025-11-24 19:12:52 +01:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1825
2 changed files with 155 additions and 2 deletions

View File

@@ -31,6 +31,43 @@ static void d3d12_command_queue_submit_locked(struct d3d12_command_queue *queue)
static HRESULT d3d12_command_queue_flush_ops(struct d3d12_command_queue *queue, bool *flushed_any);
static HRESULT d3d12_command_queue_flush_ops_locked(struct d3d12_command_queue *queue, bool *flushed_any);
static void vkd3d_resource_list_cleanup(struct vkd3d_resource_list *list)
{
vkd3d_free(list->resources);
}
static void vkd3d_resource_list_init(struct vkd3d_resource_list *list)
{
list->resources = NULL;
list->count = 0;
list->capacity = 0;
}
static bool vkd3d_resource_list_contains(const struct vkd3d_resource_list *list, struct d3d12_resource *resource)
{
size_t i;
for (i = 0; i < list->count; i++)
{
if (list->resources[i] == resource)
return true;
}
return false;
}
static void vkd3d_resource_list_append(struct vkd3d_resource_list *list, struct d3d12_resource *resource)
{
if (!vkd3d_array_reserve((void **)&list->resources, &list->capacity, list->count + 1, sizeof(*list->resources)))
ERR("Failed to grow resource list.\n");
list->resources[list->count++] = resource;
}
static void vkd3d_resource_list_clear(struct vkd3d_resource_list *list)
{
list->count = 0;
}
static void vkd3d_null_event_signal(struct vkd3d_null_event *e)
{
vkd3d_mutex_lock(&e->mutex);
@@ -2533,6 +2570,9 @@ static ULONG STDMETHODCALLTYPE d3d12_command_list_Release(ID3D12GraphicsCommandL
vkd3d_pipeline_bindings_cleanup(&list->pipeline_bindings[VKD3D_PIPELINE_BIND_POINT_COMPUTE]);
vkd3d_pipeline_bindings_cleanup(&list->pipeline_bindings[VKD3D_PIPELINE_BIND_POINT_GRAPHICS]);
vkd3d_resource_list_cleanup(&list->rtv_resources_since_last_barrier);
vkd3d_resource_list_cleanup(&list->dsv_resources_since_last_barrier);
vkd3d_free(list);
d3d12_device_release(device);
@@ -2659,6 +2699,10 @@ static void d3d12_command_list_reset_state(struct d3d12_command_list *list,
list->fb_width = 0;
list->fb_height = 0;
list->fb_layer_count = 0;
memset(list->rtv_resources, 0, sizeof(list->rtv_resources));
list->dsv_resource = NULL;
vkd3d_resource_list_clear(&list->rtv_resources_since_last_barrier);
vkd3d_resource_list_clear(&list->dsv_resources_since_last_barrier);
list->xfb_enabled = false;
list->has_depth_bounds = false;
@@ -3469,6 +3513,82 @@ static bool d3d12_command_list_update_compute_state(struct d3d12_command_list *l
return true;
}
/* Add a barrier to prevent hazards between multiple render passes to the same image. */
static void d3d12_command_list_emit_rt_barrier(struct d3d12_command_list *list, bool colour, bool depth)
{
const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
VkMemoryBarrier barrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER };
VkPipelineStageFlags srcStage = 0;
VkPipelineStageFlags dstStage = 0;
if (colour)
{
srcStage |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dstStage |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
barrier.srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
}
if (depth)
{
srcStage |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dstStage |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
barrier.srcAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
barrier.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
}
VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer, srcStage, dstStage,
VK_DEPENDENCY_BY_REGION_BIT, 1, &barrier, 0, NULL, 0, NULL));
if (colour)
vkd3d_resource_list_clear(&list->rtv_resources_since_last_barrier);
if (depth)
vkd3d_resource_list_clear(&list->rtv_resources_since_last_barrier);
}
static void d3d12_command_list_check_render_pass_hazards(struct d3d12_command_list *list)
{
struct d3d12_graphics_pipeline_state *graphics = &list->state->u.graphics;
bool rtv_hazard = false;
bool dsv_hazard = false;
unsigned int i;
for (i = 0; i < graphics->rt_count; ++i)
{
if (graphics->null_attachment_mask & (1u << i))
continue;
if (!list->rtv_resources[i])
continue;
if (vkd3d_resource_list_contains(&list->rtv_resources_since_last_barrier, list->rtv_resources[i]))
{
rtv_hazard = true;
break;
}
}
dsv_hazard = d3d12_command_list_has_depth_stencil_view(list) && list->dsv_resource
&& vkd3d_resource_list_contains(&list->dsv_resources_since_last_barrier, list->dsv_resource);
if (rtv_hazard || dsv_hazard)
d3d12_command_list_emit_rt_barrier(list, rtv_hazard, dsv_hazard);
for (i = 0; i < graphics->rt_count; ++i)
{
if (graphics->null_attachment_mask & (1u << i))
continue;
if (!list->rtv_resources[i])
continue;
vkd3d_resource_list_append(&list->rtv_resources_since_last_barrier, list->rtv_resources[i]);
}
if (d3d12_command_list_has_depth_stencil_view(list) && list->dsv_resource)
vkd3d_resource_list_append(&list->dsv_resources_since_last_barrier, list->dsv_resource);
}
static bool d3d12_command_list_begin_render_pass(struct d3d12_command_list *list)
{
const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs;
@@ -3486,6 +3606,8 @@ static bool d3d12_command_list_begin_render_pass(struct d3d12_command_list *list
if (list->current_render_pass != VK_NULL_HANDLE)
return true;
d3d12_command_list_check_render_pass_hazards(list);
vk_render_pass = list->pso_render_pass;
VKD3D_ASSERT(vk_render_pass);
@@ -5137,6 +5259,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12Graphi
{
WARN("RTV descriptor %u is not initialized.\n", i);
list->rtvs[i] = VK_NULL_HANDLE;
list->rtv_resources[i] = NULL;
continue;
}
@@ -5150,6 +5273,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12Graphi
}
list->rtvs[i] = view->v.u.vk_image_view;
list->rtv_resources[i] = rtv_desc->resource;
list->fb_width = max(list->fb_width, rtv_desc->width);
list->fb_height = max(list->fb_height, rtv_desc->height);
list->fb_layer_count = max(list->fb_layer_count, rtv_desc->layer_count);
@@ -5171,9 +5295,11 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12Graphi
{
WARN("Failed to add view.\n");
list->dsv = VK_NULL_HANDLE;
list->dsv_resource = NULL;
}
list->dsv = view->v.u.vk_image_view;
list->dsv_resource = dsv_desc->resource;
list->fb_width = max(list->fb_width, dsv_desc->width);
list->fb_height = max(list->fb_height, dsv_desc->height);
list->fb_layer_count = max(list->fb_layer_count, dsv_desc->layer_count);
@@ -5209,8 +5335,6 @@ static void d3d12_command_list_clear(struct d3d12_command_list *list,
unsigned int i;
VkResult vr;
d3d12_command_list_end_current_render_pass(list);
if (!rect_count)
{
full_rect.top = 0;
@@ -5344,6 +5468,12 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearDepthStencilView(ID3D12Gra
ds_reference.attachment = 0;
ds_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
d3d12_command_list_end_current_render_pass(list);
if (vkd3d_resource_list_contains(&list->dsv_resources_since_last_barrier, dsv_desc->resource))
d3d12_command_list_emit_rt_barrier(list, false, true);
vkd3d_resource_list_append(&list->dsv_resources_since_last_barrier, dsv_desc->resource);
d3d12_command_list_clear(list, &attachment_desc, NULL, &ds_reference,
dsv_desc->view, dsv_desc->width, dsv_desc->height, dsv_desc->layer_count,
&clear_value, rect_count, rects);
@@ -5398,6 +5528,12 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearRenderTargetView(ID3D12Gra
clear_value.color.float32[3] = color[3];
}
d3d12_command_list_end_current_render_pass(list);
if (vkd3d_resource_list_contains(&list->rtv_resources_since_last_barrier, rtv_desc->resource))
d3d12_command_list_emit_rt_barrier(list, true, false);
vkd3d_resource_list_append(&list->rtv_resources_since_last_barrier, rtv_desc->resource);
d3d12_command_list_clear(list, &attachment_desc, &color_reference, NULL,
rtv_desc->view, rtv_desc->width, rtv_desc->height, rtv_desc->layer_count,
&clear_value, rect_count, rects);
@@ -6395,6 +6531,9 @@ static HRESULT d3d12_command_list_init(struct d3d12_command_list *list,
list->type = type;
vkd3d_resource_list_init(&list->rtv_resources_since_last_barrier);
vkd3d_resource_list_init(&list->dsv_resources_since_last_barrier);
if (FAILED(hr = vkd3d_private_store_init(&list->private_store)))
return hr;

View File

@@ -1277,6 +1277,13 @@ enum vkd3d_pipeline_bind_point
VKD3D_PIPELINE_BIND_POINT_COUNT = 0x2,
};
struct vkd3d_resource_list
{
struct d3d12_resource **resources;
size_t count;
size_t capacity;
};
/* ID3D12CommandList */
struct d3d12_command_list
{
@@ -1302,6 +1309,13 @@ struct d3d12_command_list
unsigned int fb_layer_count;
VkFormat dsv_format;
/* Resources for views bound to d3d12 state */
struct d3d12_resource *rtv_resources[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
struct d3d12_resource *dsv_resource;
/* Resources bound since the last pipeline barrier */
struct vkd3d_resource_list rtv_resources_since_last_barrier;
struct vkd3d_resource_list dsv_resources_since_last_barrier;
bool xfb_enabled;
bool has_depth_bounds;
bool is_predicated;