From f793f4446c4e1f01afc2cc47354f65c7049eb38b Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Tue, 28 Apr 2020 02:28:23 +0430 Subject: [PATCH] wined3d: Implement depth/stencil clears in the Vulkan blitter. Signed-off-by: Henri Verbeet Signed-off-by: Alexandre Julliard --- dlls/wined3d/context_vk.c | 54 ++++++++++++++++++++++++--- dlls/wined3d/texture.c | 68 ++++++++++++++++++++++++++++++++-- dlls/wined3d/wined3d_private.h | 5 ++- 3 files changed, 117 insertions(+), 10 deletions(-) diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c index 427dc064055..e8fcc391782 100644 --- a/dlls/wined3d/context_vk.c +++ b/dlls/wined3d/context_vk.c @@ -630,7 +630,7 @@ static void wined3d_context_vk_destroy_bo_slab(struct wine_rb_entry *entry, void } static void wined3d_render_pass_key_vk_init(struct wined3d_render_pass_key_vk *key, - const struct wined3d_fb_state *fb, unsigned int rt_count) + const struct wined3d_fb_state *fb, unsigned int rt_count, bool depth_stencil, uint32_t clear_flags) { struct wined3d_render_pass_attachment_vk *a; struct wined3d_rendertarget_view *view; @@ -649,6 +649,17 @@ static void wined3d_render_pass_key_vk_init(struct wined3d_render_pass_key_vk *k a->vk_layout = wined3d_texture_vk(wined3d_texture_from_resource(view->resource))->layout; key->rt_mask |= 1u << i; } + + if (depth_stencil && (view = fb->depth_stencil)) + { + a = &key->ds; + a->vk_format = wined3d_format_vk(view->format)->vk_format; + a->vk_samples = max(1, wined3d_resource_get_sample_count(view->resource)); + a->vk_layout = wined3d_texture_vk(wined3d_texture_from_resource(view->resource))->layout; + key->rt_mask |= 1u << WINED3D_MAX_RENDER_TARGETS; + } + + key->clear_flags = clear_flags; } static void wined3d_render_pass_vk_cleanup(struct wined3d_render_pass_vk *pass, @@ -668,6 +679,8 @@ static bool wined3d_render_pass_vk_init(struct wined3d_render_pass_vk *pass, VkAttachmentDescription attachments[WINED3D_MAX_RENDER_TARGETS + 1]; const struct wined3d_vk_info *vk_info = context_vk->vk_info; const struct wined3d_render_pass_attachment_vk *a; + VkAttachmentReference ds_attachment_reference; + VkAttachmentReference *ds_reference = NULL; unsigned int attachment_count, rt_count, i; VkAttachmentDescription *attachment; VkSubpassDescription sub_pass_desc; @@ -687,7 +700,10 @@ static bool wined3d_render_pass_vk_init(struct wined3d_render_pass_vk *pass, attachment->flags = 0; attachment->format = a->vk_format; attachment->samples = a->vk_samples; - attachment->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + if (key->clear_flags & WINED3DCLEAR_TARGET) + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + else + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; attachment->storeOp = VK_ATTACHMENT_STORE_OP_STORE; attachment->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachment->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; @@ -709,6 +725,34 @@ static bool wined3d_render_pass_vk_init(struct wined3d_render_pass_vk *pass, attachment_references[i].layout = VK_IMAGE_LAYOUT_UNDEFINED; } + if (key->rt_mask & (1u << WINED3D_MAX_RENDER_TARGETS)) + { + a = &key->ds; + + attachment = &attachments[attachment_count]; + attachment->flags = 0; + attachment->format = a->vk_format; + attachment->samples = a->vk_samples; + if (key->clear_flags & WINED3DCLEAR_ZBUFFER) + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + else + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachment->storeOp = VK_ATTACHMENT_STORE_OP_STORE; + if (key->clear_flags & WINED3DCLEAR_STENCIL) + attachment->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + else + attachment->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachment->stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment->initialLayout = a->vk_layout; + attachment->finalLayout = a->vk_layout; + + ds_reference = &ds_attachment_reference; + ds_reference->attachment = attachment_count; + ds_reference->layout = a->vk_layout; + + ++attachment_count; + } + sub_pass_desc.flags = 0; sub_pass_desc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; sub_pass_desc.inputAttachmentCount = 0; @@ -716,7 +760,7 @@ static bool wined3d_render_pass_vk_init(struct wined3d_render_pass_vk *pass, sub_pass_desc.colorAttachmentCount = rt_count; sub_pass_desc.pColorAttachments = attachment_references; sub_pass_desc.pResolveAttachments = NULL; - sub_pass_desc.pDepthStencilAttachment = NULL; + sub_pass_desc.pDepthStencilAttachment = ds_reference; sub_pass_desc.preserveAttachmentCount = 0; sub_pass_desc.pPreserveAttachments = NULL; @@ -742,13 +786,13 @@ static bool wined3d_render_pass_vk_init(struct wined3d_render_pass_vk *pass, } VkRenderPass wined3d_context_vk_get_render_pass(struct wined3d_context_vk *context_vk, - const struct wined3d_fb_state *fb, unsigned int rt_count) + const struct wined3d_fb_state *fb, unsigned int rt_count, bool depth_stencil, uint32_t clear_flags) { struct wined3d_render_pass_key_vk key; struct wined3d_render_pass_vk *pass; struct wine_rb_entry *entry; - wined3d_render_pass_key_vk_init(&key, fb, rt_count); + wined3d_render_pass_key_vk_init(&key, fb, rt_count, depth_stencil, clear_flags); if ((entry = wine_rb_get(&context_vk->render_passes, &key))) return WINE_RB_ENTRY_VALUE(entry, struct wined3d_render_pass_vk, entry)->vk_render_pass; diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index ef5f3cd48e5..4f55abb5e2b 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -6052,8 +6052,8 @@ static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects, const RECT *draw_rect, uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil) { - VkClearValue clear_values[WINED3D_MAX_RENDER_TARGETS]; - VkImageView views[WINED3D_MAX_RENDER_TARGETS]; + VkClearValue clear_values[WINED3D_MAX_RENDER_TARGETS + 1]; + VkImageView views[WINED3D_MAX_RENDER_TARGETS + 1]; struct wined3d_rendertarget_view_vk *rtv_vk; struct wined3d_rendertarget_view *view; const struct wined3d_vk_info *vk_info; @@ -6065,6 +6065,7 @@ static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk VkFramebufferCreateInfo fb_desc; VkFramebuffer vk_framebuffer; VkRenderPass vk_render_pass; + bool depth_stencil = false; unsigned int layer_count; VkClearColorValue *c; VkResult vr; @@ -6078,6 +6079,9 @@ static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk device_vk = wined3d_device_vk(context_vk->c.device); vk_info = context_vk->vk_info; + if (!(flags & WINED3DCLEAR_TARGET)) + rt_count = 0; + for (i = 0, attachment_count = 0, layer_count = 1; i < rt_count; ++i) { if (!(view = fb->render_targets[i])) @@ -6115,7 +6119,33 @@ static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk ++attachment_count; } - if (!(vk_render_pass = wined3d_context_vk_get_render_pass(context_vk, fb, rt_count))) + if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && (view = fb->depth_stencil)) + { + if (!is_full_clear(view, draw_rect, clear_rects)) + wined3d_rendertarget_view_load_location(view, &context_vk->c, view->resource->draw_binding); + else + wined3d_rendertarget_view_prepare_location(view, &context_vk->c, view->resource->draw_binding); + wined3d_rendertarget_view_validate_location(view, view->resource->draw_binding); + wined3d_rendertarget_view_invalidate_location(view, ~view->resource->draw_binding); + + rtv_vk = wined3d_rendertarget_view_vk(view); + views[attachment_count] = wined3d_rendertarget_view_vk_get_image_view(rtv_vk, context_vk); + + clear_values[attachment_count].depthStencil.depth = depth; + clear_values[attachment_count].depthStencil.stencil = stencil; + + if (view->layer_count > layer_count) + layer_count = view->layer_count; + + depth_stencil = true; + ++attachment_count; + } + + if (!attachment_count) + return; + + if (!(vk_render_pass = wined3d_context_vk_get_render_pass(context_vk, fb, + rt_count, flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL), flags))) { ERR("Failed to get render pass.\n"); return; @@ -6183,6 +6213,19 @@ static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk texture_vk->layout, texture_vk->layout, texture_vk->vk_image, VK_IMAGE_ASPECT_COLOR_BIT); } + + if (depth_stencil) + { + view = fb->depth_stencil; + wined3d_context_vk_reference_rendertarget_view(context_vk, wined3d_rendertarget_view_vk(view)); + texture_vk = wined3d_texture_vk(wined3d_texture_from_resource(view->resource)); + wined3d_context_vk_image_barrier(context_vk, vk_command_buffer, + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + vk_access_mask_from_bind_flags(texture_vk->t.resource.bind_flags), + texture_vk->layout, texture_vk->layout, + texture_vk->vk_image, vk_aspect_mask_from_format(texture_vk->t.resource.format)); + } } static void vk_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device, @@ -6228,7 +6271,10 @@ static void vk_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_dev } } - if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && fb->depth_stencil) + if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil) + && (!view->format->depth_size || (flags & WINED3DCLEAR_ZBUFFER)) + && (!view->format->stencil_size || (flags & WINED3DCLEAR_STENCIL)) + && blitter_use_cpu_clear(view)) { next_flags |= flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL); @@ -6247,6 +6293,13 @@ static void vk_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_dev have_identical_size = false; previous = view; } + if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) + { + view = fb->depth_stencil; + + if (previous && (previous->width != view->width || previous->height != view->height)) + have_identical_size = false; + } if (have_identical_size) { @@ -6265,6 +6318,13 @@ static void vk_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_dev vk_blitter_clear_rendertargets(context_vk, 1, &tmp_fb, rect_count, clear_rects, draw_rect, WINED3DCLEAR_TARGET, colour, depth, stencil); } + if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) + { + tmp_fb.render_targets[0] = NULL; + tmp_fb.depth_stencil = fb->depth_stencil; + vk_blitter_clear_rendertargets(context_vk, 0, &tmp_fb, rect_count, + clear_rects, draw_rect, flags & ~WINED3DCLEAR_TARGET, colour, depth, stencil); + } } context_release(&context_vk->c); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index dd8e03d35d9..db86d746b5f 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2272,7 +2272,9 @@ struct wined3d_render_pass_attachment_vk struct wined3d_render_pass_key_vk { struct wined3d_render_pass_attachment_vk rt[WINED3D_MAX_RENDER_TARGETS]; + struct wined3d_render_pass_attachment_vk ds; uint32_t rt_mask; + uint32_t clear_flags; }; struct wined3d_render_pass_vk @@ -2330,7 +2332,8 @@ void wined3d_context_vk_destroy_memory(struct wined3d_context_vk *context_vk, VkDeviceMemory vk_memory, uint64_t command_buffer_id) DECLSPEC_HIDDEN; VkCommandBuffer wined3d_context_vk_get_command_buffer(struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN; VkRenderPass wined3d_context_vk_get_render_pass(struct wined3d_context_vk *context_vk, - const struct wined3d_fb_state *fb, unsigned int rt_count) DECLSPEC_HIDDEN; + const struct wined3d_fb_state *fb, unsigned int rt_count, + bool depth_stencil, uint32_t clear_flags) DECLSPEC_HIDDEN; void wined3d_context_vk_image_barrier(struct wined3d_context_vk *context_vk, VkCommandBuffer vk_command_buffer, VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask, VkAccessFlags src_access_mask, VkAccessFlags dst_access_mask, VkImageLayout old_layout,