[PATCH 5/5] wined3d: Implement clears in the Vulkan blitter.

Henri Verbeet hverbeet at codeweavers.com
Mon Apr 27 10:48:47 CDT 2020


Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
 dlls/wined3d/context_vk.c      | 194 ++++++++++++++++++++++
 dlls/wined3d/texture.c         | 294 ++++++++++++++++++++++++++++++++-
 dlls/wined3d/view.c            |   2 +-
 dlls/wined3d/wined3d_private.h |  49 +++++-
 4 files changed, 531 insertions(+), 8 deletions(-)

diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c
index f5a321b076c..f4a52fb9c2f 100644
--- a/dlls/wined3d/context_vk.c
+++ b/dlls/wined3d/context_vk.c
@@ -296,6 +296,31 @@ static struct wined3d_retired_object_vk *wined3d_context_vk_get_retired_object_v
     return &retired->objects[retired->count++];
 }
 
+void wined3d_context_vk_destroy_framebuffer(struct wined3d_context_vk *context_vk,
+        VkFramebuffer vk_framebuffer, uint64_t command_buffer_id)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+    struct wined3d_retired_object_vk *o;
+
+    if (context_vk->completed_command_buffer_id > command_buffer_id)
+    {
+        VK_CALL(vkDestroyFramebuffer(device_vk->vk_device, vk_framebuffer, NULL));
+        TRACE("Destroyed framebuffer 0x%s.\n", wine_dbgstr_longlong(vk_framebuffer));
+        return;
+    }
+
+    if (!(o = wined3d_context_vk_get_retired_object_vk(context_vk)))
+    {
+        ERR("Leaking framebuffer 0x%s.\n", wine_dbgstr_longlong(vk_framebuffer));
+        return;
+    }
+
+    o->type = WINED3D_RETIRED_FRAMEBUFFER_VK;
+    o->u.vk_framebuffer = vk_framebuffer;
+    o->command_buffer_id = command_buffer_id;
+}
+
 void wined3d_context_vk_destroy_memory(struct wined3d_context_vk *context_vk,
         VkDeviceMemory vk_memory, uint64_t command_buffer_id)
 {
@@ -538,6 +563,11 @@ static void wined3d_context_vk_cleanup_resources(struct wined3d_context_vk *cont
                 /* Nothing to do. */
                 break;
 
+            case WINED3D_RETIRED_FRAMEBUFFER_VK:
+                VK_CALL(vkDestroyFramebuffer(device_vk->vk_device, o->u.vk_framebuffer, NULL));
+                TRACE("Destroyed framebuffer 0x%s.\n", wine_dbgstr_longlong(o->u.vk_framebuffer));
+                break;
+
             case WINED3D_RETIRED_MEMORY_VK:
                 VK_CALL(vkFreeMemory(device_vk->vk_device, o->u.vk_memory, NULL));
                 TRACE("Freed memory 0x%s.\n", wine_dbgstr_longlong(o->u.vk_memory));
@@ -599,6 +629,158 @@ 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)
+{
+    struct wined3d_render_pass_attachment_vk *a;
+    struct wined3d_rendertarget_view *view;
+    unsigned int i;
+
+    memset(key, 0, sizeof(*key));
+
+    for (i = 0; i < rt_count; ++i)
+    {
+        if (!(view = fb->render_targets[i]) || view->format->id == WINED3DFMT_NULL)
+            continue;
+
+        a = &key->rt[i];
+        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 << i;
+    }
+}
+
+static void wined3d_render_pass_vk_cleanup(struct wined3d_render_pass_vk *pass,
+        struct wined3d_context_vk *context_vk)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+
+    VK_CALL(vkDestroyRenderPass(device_vk->vk_device, pass->vk_render_pass, NULL));
+}
+
+static bool wined3d_render_pass_vk_init(struct wined3d_render_pass_vk *pass,
+        struct wined3d_context_vk *context_vk, const struct wined3d_render_pass_key_vk *key)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+    VkAttachmentReference attachment_references[WINED3D_MAX_RENDER_TARGETS];
+    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;
+    unsigned int attachment_count, rt_count, i;
+    VkAttachmentDescription *attachment;
+    VkSubpassDescription sub_pass_desc;
+    VkRenderPassCreateInfo pass_desc;
+    uint32_t mask;
+    VkResult vr;
+
+    rt_count = 0;
+    attachment_count = 0;
+    mask = key->rt_mask & ((1u << WINED3D_MAX_RENDER_TARGETS) - 1);
+    while (mask)
+    {
+        i = wined3d_bit_scan(&mask);
+        a = &key->rt[i];
+
+        attachment = &attachments[attachment_count];
+        attachment->flags = 0;
+        attachment->format = a->vk_format;
+        attachment->samples = a->vk_samples;
+        attachment->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+        attachment->storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+        attachment->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+        attachment->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+        attachment->initialLayout = a->vk_layout;
+        attachment->finalLayout = a->vk_layout;
+
+        attachment_references[i].attachment = attachment_count;
+        attachment_references[i].layout = a->vk_layout;
+
+        ++attachment_count;
+        rt_count = i + 1;
+    }
+
+    mask = ~key->rt_mask & ((1u << rt_count) - 1);
+    while (mask)
+    {
+        i = wined3d_bit_scan(&mask);
+        attachment_references[i].attachment = VK_ATTACHMENT_UNUSED;
+        attachment_references[i].layout = VK_IMAGE_LAYOUT_UNDEFINED;
+    }
+
+    sub_pass_desc.flags = 0;
+    sub_pass_desc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+    sub_pass_desc.inputAttachmentCount = 0;
+    sub_pass_desc.pInputAttachments = NULL;
+    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.preserveAttachmentCount = 0;
+    sub_pass_desc.pPreserveAttachments = NULL;
+
+    pass_desc.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+    pass_desc.pNext = NULL;
+    pass_desc.flags = 0;
+    pass_desc.attachmentCount = attachment_count;
+    pass_desc.pAttachments = attachments;
+    pass_desc.subpassCount = 1;
+    pass_desc.pSubpasses = &sub_pass_desc;
+    pass_desc.dependencyCount = 0;
+    pass_desc.pDependencies = NULL;
+
+    pass->key = *key;
+    if ((vr = VK_CALL(vkCreateRenderPass(device_vk->vk_device,
+            &pass_desc, NULL, &pass->vk_render_pass))) < 0)
+    {
+        WARN("Failed to create Vulkan render pass, vr %d.\n", vr);
+        return false;
+    }
+
+    return true;
+}
+
+VkRenderPass wined3d_context_vk_get_render_pass(struct wined3d_context_vk *context_vk,
+        const struct wined3d_fb_state *fb, unsigned int rt_count)
+{
+    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);
+    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;
+
+    if (!(pass = heap_alloc(sizeof(*pass))))
+        return VK_NULL_HANDLE;
+
+    if (!wined3d_render_pass_vk_init(pass, context_vk, &key))
+    {
+        heap_free(pass);
+        return VK_NULL_HANDLE;
+    }
+
+    if (wine_rb_put(&context_vk->render_passes, &pass->key, &pass->entry) == -1)
+    {
+        ERR("Failed to insert render pass.\n");
+        wined3d_render_pass_vk_cleanup(pass, context_vk);
+        heap_free(pass);
+        return VK_NULL_HANDLE;
+    }
+
+    return pass->vk_render_pass;
+}
+
+static void wined3d_context_vk_destroy_render_pass(struct wine_rb_entry *entry, void *ctx)
+{
+    struct wined3d_render_pass_vk *pass = WINE_RB_ENTRY_VALUE(entry,
+            struct wined3d_render_pass_vk, entry);
+
+    wined3d_render_pass_vk_cleanup(pass, ctx);
+    heap_free(pass);
+}
+
 void wined3d_context_vk_cleanup(struct wined3d_context_vk *context_vk)
 {
     struct wined3d_command_buffer_vk *buffer = &context_vk->current_command_buffer;
@@ -620,6 +802,8 @@ void wined3d_context_vk_cleanup(struct wined3d_context_vk *context_vk)
     heap_free(context_vk->submitted.buffers);
     heap_free(context_vk->retired.objects);
 
+    wine_rb_destroy(&context_vk->render_passes, wined3d_context_vk_destroy_render_pass, context_vk);
+
     wined3d_context_cleanup(&context_vk->c);
 }
 
@@ -784,6 +968,15 @@ void wined3d_context_vk_image_barrier(struct wined3d_context_vk *context_vk,
     VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, src_stage_mask, dst_stage_mask, 0, 0, NULL, 0, NULL, 1, &barrier));
 }
 
+static int wined3d_render_pass_vk_compare(const void *key, const struct wine_rb_entry *entry)
+{
+    const struct wined3d_render_pass_key_vk *k = key;
+    const struct wined3d_render_pass_vk *pass = WINE_RB_ENTRY_VALUE(entry,
+            const struct wined3d_render_pass_vk, entry);
+
+    return memcmp(k, &pass->key, sizeof(*k));
+}
+
 static int wined3d_bo_slab_vk_compare(const void *key, const struct wine_rb_entry *entry)
 {
     const struct wined3d_bo_slab_vk *slab = WINE_RB_ENTRY_VALUE(entry, const struct wined3d_bo_slab_vk, entry);
@@ -824,6 +1017,7 @@ HRESULT wined3d_context_vk_init(struct wined3d_context_vk *context_vk, struct wi
     }
     context_vk->current_command_buffer.id = 1;
 
+    wine_rb_init(&context_vk->render_passes, wined3d_render_pass_vk_compare);
     wine_rb_init(&context_vk->bo_slab_available, wined3d_bo_slab_vk_compare);
 
     return WINED3D_OK;
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index 0e39ad55a8c..ef5f3cd48e5 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -4484,6 +4484,57 @@ HRESULT wined3d_texture_no3d_init(struct wined3d_texture *texture_no3d, struct w
             flags, device, parent, parent_ops, &texture_no3d[1], &wined3d_texture_no3d_ops);
 }
 
+const VkDescriptorImageInfo *wined3d_texture_vk_get_default_image_info(struct wined3d_texture_vk *texture_vk,
+        struct wined3d_context_vk *context_vk)
+{
+    const struct wined3d_format_vk *format_vk;
+    const struct wined3d_vk_info *vk_info;
+    struct wined3d_device_vk *device_vk;
+    VkImageViewCreateInfo create_info;
+    uint32_t flags = 0;
+    VkResult vr;
+
+    if (texture_vk->default_image_info.imageView)
+        return &texture_vk->default_image_info;
+
+    format_vk = wined3d_format_vk(texture_vk->t.resource.format);
+    device_vk = wined3d_device_vk(texture_vk->t.resource.device);
+    vk_info = context_vk->vk_info;
+
+    if (texture_vk->t.layer_count > 1)
+        flags |= WINED3D_VIEW_TEXTURE_ARRAY;
+
+    wined3d_texture_vk_prepare_texture(texture_vk, context_vk);
+    create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+    create_info.pNext = NULL;
+    create_info.flags = 0;
+    create_info.image = texture_vk->vk_image;
+    create_info.viewType = vk_image_view_type_from_wined3d(texture_vk->t.resource.type, flags);
+    create_info.format = format_vk->vk_format;
+    create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+    create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+    create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+    create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+    create_info.subresourceRange.aspectMask = vk_aspect_mask_from_format(&format_vk->f);
+    create_info.subresourceRange.baseMipLevel = 0;
+    create_info.subresourceRange.levelCount = texture_vk->t.level_count;
+    create_info.subresourceRange.baseArrayLayer = 0;
+    create_info.subresourceRange.layerCount = texture_vk->t.layer_count;
+    if ((vr = VK_CALL(vkCreateImageView(device_vk->vk_device, &create_info,
+            NULL, &texture_vk->default_image_info.imageView))) < 0)
+    {
+        ERR("Failed to create Vulkan image view, vr %s.\n", wined3d_debug_vkresult(vr));
+        return NULL;
+    }
+
+    TRACE("Created image view 0x%s.\n", wine_dbgstr_longlong(texture_vk->default_image_info.imageView));
+
+    texture_vk->default_image_info.sampler = VK_NULL_HANDLE;
+    texture_vk->default_image_info.imageLayout = texture_vk->layout;
+
+    return &texture_vk->default_image_info;
+}
+
 static void wined3d_texture_vk_upload_data(struct wined3d_context *context,
         const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format,
         const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch,
@@ -5042,6 +5093,13 @@ static void wined3d_texture_vk_unload_location(struct wined3d_texture *texture,
     switch (location)
     {
         case WINED3D_LOCATION_TEXTURE_RGB:
+            if (texture_vk->default_image_info.imageView)
+            {
+                wined3d_context_vk_destroy_image_view(context_vk,
+                        texture_vk->default_image_info.imageView, texture_vk->command_buffer_id);
+                texture_vk->default_image_info.imageView = VK_NULL_HANDLE;
+            }
+
             if (texture_vk->vk_image)
             {
                 wined3d_context_vk_destroy_image(context_vk, texture_vk->vk_image, texture_vk->command_buffer_id);
@@ -5419,7 +5477,7 @@ static void ffp_blitter_clear_rendertargets(struct wined3d_device *device, unsig
     context_release(context);
 }
 
-static bool ffp_blitter_use_cpu_clear(struct wined3d_rendertarget_view *view)
+static bool blitter_use_cpu_clear(struct wined3d_rendertarget_view *view)
 {
     struct wined3d_resource *resource;
     struct wined3d_texture *texture;
@@ -5458,7 +5516,7 @@ static void ffp_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_de
             if (!(view = fb->render_targets[i]))
                 continue;
 
-            if (ffp_blitter_use_cpu_clear(view)
+            if (blitter_use_cpu_clear(view)
                     || (!(view->resource->bind_flags & WINED3D_BIND_RENDER_TARGET)
                     && (wined3d_settings.offscreen_rendering_mode != ORM_FBO
                     || !(view->format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE))))
@@ -5478,7 +5536,7 @@ static void ffp_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_de
     if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil)
             && (!view->format->depth_size || (flags & WINED3DCLEAR_ZBUFFER))
             && (!view->format->stencil_size || (flags & WINED3DCLEAR_STENCIL))
-            && ffp_blitter_use_cpu_clear(view))
+            && blitter_use_cpu_clear(view))
     {
         next_flags |= flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
         flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
@@ -5978,17 +6036,243 @@ static void vk_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_c
     heap_free(blitter);
 }
 
+static inline VkImageView wined3d_rendertarget_view_vk_get_image_view(struct wined3d_rendertarget_view_vk *rtv_vk,
+        struct wined3d_context_vk *context_vk)
+{
+    struct wined3d_texture_vk *texture_vk;
+
+    if (rtv_vk->vk_image_view)
+        return rtv_vk->vk_image_view;
+
+    texture_vk = wined3d_texture_vk(wined3d_texture_from_resource(rtv_vk->v.resource));
+    return wined3d_texture_vk_get_default_image_info(texture_vk, context_vk)->imageView;
+}
+
+static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk, unsigned int rt_count,
+        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];
+    struct wined3d_rendertarget_view_vk *rtv_vk;
+    struct wined3d_rendertarget_view *view;
+    const struct wined3d_vk_info *vk_info;
+    struct wined3d_texture_vk *texture_vk;
+    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;
+    unsigned int layer_count;
+    VkClearColorValue *c;
+    VkResult vr;
+    RECT r;
+
+    TRACE("context_vk %p, rt_count %u, fb %p, rect_count %u, clear_rects %p, "
+            "draw_rect %s, flags %#x, colour %s, depth %.8e, stencil %#x.\n",
+            context_vk, rt_count, fb, rect_count, clear_rects,
+            wine_dbgstr_rect(draw_rect), flags, debug_color(colour), depth, stencil);
+
+    device_vk = wined3d_device_vk(context_vk->c.device);
+    vk_info = context_vk->vk_info;
+
+    for (i = 0, attachment_count = 0, layer_count = 1; i < rt_count; ++i)
+    {
+        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);
+        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);
+
+        c = &clear_values[attachment_count].color;
+        if (view->format_flags & WINED3DFMT_FLAG_INTEGER)
+        {
+            c->int32[0] = colour->r;
+            c->int32[1] = colour->g;
+            c->int32[2] = colour->b;
+            c->int32[3] = colour->a;
+        }
+        else
+        {
+            c->float32[0] = colour->r;
+            c->float32[1] = colour->g;
+            c->float32[2] = colour->b;
+            c->float32[3] = colour->a;
+        }
+
+        if (view->layer_count > layer_count)
+            layer_count = view->layer_count;
+
+        ++attachment_count;
+    }
+
+    if (!(vk_render_pass = wined3d_context_vk_get_render_pass(context_vk, fb, rt_count)))
+    {
+        ERR("Failed to get render pass.\n");
+        return;
+    }
+
+    if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
+    {
+        ERR("Failed to get command buffer.\n");
+        return;
+    }
+
+    fb_desc.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+    fb_desc.pNext = NULL;
+    fb_desc.flags = 0;
+    fb_desc.renderPass = vk_render_pass;
+    fb_desc.attachmentCount = attachment_count;
+    fb_desc.pAttachments = views;
+    fb_desc.width = draw_rect->right - draw_rect->left;
+    fb_desc.height = draw_rect->bottom - draw_rect->top;
+    fb_desc.layers = layer_count;
+    if ((vr = VK_CALL(vkCreateFramebuffer(device_vk->vk_device, &fb_desc, NULL, &vk_framebuffer))) < 0)
+    {
+        ERR("Failed to create Vulkan framebuffer, vr %s.\n", wined3d_debug_vkresult(vr));
+        return;
+    }
+
+    begin_desc.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+    begin_desc.pNext = NULL;
+    begin_desc.renderPass = vk_render_pass;
+    begin_desc.framebuffer = vk_framebuffer;
+    begin_desc.clearValueCount = attachment_count;
+    begin_desc.pClearValues = clear_values;
+
+    for (i = 0; i < rect_count; ++i)
+    {
+        r.left = max(clear_rects[i].left, draw_rect->left);
+        r.top = max(clear_rects[i].top, draw_rect->top);
+        r.right = min(clear_rects[i].right, draw_rect->right);
+        r.bottom = min(clear_rects[i].bottom, draw_rect->bottom);
+
+        if (r.left >= r.right || r.top >= r.bottom)
+            continue;
+
+        begin_desc.renderArea.offset.x = r.left;
+        begin_desc.renderArea.offset.y = r.top;
+        begin_desc.renderArea.extent.width = r.right - r.left;
+        begin_desc.renderArea.extent.height = r.bottom - r.top;
+        VK_CALL(vkCmdBeginRenderPass(vk_command_buffer, &begin_desc, VK_SUBPASS_CONTENTS_INLINE));
+        VK_CALL(vkCmdEndRenderPass(vk_command_buffer));
+    }
+
+    wined3d_context_vk_destroy_framebuffer(context_vk, vk_framebuffer, context_vk->current_command_buffer.id);
+
+    for (i = 0; i < rt_count; ++i)
+    {
+        if (!(view = fb->render_targets[i]))
+            continue;
+
+        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_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+                VK_ACCESS_COLOR_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_IMAGE_ASPECT_COLOR_BIT);
+    }
+}
+
 static void vk_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
         unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
         const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
 {
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(device);
+    struct wined3d_rendertarget_view *view, *previous = NULL;
+    struct wined3d_context_vk *context_vk;
+    bool have_identical_size = true;
+    struct wined3d_fb_state tmp_fb;
+    unsigned int next_rt_count = 0;
     struct wined3d_blitter *next;
+    uint32_t next_flags = 0;
+    unsigned int i;
 
     TRACE("blitter %p, device %p, rt_count %u, fb %p, rect_count %u, clear_rects %p, "
             "draw_rect %s, flags %#x, colour %s, depth %.8e, stencil %#x.\n",
             blitter, device, rt_count, fb, rect_count, clear_rects,
             wine_dbgstr_rect(draw_rect), flags, debug_color(colour), depth, stencil);
 
+    if (!rect_count)
+    {
+        rect_count = 1;
+        clear_rects = draw_rect;
+    }
+
+    if (flags & WINED3DCLEAR_TARGET)
+    {
+        for (i = 0; i < rt_count; ++i)
+        {
+            if (!(view = fb->render_targets[i]))
+                continue;
+
+            if (blitter_use_cpu_clear(view))
+            {
+                next_flags |= WINED3DCLEAR_TARGET;
+                flags &= ~WINED3DCLEAR_TARGET;
+                next_rt_count = rt_count;
+                rt_count = 0;
+                break;
+            }
+        }
+    }
+
+    if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && fb->depth_stencil)
+    {
+        next_flags |= flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
+        flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
+    }
+
+    if (flags)
+    {
+        context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
+
+        for (i = 0; i < rt_count; ++i)
+        {
+            if (!(view = fb->render_targets[i]))
+                continue;
+
+            if (previous && (previous->width != view->width || previous->height != view->height))
+                have_identical_size = false;
+            previous = view;
+        }
+
+        if (have_identical_size)
+        {
+            vk_blitter_clear_rendertargets(context_vk, rt_count, fb, rect_count,
+                    clear_rects, draw_rect, flags, colour, depth, stencil);
+        }
+        else
+        {
+            for (i = 0; i < rt_count; ++i)
+            {
+                if (!(view = fb->render_targets[i]))
+                    continue;
+
+                tmp_fb.render_targets[0] = view;
+                tmp_fb.depth_stencil = NULL;
+                vk_blitter_clear_rendertargets(context_vk, 1, &tmp_fb, rect_count,
+                        clear_rects, draw_rect, WINED3DCLEAR_TARGET, colour, depth, stencil);
+            }
+        }
+
+        context_release(&context_vk->c);
+    }
+
+    if (!next_flags)
+        return;
+
     if (!(next = blitter->next))
     {
         ERR("No blitter to handle clear.\n");
@@ -5996,8 +6280,8 @@ static void vk_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_dev
     }
 
     TRACE("Forwarding to blitter %p.\n", next);
-    next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
-            clear_rects, draw_rect, flags, colour, depth, stencil);
+    next->ops->blitter_clear(next, device, next_rt_count, fb, rect_count,
+            clear_rects, draw_rect, next_flags, colour, depth, stencil);
 }
 
 static bool vk_blitter_blit_supported(enum wined3d_blit_op op, const struct wined3d_context *context,
diff --git a/dlls/wined3d/view.c b/dlls/wined3d/view.c
index 438d9a8b18f..fee64bd47d2 100644
--- a/dlls/wined3d/view.c
+++ b/dlls/wined3d/view.c
@@ -621,7 +621,7 @@ HRESULT wined3d_rendertarget_view_gl_init(struct wined3d_rendertarget_view_gl *v
     return hr;
 }
 
-static VkImageViewType vk_image_view_type_from_wined3d(enum wined3d_resource_type type, uint32_t flags)
+VkImageViewType vk_image_view_type_from_wined3d(enum wined3d_resource_type type, uint32_t flags)
 {
     switch (type)
     {
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 43bdb26c936..dd8e03d35d9 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -300,6 +300,7 @@ extern const GLenum magLookup[WINED3D_TEXF_LINEAR + 1] DECLSPEC_HIDDEN;
 
 GLenum wined3d_gl_compare_func(enum wined3d_cmp_func f) DECLSPEC_HIDDEN;
 VkAccessFlags vk_access_mask_from_bind_flags(uint32_t bind_flags) DECLSPEC_HIDDEN;
+VkImageViewType vk_image_view_type_from_wined3d(enum wined3d_resource_type type, uint32_t flags) DECLSPEC_HIDDEN;
 
 static inline enum wined3d_cmp_func wined3d_sanitize_cmp_func(enum wined3d_cmp_func func)
 {
@@ -2223,6 +2224,7 @@ struct wined3d_command_buffer_vk
 enum wined3d_retired_object_type_vk
 {
     WINED3D_RETIRED_FREE_VK,
+    WINED3D_RETIRED_FRAMEBUFFER_VK,
     WINED3D_RETIRED_MEMORY_VK,
     WINED3D_RETIRED_ALLOCATOR_BLOCK_VK,
     WINED3D_RETIRED_BO_SLAB_SLICE_VK,
@@ -2237,6 +2239,7 @@ struct wined3d_retired_object_vk
     union
     {
         struct wined3d_retired_object_vk *next;
+        VkFramebuffer vk_framebuffer;
         VkDeviceMemory vk_memory;
         struct wined3d_allocator_block *block;
         struct
@@ -2259,6 +2262,26 @@ struct wined3d_retired_objects_vk
     SIZE_T count;
 };
 
+struct wined3d_render_pass_attachment_vk
+{
+    VkFormat vk_format;
+    VkSampleCountFlagBits vk_samples;
+    VkImageLayout vk_layout;
+};
+
+struct wined3d_render_pass_key_vk
+{
+    struct wined3d_render_pass_attachment_vk rt[WINED3D_MAX_RENDER_TARGETS];
+    uint32_t rt_mask;
+};
+
+struct wined3d_render_pass_vk
+{
+    struct wine_rb_entry entry;
+    struct wined3d_render_pass_key_vk key;
+    VkRenderPass vk_render_pass;
+};
+
 struct wined3d_context_vk
 {
     struct wined3d_context c;
@@ -2277,6 +2300,7 @@ struct wined3d_context_vk
     } submitted;
 
     struct wined3d_retired_objects_vk retired;
+    struct wine_rb_tree render_passes;
     struct wine_rb_tree bo_slab_available;
 };
 
@@ -2296,6 +2320,8 @@ void wined3d_context_vk_destroy_allocator_block(struct wined3d_context_vk *conte
         struct wined3d_allocator_block *block, uint64_t command_buffer_id) DECLSPEC_HIDDEN;
 void wined3d_context_vk_destroy_bo(struct wined3d_context_vk *context_vk,
         const struct wined3d_bo_vk *bo) DECLSPEC_HIDDEN;
+void wined3d_context_vk_destroy_framebuffer(struct wined3d_context_vk *context_vk,
+        VkFramebuffer vk_framebuffer, uint64_t command_buffer_id) DECLSPEC_HIDDEN;
 void wined3d_context_vk_destroy_image(struct wined3d_context_vk *context_vk,
         VkImage vk_image, uint64_t command_buffer_id) DECLSPEC_HIDDEN;
 void wined3d_context_vk_destroy_image_view(struct wined3d_context_vk *context_vk,
@@ -2303,6 +2329,8 @@ void wined3d_context_vk_destroy_image_view(struct wined3d_context_vk *context_vk
 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;
 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,
@@ -3996,6 +4024,8 @@ struct wined3d_texture_vk
     VkDeviceMemory vk_memory;
     enum VkImageLayout layout;
     uint64_t command_buffer_id;
+
+    VkDescriptorImageInfo default_image_info;
 };
 
 static inline struct wined3d_texture_vk *wined3d_texture_vk(struct wined3d_texture *texture)
@@ -4003,6 +4033,8 @@ static inline struct wined3d_texture_vk *wined3d_texture_vk(struct wined3d_textu
     return CONTAINING_RECORD(texture, struct wined3d_texture_vk, t);
 }
 
+const VkDescriptorImageInfo *wined3d_texture_vk_get_default_image_info(struct wined3d_texture_vk *texture_vk,
+        struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN;
 HRESULT wined3d_texture_vk_init(struct wined3d_texture_vk *texture_vk, struct wined3d_device *device,
         const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count,
         uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops) DECLSPEC_HIDDEN;
@@ -5490,17 +5522,30 @@ static inline void wined3d_context_copy_bo_address(struct wined3d_context *conte
     context->device->adapter->adapter_ops->adapter_copy_bo_address(context, dst, src, size);
 }
 
-static inline void wined3d_context_vk_reference_bo(struct wined3d_context_vk *context_vk, struct wined3d_bo_vk *bo)
+static inline void wined3d_context_vk_reference_bo(const struct wined3d_context_vk *context_vk,
+        struct wined3d_bo_vk *bo)
 {
     bo->command_buffer_id = context_vk->current_command_buffer.id;
 }
 
-static inline void wined3d_context_vk_reference_texture(struct wined3d_context_vk *context_vk,
+static inline void wined3d_context_vk_reference_texture(const struct wined3d_context_vk *context_vk,
         struct wined3d_texture_vk *texture_vk)
 {
     texture_vk->command_buffer_id = context_vk->current_command_buffer.id;
 }
 
+static inline void wined3d_context_vk_reference_rendertarget_view(const struct wined3d_context_vk *context_vk,
+        struct wined3d_rendertarget_view_vk *rtv_vk)
+{
+    struct wined3d_resource *resource = rtv_vk->v.resource;
+
+    if (resource->type == WINED3D_RTYPE_BUFFER)
+        wined3d_context_vk_reference_bo(context_vk, &wined3d_buffer_vk(buffer_from_resource(resource))->bo);
+    else
+        wined3d_context_vk_reference_texture(context_vk, wined3d_texture_vk(texture_from_resource(resource)));
+    rtv_vk->command_buffer_id = context_vk->current_command_buffer.id;
+}
+
 static inline BOOL wined3d_dsv_srv_conflict(const struct wined3d_rendertarget_view *dsv,
         const struct wined3d_format *srv_format)
 {
-- 
2.20.1




More information about the wine-devel mailing list