[PATCH 4/4] wined3d: Set WINED3D_LOCATION_CLEARED for full-subresource clears to black.

Stefan Dösinger stefan at codeweavers.com
Sun Apr 24 11:24:49 CDT 2022


Signed-off-by: Stefan Dösinger <stefan at codeweavers.com>

---

This is in the Vulkan codepath because GL lacks the renderpass clear
functionality and delaying from an explicit d3d clear call to the next
time the resource is used for something else isn't necessarily a
performance win. Most likely we'd just break up a TARGET|DEPTH|STENCIL
clear into 3 separate glClear invocations...
---
 dlls/wined3d/texture.c | 86 ++++++++++++++++++++++++++++++++----------
 1 file changed, 67 insertions(+), 19 deletions(-)

diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index eaa7cdf3ea5..0fffb8fc4f2 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -805,6 +805,9 @@ BOOL wined3d_texture_load_location(struct wined3d_texture *texture,
 
         /* FIXME: Clear textures on the GPU if possible. */
 
+        if (location != WINED3D_LOCATION_SYSMEM)
+            WARN_(d3d_perf)("Clearing texture %p in CPU.\n", texture);
+
         if (!wined3d_texture_prepare_location(texture, sub_resource_idx, context, WINED3D_LOCATION_SYSMEM))
             return FALSE;
         wined3d_texture_get_bo_address(texture, sub_resource_idx, &addr, WINED3D_LOCATION_SYSMEM);
@@ -6407,13 +6410,13 @@ static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk
 {
     VkClearValue clear_values[WINED3D_MAX_RENDER_TARGETS + 1];
     VkImageView views[WINED3D_MAX_RENDER_TARGETS + 1];
+    unsigned int i, attachment_count, delay_count = 0;
     struct wined3d_rendertarget_view_vk *rtv_vk;
     struct wined3d_rendertarget_view *view;
     const struct wined3d_vk_info *vk_info;
     struct wined3d_device_vk *device_vk;
     VkCommandBuffer vk_command_buffer;
     VkRenderPassBeginInfo begin_desc;
-    unsigned int i, attachment_count;
     VkFramebufferCreateInfo fb_desc;
     VkFramebuffer vk_framebuffer;
     VkRenderPass vk_render_pass;
@@ -6439,10 +6442,25 @@ static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk
         if (!(view = fb->render_targets[i]))
             continue;
 
-        if (!is_full_clear(view, draw_rect, clear_rects))
-            wined3d_rendertarget_view_load_location(view, &context_vk->c, view->resource->draw_binding);
+        if (is_full_clear(view, draw_rect, clear_rects))
+        {
+            if (!colour->r && !colour->g && !colour->b && !colour->a)
+            {
+                wined3d_rendertarget_view_validate_location(view, WINED3D_LOCATION_CLEARED);
+                wined3d_rendertarget_view_invalidate_location(view, ~WINED3D_LOCATION_CLEARED);
+                delay_count++;
+                continue;
+            }
+            else
+            {
+                FIXME("non-zero clear\n");
+                wined3d_rendertarget_view_prepare_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_load_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);
 
@@ -6472,31 +6490,60 @@ static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk
         ++attachment_count;
     }
 
+    if (!attachment_count)
+        flags &= ~WINED3DCLEAR_TARGET;
+
     if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && (view = fb->depth_stencil))
     {
-        if (!is_full_clear(view, draw_rect, clear_rects))
+        DWORD full_flags = 0;
+
+        /* Vulkan can clear only depth or stencil, but at the moment we can't put the depth and
+         * stencil parts in separate locations. It isn't easy to do either, as such a half-cleared
+         * texture would need to be handled not just as a DS target but also when used as a shader
+         * resource or accessed on sysmem. */
+        if (view->format->depth_size)
+            full_flags = WINED3DCLEAR_ZBUFFER;
+        if (view->format->stencil_size)
+            full_flags |= WINED3DCLEAR_STENCIL;
+
+        if (!is_full_clear(view, draw_rect, clear_rects)
+                || depth || stencil || (flags & full_flags) != full_flags)
+        {
             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);
+            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);
-        wined3d_rendertarget_view_vk_barrier(rtv_vk, context_vk, WINED3D_BIND_DEPTH_STENCIL);
+            rtv_vk = wined3d_rendertarget_view_vk(view);
+            views[attachment_count] = wined3d_rendertarget_view_vk_get_image_view(rtv_vk, context_vk);
+            wined3d_rendertarget_view_vk_barrier(rtv_vk, context_vk, WINED3D_BIND_DEPTH_STENCIL);
 
-        clear_values[attachment_count].depthStencil.depth = depth;
-        clear_values[attachment_count].depthStencil.stencil = stencil;
+            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;
+            if (view->layer_count > layer_count)
+                layer_count = view->layer_count;
 
-        depth_stencil = true;
-        ++attachment_count;
+            depth_stencil = true;
+            ++attachment_count;
+        }
+        else
+        {
+            wined3d_rendertarget_view_validate_location(view, WINED3D_LOCATION_CLEARED);
+            wined3d_rendertarget_view_invalidate_location(view, ~WINED3D_LOCATION_CLEARED);
+            flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
+            delay_count++;
+        }
     }
 
     if (!attachment_count)
+    {
+        TRACE("The clear has been delayed until draw time.\n");
         return;
+    }
+
+    TRACE("Doing an immediate clear of %u attachments.\n", attachment_count);
+    if (delay_count)
+        WARN_(d3d_perf)("Partial clear: %u immediate, %u delayed.\n", attachment_count, delay_count);
 
     if (!(vk_render_pass = wined3d_context_vk_get_render_pass(context_vk, fb,
             rt_count, flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL), flags)))
@@ -6650,6 +6697,7 @@ static void vk_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_dev
         }
         else
         {
+            ERR("subrect clear\n");
             for (i = 0; i < rt_count; ++i)
             {
                 if (!(view = fb->render_targets[i]))
@@ -6681,7 +6729,7 @@ static void vk_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_dev
         return;
     }
 
-    TRACE("Forwarding to blitter %p.\n", next);
+    ERR("Forwarding to blitter %p.\n", next);
     next->ops->blitter_clear(next, device, next_rt_count, fb, rect_count,
             clear_rects, draw_rect, next_flags, colour, depth, stencil);
 }
-- 
2.35.1




More information about the wine-devel mailing list