vkd3d: Remove deferred clears.

Emitting render pass clears while we're in the process of starting
a render pass overrides dsv layout tracking info.

Signed-off-by: Philip Rebohle <philip.rebohle@tu-dortmund.de>
This commit is contained in:
Philip Rebohle 2021-09-02 15:58:06 +02:00 committed by Hans-Kristian Arntzen
parent b05145b421
commit 7fea3527ed
2 changed files with 9 additions and 233 deletions

View File

@ -2703,28 +2703,6 @@ static void d3d12_command_list_clear_attachment_pass(struct d3d12_command_list *
VK_CALL(vkCmdEndRenderPass2KHR(list->vk_command_buffer, &subpass_end_info));
}
static void d3d12_command_list_clear_attachment_deferred(struct d3d12_command_list *list, unsigned int attachment_idx,
VkImageAspectFlags clear_aspects, const VkClearValue *clear_value)
{
struct vkd3d_clear_state *clear_state = &list->clear_state;
struct vkd3d_clear_attachment *attachment = &clear_state->attachments[attachment_idx];
/* If necessary, combine with previous clear so that e.g. a
* depth-only clear does not override a stencil-only clear. */
clear_state->attachment_mask |= 1u << attachment_idx;
attachment->aspect_mask |= clear_aspects;
attachment->discard_mask &= ~clear_aspects;
if (clear_aspects & VK_IMAGE_ASPECT_COLOR_BIT)
attachment->value.color = clear_value->color;
if (clear_aspects & VK_IMAGE_ASPECT_DEPTH_BIT)
attachment->value.depthStencil.depth = clear_value->depthStencil.depth;
if (clear_aspects & VK_IMAGE_ASPECT_STENCIL_BIT)
attachment->value.depthStencil.stencil = clear_value->depthStencil.stencil;
}
static void d3d12_command_list_discard_attachment_barrier(struct d3d12_command_list *list,
struct d3d12_resource *resource, const VkImageSubresourceLayers *subresource, bool is_bound)
{
@ -2772,144 +2750,6 @@ static void d3d12_command_list_discard_attachment_barrier(struct d3d12_command_l
stages, stages, 0, 0, NULL, 0, NULL, 1, &barrier));
}
static void d3d12_command_list_discard_attachment_deferred(struct d3d12_command_list *list,
uint32_t attachment_idx, VkImageAspectFlags discard_aspects)
{
struct vkd3d_clear_state *clear_state = &list->clear_state;
struct vkd3d_clear_attachment *attachment = &clear_state->attachments[attachment_idx];
clear_state->attachment_mask |= 1u << attachment_idx;
attachment->aspect_mask &= ~discard_aspects;
attachment->discard_mask |= discard_aspects;
}
static bool d3d12_command_list_has_render_pass_rtv_clear(struct d3d12_command_list *list, unsigned int attachment_idx)
{
const struct d3d12_graphics_pipeline_state *graphics;
if (!d3d12_pipeline_state_is_graphics(list->state))
return false;
graphics = &list->state->graphics;
return attachment_idx < graphics->rt_count &&
!(graphics->null_attachment_mask & (1 << attachment_idx)) &&
(list->clear_state.attachment_mask & (1 << attachment_idx));
}
static bool d3d12_command_list_has_depth_stencil_view(struct d3d12_command_list *list);
static bool d3d12_command_list_has_render_pass_dsv_clear(struct d3d12_command_list *list)
{
struct vkd3d_clear_attachment *clear_attachment = &list->clear_state.attachments[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
VkImageAspectFlags clear_aspects, write_aspects;
if (!d3d12_pipeline_state_is_graphics(list->state))
return false;
if (!d3d12_command_list_has_depth_stencil_view(list))
return false;
if (!(list->clear_state.attachment_mask & (1 << D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT)))
return false;
/* If any of the aspects to clear are read-only in the render
* pass, we have to perform the DSV clear in a separate pass. */
write_aspects = vk_writable_aspects_from_image_layout(list->dsv_layout);
clear_aspects = clear_attachment->aspect_mask | clear_attachment->discard_mask;
return (write_aspects & clear_aspects) == clear_aspects;
}
static void d3d12_command_list_emit_deferred_clear(struct d3d12_command_list *list, unsigned int attachment_idx)
{
struct vkd3d_clear_attachment *clear_attachment = &list->clear_state.attachments[attachment_idx];
VkImageSubresourceLayers vk_subresource_layers;
struct d3d12_resource *resource;
struct vkd3d_view *view;
if (attachment_idx < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT)
{
resource = list->rtvs[attachment_idx].resource;
view = list->rtvs[attachment_idx].view;
}
else
{
resource = list->dsv.resource;
view = list->dsv.view;
}
if (list->current_render_pass)
{
if (clear_attachment->aspect_mask)
{
d3d12_command_list_clear_attachment_inline(list, resource,
view, attachment_idx, clear_attachment->aspect_mask,
&clear_attachment->value, 0, NULL);
}
}
else
{
if (clear_attachment->aspect_mask)
{
d3d12_command_list_clear_attachment_pass(list, resource, view,
clear_attachment->aspect_mask, &clear_attachment->value, 0, NULL,
list->render_pass_suspended);
}
if (clear_attachment->discard_mask)
{
vk_subresource_layers = vk_subresource_layers_from_view(view);
d3d12_command_list_discard_attachment_barrier(list, resource,
&vk_subresource_layers, list->render_pass_suspended);
}
}
clear_attachment->aspect_mask = 0;
clear_attachment->discard_mask = 0;
}
static void d3d12_command_list_emit_render_pass_clears(struct d3d12_command_list *list, bool invert_mask)
{
struct vkd3d_clear_state *clear_state = &list->clear_state;
uint64_t attachment_mask = 0;
unsigned int i;
if (!clear_state->attachment_mask)
return;
for (i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
{
if (d3d12_command_list_has_render_pass_rtv_clear(list, i))
attachment_mask |= 1 << i;
}
if (d3d12_command_list_has_render_pass_dsv_clear(list))
attachment_mask |= 1 << D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT;
if (invert_mask)
attachment_mask = (~attachment_mask) & clear_state->attachment_mask;
clear_state->attachment_mask &= ~attachment_mask;
while (attachment_mask)
{
unsigned int attachment_idx = vkd3d_bitmask_iter64(&attachment_mask);
d3d12_command_list_emit_deferred_clear(list, attachment_idx);
}
}
static void d3d12_command_list_flush_deferred_clears(struct d3d12_command_list *list)
{
struct vkd3d_clear_state *clear_state = &list->clear_state;
while (clear_state->attachment_mask)
{
unsigned int attachment_idx = vkd3d_bitmask_iter64(&clear_state->attachment_mask);
d3d12_command_list_emit_deferred_clear(list, attachment_idx);
}
}
enum vkd3d_render_pass_transition_mode
{
VKD3D_RENDER_PASS_TRANSITION_MODE_BEGIN,
@ -2930,7 +2770,7 @@ static bool d3d12_resource_requires_shader_visibility_after_transition(
static VkPipelineStageFlags vk_render_pass_barrier_from_view(struct d3d12_command_list *list,
const struct vkd3d_view *view, const struct d3d12_resource *resource,
enum vkd3d_render_pass_transition_mode mode, VkImageLayout layout, bool clear, VkImageMemoryBarrier *vk_barrier)
enum vkd3d_render_pass_transition_mode mode, VkImageLayout layout, VkImageMemoryBarrier *vk_barrier)
{
VkImageLayout outside_render_pass_layout;
VkPipelineStageFlags stages;
@ -2959,11 +2799,6 @@ static VkPipelineStageFlags vk_render_pass_barrier_from_view(struct d3d12_comman
vk_barrier->oldLayout = outside_render_pass_layout;
vk_barrier->newLayout = layout;
/* Ignore 3D images as re-initializing those may cause us to
* discard the entire image, not just the layers to clear. */
if (clear && resource->desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE3D)
vk_barrier->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
/* If we're transitioning into depth state and we could potentially read
* (we cannot know this here),
* shader might want to read from it as well, so we have to make that visible here
@ -3029,7 +2864,6 @@ static void d3d12_command_list_emit_render_pass_transition(struct d3d12_command_
VkPipelineStageFlags stage_mask = 0;
VkPipelineStageFlags new_stages;
struct d3d12_rtv_desc *dsv;
bool do_clear = false;
uint32_t i, j;
for (i = 0, j = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
@ -3039,11 +2873,8 @@ static void d3d12_command_list_emit_render_pass_transition(struct d3d12_command_
if (!rtv->view)
continue;
if (mode == VKD3D_RENDER_PASS_TRANSITION_MODE_BEGIN)
do_clear = d3d12_command_list_has_render_pass_rtv_clear(list, i);
if ((new_stages = vk_render_pass_barrier_from_view(list, rtv->view, rtv->resource,
mode, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, do_clear, &vk_image_barriers[j])))
mode, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, &vk_image_barriers[j])))
{
stage_mask |= new_stages;
j++;
@ -3056,11 +2887,8 @@ static void d3d12_command_list_emit_render_pass_transition(struct d3d12_command_
if (dsv->view && list->dsv_layout)
{
if (mode == VKD3D_RENDER_PASS_TRANSITION_MODE_BEGIN)
do_clear = d3d12_command_list_has_render_pass_dsv_clear(list);
if ((new_stages = vk_render_pass_barrier_from_view(list, dsv->view, dsv->resource,
mode, list->dsv_layout, do_clear, &vk_image_barriers[j])))
mode, list->dsv_layout, &vk_image_barriers[j])))
{
stage_mask |= new_stages;
j++;
@ -3604,13 +3432,6 @@ static void d3d12_command_list_end_current_render_pass(struct d3d12_command_list
list->render_pass_suspended = suspend && (list->current_render_pass || list->render_pass_suspended);
list->current_render_pass = VK_NULL_HANDLE;
/* Emit pending deferred clears. This can happen if
* no draw got executed after the clear operation.
* We are sensitive to list->render_pass_suspended here
* so make sure we update that before doing deferred clears
* since we need to know which image layouts to use. */
d3d12_command_list_flush_deferred_clears(list);
if (list->xfb_enabled)
{
VkMemoryBarrier vk_barrier;
@ -4392,7 +4213,6 @@ static void d3d12_command_list_reset_api_state(struct d3d12_command_list *list,
memset(list->rtvs, 0, sizeof(list->rtvs));
memset(&list->dsv, 0, sizeof(list->dsv));
memset(&list->clear_state, 0, sizeof(list->clear_state));
list->dsv_layout = VK_IMAGE_LAYOUT_UNDEFINED;
list->dsv_plane_optimal_mask = 0;
list->fb_width = 0;
@ -5482,11 +5302,6 @@ static bool d3d12_command_list_begin_render_pass(struct d3d12_command_list *list
vk_render_pass = list->pso_render_pass;
assert(vk_render_pass);
/* Emit deferred clears that we cannot clear inside the
* render pass, e.g. when the attachments to clear are
* not included in the current pipeline's render pass. */
d3d12_command_list_emit_render_pass_clears(list, true);
if (!list->render_pass_suspended)
d3d12_command_list_emit_render_pass_transition(list, VKD3D_RENDER_PASS_TRANSITION_MODE_BEGIN);
@ -5509,9 +5324,6 @@ static bool d3d12_command_list_begin_render_pass(struct d3d12_command_list *list
list->current_render_pass = vk_render_pass;
/* Emit deferred clears with vkCmdClearAttachment */
d3d12_command_list_emit_render_pass_clears(list, false);
graphics = &list->state->graphics;
if (graphics->xfb_enabled)
{
@ -7976,7 +7788,7 @@ static void d3d12_command_list_clear_attachment(struct d3d12_command_list *list,
if (attachment_idx == D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT && list->current_render_pass)
writable = (vk_writable_aspects_from_image_layout(list->dsv_layout) & clear_aspects) == clear_aspects;
if (attachment_idx < 0 || (!list->current_render_pass && !full_clear) || !writable)
if (attachment_idx < 0 || !list->current_render_pass || !writable)
{
/* View currently not bound as a render target, or bound but
* the render pass isn't active and we're only going to clear
@ -7986,21 +7798,13 @@ static void d3d12_command_list_clear_attachment(struct d3d12_command_list *list,
d3d12_command_list_clear_attachment_pass(list, resource, view,
clear_aspects, clear_value, rect_count, rects, false);
}
else if (list->current_render_pass)
else
{
/* View bound and render pass active, just emit the clear */
d3d12_command_list_clear_attachment_inline(list, resource, view,
attachment_idx, clear_aspects, clear_value,
rect_count, rects);
}
else
{
/* View bound but render pass not active, and we'll clear
* the entire image. Defer the clear until we begin the
* render pass to avoid unnecessary barriers. */
d3d12_command_list_clear_attachment_deferred(list, attachment_idx,
clear_aspects, clear_value);
}
}
static void STDMETHODCALLTYPE d3d12_command_list_ClearDepthStencilView(d3d12_command_list_iface *iface,
@ -8440,9 +8244,9 @@ static void STDMETHODCALLTYPE d3d12_command_list_DiscardResource(d3d12_command_l
VkImageSubresourceLayers vk_subresource_layers;
unsigned int resource_subresource_count;
VkImageSubresource vk_subresource;
bool full_discard, is_bound;
D3D12_RECT full_rect;
int attachment_idx;
bool full_discard;
TRACE("iface %p, resource %p, region %p.\n", iface, resource, region);
@ -8510,23 +8314,9 @@ static void STDMETHODCALLTYPE d3d12_command_list_DiscardResource(d3d12_command_l
vk_subresource_layers = vk_subresource_layers_from_subresource(&vk_subresource);
attachment_idx = d3d12_command_list_find_attachment_view(list, texture, &vk_subresource_layers);
if (attachment_idx < 0)
{
/* Image is not currently bound as an attachment */
d3d12_command_list_end_current_render_pass(list, false);
d3d12_command_list_discard_attachment_barrier(list, texture, &vk_subresource_layers, false);
}
else if (list->current_render_pass || list->render_pass_suspended)
{
/* Image is bound and the render pass is active */
d3d12_command_list_end_current_render_pass(list, true);
d3d12_command_list_discard_attachment_barrier(list, texture, &vk_subresource_layers, true);
}
else
{
/* Image is bound, but the render pass is not active */
d3d12_command_list_discard_attachment_deferred(list, attachment_idx, vk_subresource.aspectMask);
}
is_bound = attachment_idx >= 0 && (list->current_render_pass || list->render_pass_suspended);
d3d12_command_list_end_current_render_pass(list, is_bound);
d3d12_command_list_discard_attachment_barrier(list, texture, &vk_subresource_layers, is_bound);
}
}

View File

@ -1684,19 +1684,6 @@ struct vkd3d_dynamic_state
/* ID3D12CommandList */
typedef ID3D12GraphicsCommandList5 d3d12_command_list_iface;
struct vkd3d_clear_attachment
{
VkImageAspectFlags aspect_mask;
VkImageAspectFlags discard_mask;
VkClearValue value;
};
struct vkd3d_clear_state
{
uint64_t attachment_mask;
struct vkd3d_clear_attachment attachments[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT + 1];
};
enum vkd3d_initial_transition_type
{
VKD3D_INITIAL_TRANSITION_TYPE_RESOURCE,
@ -1780,7 +1767,6 @@ struct d3d12_command_list
struct d3d12_rtv_desc rtvs[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
struct d3d12_rtv_desc dsv;
struct vkd3d_clear_state clear_state;
uint32_t dsv_plane_optimal_mask;
VkImageLayout dsv_layout;
unsigned int fb_width;