From 7fea3527edefba585efe2ba8b80ab84dd3c52be3 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Thu, 2 Sep 2021 15:58:06 +0200 Subject: [PATCH] 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 --- libs/vkd3d/command.c | 228 ++----------------------------------- libs/vkd3d/vkd3d_private.h | 14 --- 2 files changed, 9 insertions(+), 233 deletions(-) diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index e2c3a34d..8b35eca5 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -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); } } diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 0ce90183..e6dd5337 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -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;