[PATCH 2/4] wined3d: Support buffer object backed textures in the Vulkan backend.

Jan Sikorski jsikorski at codeweavers.com
Thu Sep 2 08:14:21 CDT 2021


Signed-off-by: Jan Sikorski <jsikorski at codeweavers.com>
---
 dlls/wined3d/adapter_vk.c      |  29 +++-
 dlls/wined3d/texture.c         | 270 +++++++++++++++++++++++----------
 dlls/wined3d/wined3d_private.h |  14 +-
 3 files changed, 231 insertions(+), 82 deletions(-)

diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c
index c7da02865ea..1db25a4d72f 100644
--- a/dlls/wined3d/adapter_vk.c
+++ b/dlls/wined3d/adapter_vk.c
@@ -856,7 +856,7 @@ void wined3d_bo_slab_vk_unmap(struct wined3d_bo_slab_vk *slab_vk, struct wined3d
     slab_vk->map_ptr = NULL;
 }
 
-static VkAccessFlags vk_access_mask_from_buffer_usage(VkBufferUsageFlags usage)
+VkAccessFlags vk_access_mask_from_buffer_usage(VkBufferUsageFlags usage)
 {
     VkAccessFlags flags = 0;
 
@@ -877,6 +877,33 @@ static VkAccessFlags vk_access_mask_from_buffer_usage(VkBufferUsageFlags usage)
     if (usage & VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT)
         flags |= VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT
                 | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT;
+    if (usage & VK_BUFFER_USAGE_TRANSFER_SRC_BIT)
+        flags |= VK_ACCESS_TRANSFER_READ_BIT;
+    if (usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT)
+        flags |= VK_ACCESS_TRANSFER_WRITE_BIT;
+
+    return flags;
+}
+
+VkPipelineStageFlags vk_pipeline_stage_mask_from_buffer_usage(VkBufferUsageFlags usage)
+{
+    VkPipelineStageFlags flags = 0;
+
+    if (usage & (VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT))
+        flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
+    if (usage & (VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT
+            | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT))
+        flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
+                | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT
+                | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT
+                | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
+    if (usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT)
+        flags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
+    if (usage & (VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT
+            | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT))
+        flags |= VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT;
+    if (usage & (VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT))
+        flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
 
     return flags;
 }
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index 6663e788e9c..49a8d4ead8b 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -49,8 +49,10 @@ struct wined3d_rect_f
 
 static BOOL wined3d_texture_use_pbo(const struct wined3d_texture *texture, const struct wined3d_gl_info *gl_info)
 {
-    if (!gl_info->supported[ARB_PIXEL_BUFFER_OBJECT]
-            || texture->resource.format->conv_byte_count
+    if (gl_info->selected_gl_version && !gl_info->supported[ARB_PIXEL_BUFFER_OBJECT])
+        return FALSE;
+
+    if (texture->resource.format->conv_byte_count
             || (texture->flags & (WINED3D_TEXTURE_PIN_SYSMEM | WINED3D_TEXTURE_COND_NP2_EMULATED)))
         return FALSE;
 
@@ -851,7 +853,7 @@ void wined3d_texture_get_memory(struct wined3d_texture *texture, unsigned int su
 static void wined3d_texture_remove_buffer_object(struct wined3d_texture *texture,
         unsigned int sub_resource_idx, struct wined3d_context_gl *context_gl)
 {
-    struct wined3d_bo_gl *bo = &texture->sub_resources[sub_resource_idx].bo;
+    struct wined3d_bo_gl *bo = &texture->sub_resources[sub_resource_idx].bo.gl;
 
     TRACE("texture %p, sub_resource_idx %u, context_gl %p.\n", texture, sub_resource_idx, context_gl);
 
@@ -859,6 +861,12 @@ static void wined3d_texture_remove_buffer_object(struct wined3d_texture *texture
     wined3d_texture_invalidate_location(texture, sub_resource_idx, WINED3D_LOCATION_BUFFER);
 }
 
+static void wined3d_texture_unload_location(struct wined3d_texture *texture,
+        struct wined3d_context *context, unsigned int location)
+{
+    texture->texture_ops->texture_unload_location(texture, context, location);
+}
+
 static void wined3d_texture_update_map_binding(struct wined3d_texture *texture)
 {
     unsigned int sub_count = texture->level_count * texture->layer_count;
@@ -874,10 +882,11 @@ static void wined3d_texture_update_map_binding(struct wined3d_texture *texture)
         if (texture->sub_resources[i].locations == texture->resource.map_binding
                 && !wined3d_texture_load_location(texture, i, context, map_binding))
             ERR("Failed to load location %s.\n", wined3d_debug_location(map_binding));
-        if (texture->resource.map_binding == WINED3D_LOCATION_BUFFER)
-            wined3d_texture_remove_buffer_object(texture, i, wined3d_context_gl(context));
     }
 
+    if (texture->resource.map_binding == WINED3D_LOCATION_BUFFER)
+        wined3d_texture_unload_location(texture, context, WINED3D_LOCATION_BUFFER);
+
     context_release(context);
 
     texture->resource.map_binding = map_binding;
@@ -1980,7 +1989,7 @@ static void wined3d_texture_gl_prepare_buffer_object(struct wined3d_texture_gl *
     struct wined3d_bo_gl *bo;
 
     sub_resource = &texture_gl->t.sub_resources[sub_resource_idx];
-    bo = &sub_resource->bo;
+    bo = &sub_resource->bo.gl;
     if (bo->id)
         return;
 
@@ -2110,12 +2119,6 @@ BOOL wined3d_texture_prepare_location(struct wined3d_texture *texture,
     return texture->texture_ops->texture_prepare_location(texture, sub_resource_idx, context, location);
 }
 
-static void wined3d_texture_unload_location(struct wined3d_texture *texture,
-        struct wined3d_context *context, unsigned int location)
-{
-    texture->texture_ops->texture_unload_location(texture, context, location);
-}
-
 static struct wined3d_texture_sub_resource *wined3d_texture_get_sub_resource(struct wined3d_texture *texture,
         unsigned int sub_resource_idx)
 {
@@ -3152,7 +3155,7 @@ static BOOL wined3d_texture_gl_load_texture(struct wined3d_texture_gl *texture_g
     /* Don't use PBOs for converted surfaces. During PBO conversion we look at
      * WINED3D_TEXTURE_CONVERTED but it isn't set (yet) in all cases it is
      * getting called. */
-    if (conversion && sub_resource->bo.id)
+    if (conversion && sub_resource->bo.gl.id)
     {
         TRACE("Removing the pbo attached to texture %p, %u.\n", texture_gl, sub_resource_idx);
 
@@ -3289,7 +3292,7 @@ static void wined3d_texture_gl_unload_location(struct wined3d_texture *texture,
             sub_count = texture->level_count * texture->layer_count;
             for (i = 0; i < sub_count; ++i)
             {
-                if (texture_gl->t.sub_resources[i].bo.id)
+                if (texture_gl->t.sub_resources[i].bo.gl.id)
                     wined3d_texture_remove_buffer_object(&texture_gl->t, i, context_gl);
             }
             break;
@@ -4657,11 +4660,14 @@ static void wined3d_texture_vk_upload_data(struct wined3d_context *context,
     unsigned int dst_level, dst_row_pitch, dst_slice_pitch;
     struct wined3d_texture_sub_resource *sub_resource;
     struct wined3d_bo_address staging_bo_addr;
+    VkPipelineStageFlags bo_stage_flags = 0;
     const struct wined3d_vk_info *vk_info;
     VkCommandBuffer vk_command_buffer;
+    VkBufferMemoryBarrier vk_barrier;
     VkImageSubresourceRange vk_range;
     struct wined3d_bo_vk staging_bo;
     VkImageAspectFlags aspect_mask;
+    struct wined3d_bo_vk *src_bo;
     struct wined3d_range range;
     VkBufferImageCopy region;
     size_t src_offset;
@@ -4673,12 +4679,6 @@ static void wined3d_texture_vk_upload_data(struct wined3d_context *context,
             src_row_pitch, src_slice_pitch, dst_texture, dst_sub_resource_idx,
             wined3d_debug_location(dst_location), dst_x, dst_y, dst_z);
 
-    if (src_bo_addr->buffer_object)
-    {
-        FIXME("Unhandled buffer object %#lx.\n", src_bo_addr->buffer_object);
-        return;
-    }
-
     if (src_format->id != dst_texture->resource.format->id)
     {
         FIXME("Unhandled format conversion (%s -> %s).\n",
@@ -4720,36 +4720,66 @@ static void wined3d_texture_vk_upload_data(struct wined3d_context *context,
             + (src_box->top / src_format->block_height) * src_row_pitch
             + (src_box->left / src_format->block_width) * src_format->block_byte_count;
 
-    if (!wined3d_context_vk_create_bo(context_vk, sub_resource->size,
-            VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &staging_bo))
+    if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
     {
-        ERR("Failed to create staging bo.\n");
+        ERR("Failed to get command buffer.\n");
+        if (!src_bo_addr->buffer_object)
+            wined3d_context_vk_destroy_bo(context_vk, &staging_bo);
         return;
     }
 
-    staging_bo_addr.buffer_object = (uintptr_t)&staging_bo;
-    staging_bo_addr.addr = NULL;
-    if (!(map_ptr = wined3d_context_map_bo_address(context, &staging_bo_addr,
-            sub_resource->size, WINED3D_MAP_DISCARD | WINED3D_MAP_WRITE)))
+    wined3d_context_vk_end_current_render_pass(context_vk);
+
+    if (!(src_bo = (struct wined3d_bo_vk *)src_bo_addr->buffer_object))
     {
-        ERR("Failed to map staging bo.\n");
-        wined3d_context_vk_destroy_bo(context_vk, &staging_bo);
-        return;
-    }
+        if (!wined3d_context_vk_create_bo(context_vk, sub_resource->size,
+                VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &staging_bo))
+        {
+            ERR("Failed to create staging bo.\n");
+            return;
+        }
 
-    wined3d_format_copy_data(src_format, src_bo_addr->addr + src_offset, src_row_pitch,
-            src_slice_pitch, map_ptr, dst_row_pitch, dst_slice_pitch, src_box->right - src_box->left,
-            src_box->bottom - src_box->top, src_box->back - src_box->front);
+        staging_bo_addr.buffer_object = (uintptr_t)&staging_bo;
+        staging_bo_addr.addr = NULL;
+        if (!(map_ptr = wined3d_context_map_bo_address(context, &staging_bo_addr,
+                sub_resource->size, WINED3D_MAP_DISCARD | WINED3D_MAP_WRITE)))
+        {
+            ERR("Failed to map staging bo.\n");
+            wined3d_context_vk_destroy_bo(context_vk, &staging_bo);
+            return;
+        }
 
-    range.offset = 0;
-    range.size = sub_resource->size;
-    wined3d_context_unmap_bo_address(context, &staging_bo_addr, 1, &range);
+        wined3d_format_copy_data(src_format, src_bo_addr->addr + src_offset, src_row_pitch,
+                src_slice_pitch, map_ptr, dst_row_pitch, dst_slice_pitch, src_box->right - src_box->left,
+                src_box->bottom - src_box->top, src_box->back - src_box->front);
 
-    if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
+        range.offset = 0;
+        range.size = sub_resource->size;
+        wined3d_context_unmap_bo_address(context, &staging_bo_addr, 1, &range);
+
+        src_bo = &staging_bo;
+
+        src_offset = 0;
+        src_row_pitch = dst_row_pitch;
+        src_slice_pitch = dst_slice_pitch;
+    }
+    else
     {
-        ERR("Failed to get command buffer.\n");
-        wined3d_context_vk_destroy_bo(context_vk, &staging_bo);
-        return;
+        vk_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
+        vk_barrier.pNext = NULL;
+        vk_barrier.srcAccessMask = vk_access_mask_from_buffer_usage(src_bo->usage) & ~WINED3D_READ_ONLY_ACCESS_FLAGS;
+        vk_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
+        vk_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+        vk_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+        vk_barrier.buffer = src_bo->vk_buffer;
+        vk_barrier.offset = src_bo->buffer_offset;
+        vk_barrier.size = src_bo->size;
+
+        bo_stage_flags = vk_pipeline_stage_mask_from_buffer_usage(src_bo->usage);
+
+        if (vk_barrier.srcAccessMask)
+            VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, bo_stage_flags,
+                    VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 1, &vk_barrier, 0, NULL));
     }
 
     vk_range.aspectMask = aspect_mask;
@@ -4765,10 +4795,10 @@ static void wined3d_texture_vk_upload_data(struct wined3d_context *context,
             dst_texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
             dst_texture_vk->image.vk_image, &vk_range);
 
-    region.bufferOffset = staging_bo.buffer_offset;
-    region.bufferRowLength = (dst_row_pitch / src_format->block_byte_count) * src_format->block_width;
-    if (dst_row_pitch)
-        region.bufferImageHeight = (dst_slice_pitch / dst_row_pitch) * src_format->block_height;
+    region.bufferOffset = src_bo->buffer_offset + src_offset;
+    region.bufferRowLength = (src_row_pitch / src_format->block_byte_count) * src_format->block_width;
+    if (src_row_pitch)
+        region.bufferImageHeight = (src_slice_pitch / src_row_pitch) * src_format->block_height;
     else
         region.bufferImageHeight = 1;
     region.imageSubresource.aspectMask = vk_range.aspectMask;
@@ -4782,7 +4812,7 @@ static void wined3d_texture_vk_upload_data(struct wined3d_context *context,
     region.imageExtent.height = src_box->bottom - src_box->top;
     region.imageExtent.depth = src_box->back - src_box->front;
 
-    VK_CALL(vkCmdCopyBufferToImage(vk_command_buffer, staging_bo.vk_buffer,
+    VK_CALL(vkCmdCopyBufferToImage(vk_command_buffer, src_bo->vk_buffer,
             dst_texture_vk->image.vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region));
 
     wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
@@ -4792,8 +4822,18 @@ static void wined3d_texture_vk_upload_data(struct wined3d_context *context,
             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_texture_vk->layout,
             dst_texture_vk->image.vk_image, &vk_range);
     wined3d_context_vk_reference_texture(context_vk, dst_texture_vk);
-    wined3d_context_vk_reference_bo(context_vk, &staging_bo);
-    wined3d_context_vk_destroy_bo(context_vk, &staging_bo);
+    wined3d_context_vk_reference_bo(context_vk, src_bo);
+
+    if (src_bo_addr->buffer_object)
+    {
+        if (vk_barrier.srcAccessMask)
+            VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
+                    bo_stage_flags, 0, 0, NULL, 0, NULL, 0, NULL));
+    }
+    else
+    {
+        wined3d_context_vk_destroy_bo(context_vk, &staging_bo);
+    }
 }
 
 static void wined3d_texture_vk_download_data(struct wined3d_context *context,
@@ -4808,11 +4848,14 @@ static void wined3d_texture_vk_download_data(struct wined3d_context *context,
     struct wined3d_texture_sub_resource *sub_resource;
     unsigned int src_row_pitch, src_slice_pitch;
     struct wined3d_bo_address staging_bo_addr;
+    VkPipelineStageFlags bo_stage_flags = 0;
     const struct wined3d_vk_info *vk_info;
     VkCommandBuffer vk_command_buffer;
     VkImageSubresourceRange vk_range;
+    VkBufferMemoryBarrier vk_barrier;
     struct wined3d_bo_vk staging_bo;
     VkImageAspectFlags aspect_mask;
+    struct wined3d_bo_vk *dst_bo;
     VkBufferImageCopy region;
     void *map_ptr;
 
@@ -4839,12 +4882,6 @@ static void wined3d_texture_vk_download_data(struct wined3d_context *context,
         return;
     }
 
-    if (dst_bo_addr->buffer_object)
-    {
-        FIXME("Unhandled buffer object %#lx.\n", dst_bo_addr->buffer_object);
-        return;
-    }
-
     if (dst_format->id != src_texture->resource.format->id)
     {
         FIXME("Unhandled format conversion (%s -> %s).\n",
@@ -4886,11 +4923,35 @@ static void wined3d_texture_vk_download_data(struct wined3d_context *context,
         return;
     }
 
-    if (!wined3d_context_vk_create_bo(context_vk, sub_resource->size,
-            VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &staging_bo))
+    wined3d_context_vk_end_current_render_pass(context_vk);
+
+    if (!(dst_bo = (struct wined3d_bo_vk *)dst_bo_addr->buffer_object))
     {
-        ERR("Failed to create staging bo.\n");
-        return;
+        if (!wined3d_context_vk_create_bo(context_vk, sub_resource->size,
+                VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &staging_bo))
+        {
+            ERR("Failed to create staging bo.\n");
+            return;
+        }
+
+        dst_bo = &staging_bo;
+    }
+    else
+    {
+        vk_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
+        vk_barrier.pNext = NULL;
+        vk_barrier.srcAccessMask = vk_access_mask_from_buffer_usage(dst_bo->usage);
+        vk_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+        vk_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+        vk_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+        vk_barrier.buffer = dst_bo->vk_buffer;
+        vk_barrier.offset = dst_bo->buffer_offset;
+        vk_barrier.size = dst_bo->size;
+
+        bo_stage_flags = vk_pipeline_stage_mask_from_buffer_usage(dst_bo->usage);
+
+        VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, bo_stage_flags,
+                VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 1, &vk_barrier, 0, NULL));
     }
 
     vk_range.aspectMask = aspect_mask;
@@ -4906,7 +4967,7 @@ static void wined3d_texture_vk_download_data(struct wined3d_context *context,
             src_texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
             src_texture_vk->image.vk_image, &vk_range);
 
-    region.bufferOffset = staging_bo.buffer_offset;
+    region.bufferOffset = dst_bo->buffer_offset;
     region.bufferRowLength = 0;
     region.bufferImageHeight = 0;
     region.imageSubresource.aspectMask = vk_range.aspectMask;
@@ -4921,7 +4982,7 @@ static void wined3d_texture_vk_download_data(struct wined3d_context *context,
     region.imageExtent.depth = src_depth;
 
     VK_CALL(vkCmdCopyImageToBuffer(vk_command_buffer, src_texture_vk->image.vk_image,
-            VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, staging_bo.vk_buffer, 1, &region));
+            VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_bo->vk_buffer, 1, &region));
 
     wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
             VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
@@ -4931,26 +4992,38 @@ static void wined3d_texture_vk_download_data(struct wined3d_context *context,
             src_texture_vk->image.vk_image, &vk_range);
 
     wined3d_context_vk_reference_texture(context_vk, src_texture_vk);
-    wined3d_context_vk_reference_bo(context_vk, &staging_bo);
-    wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL);
-    wined3d_context_vk_wait_command_buffer(context_vk, src_texture_vk->image.command_buffer_id);
+    wined3d_context_vk_reference_bo(context_vk, dst_bo);
 
-    staging_bo_addr.buffer_object = (uintptr_t)&staging_bo;
-    staging_bo_addr.addr = NULL;
-    if (!(map_ptr = wined3d_context_map_bo_address(context, &staging_bo_addr,
-            sub_resource->size, WINED3D_MAP_READ)))
+    if (dst_bo_addr->buffer_object)
     {
-        ERR("Failed to map staging bo.\n");
-        wined3d_context_vk_destroy_bo(context_vk, &staging_bo);
-        return;
+        vk_barrier.dstAccessMask = vk_barrier.srcAccessMask | VK_ACCESS_HOST_READ_BIT;
+        vk_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+
+        VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
+                bo_stage_flags | VK_PIPELINE_STAGE_HOST_BIT, 0, 0, NULL, 1, &vk_barrier, 0, NULL));
     }
+    else
+    {
+        wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL);
+        wined3d_context_vk_wait_command_buffer(context_vk, src_texture_vk->image.command_buffer_id);
 
-    wined3d_format_copy_data(dst_format, map_ptr, src_row_pitch, src_slice_pitch,
-            dst_bo_addr->addr, dst_row_pitch, dst_slice_pitch, src_box->right - src_box->left,
-            src_box->bottom - src_box->top, src_box->back - src_box->front);
+        staging_bo_addr.buffer_object = (uintptr_t)&staging_bo;
+        staging_bo_addr.addr = NULL;
+        if (!(map_ptr = wined3d_context_map_bo_address(context, &staging_bo_addr,
+                sub_resource->size, WINED3D_MAP_READ)))
+        {
+            ERR("Failed to map staging bo.\n");
+            wined3d_context_vk_destroy_bo(context_vk, &staging_bo);
+            return;
+        }
+
+        wined3d_format_copy_data(dst_format, map_ptr, src_row_pitch, src_slice_pitch,
+                dst_bo_addr->addr, dst_row_pitch, dst_slice_pitch, src_box->right - src_box->left,
+                src_box->bottom - src_box->top, src_box->back - src_box->front);
 
-    wined3d_context_unmap_bo_address(context, &staging_bo_addr, 0, NULL);
-    wined3d_context_vk_destroy_bo(context_vk, &staging_bo);
+        wined3d_context_unmap_bo_address(context, &staging_bo_addr, 0, NULL);
+        wined3d_context_vk_destroy_bo(context_vk, &staging_bo);
+    }
 }
 
 static BOOL wined3d_texture_vk_load_texture(struct wined3d_texture_vk *texture_vk,
@@ -4962,14 +5035,14 @@ static BOOL wined3d_texture_vk_load_texture(struct wined3d_texture_vk *texture_v
     struct wined3d_box src_box;
 
     sub_resource = &texture_vk->t.sub_resources[sub_resource_idx];
-    if (!(sub_resource->locations & WINED3D_LOCATION_SYSMEM))
+    if (!(sub_resource->locations & wined3d_texture_sysmem_locations))
     {
         ERR("Unimplemented load from %s.\n", wined3d_debug_location(sub_resource->locations));
         return FALSE;
     }
 
     level = sub_resource_idx % texture_vk->t.level_count;
-    wined3d_texture_get_memory(&texture_vk->t, sub_resource_idx, &data, WINED3D_LOCATION_SYSMEM);
+    wined3d_texture_get_memory(&texture_vk->t, sub_resource_idx, &data, sub_resource->locations);
     wined3d_texture_get_level_box(&texture_vk->t, level, &src_box);
     wined3d_texture_get_pitch(&texture_vk->t, level, &row_pitch, &slice_pitch);
     wined3d_texture_vk_upload_data(context, wined3d_const_bo_address(&data), texture_vk->t.resource.format,
@@ -4980,7 +5053,7 @@ static BOOL wined3d_texture_vk_load_texture(struct wined3d_texture_vk *texture_v
 }
 
 static BOOL wined3d_texture_vk_load_sysmem(struct wined3d_texture_vk *texture_vk,
-        unsigned int sub_resource_idx, struct wined3d_context *context)
+        unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location)
 {
     struct wined3d_texture_sub_resource *sub_resource;
     unsigned int level, row_pitch, slice_pitch;
@@ -4995,7 +5068,7 @@ static BOOL wined3d_texture_vk_load_sysmem(struct wined3d_texture_vk *texture_vk
     }
 
     level = sub_resource_idx % texture_vk->t.level_count;
-    wined3d_texture_get_memory(&texture_vk->t, sub_resource_idx, &data, WINED3D_LOCATION_SYSMEM);
+    wined3d_texture_get_memory(&texture_vk->t, sub_resource_idx, &data, location);
     wined3d_texture_get_level_box(&texture_vk->t, level, &src_box);
     wined3d_texture_get_pitch(&texture_vk->t, level, &row_pitch, &slice_pitch);
     wined3d_texture_vk_download_data(context, &texture_vk->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB,
@@ -5111,6 +5184,26 @@ BOOL wined3d_texture_vk_prepare_texture(struct wined3d_texture_vk *texture_vk,
     return TRUE;
 }
 
+static BOOL wined3d_texture_vk_prepare_buffer_object(struct wined3d_texture_vk *texture_vk,
+        unsigned int sub_resource_idx, struct wined3d_context_vk *context_vk)
+{
+    struct wined3d_texture_sub_resource *sub_resource;
+    struct wined3d_bo_vk *bo;
+
+    sub_resource = &texture_vk->t.sub_resources[sub_resource_idx];
+    bo = &sub_resource->bo.vk;
+    if (bo->vk_buffer)
+        return TRUE;
+
+    if (!wined3d_context_vk_create_bo(context_vk, sub_resource->size,
+            VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
+            VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, bo))
+        return FALSE;
+
+    TRACE("Created buffer object %p for texture %p, sub-resource %u.\n", bo, texture_vk, sub_resource_idx);
+    return TRUE;
+}
+
 static BOOL wined3d_texture_vk_prepare_location(struct wined3d_texture *texture,
         unsigned int sub_resource_idx, struct wined3d_context *context, unsigned int location)
 {
@@ -5123,6 +5216,10 @@ static BOOL wined3d_texture_vk_prepare_location(struct wined3d_texture *texture,
         case WINED3D_LOCATION_TEXTURE_RGB:
             return wined3d_texture_vk_prepare_texture(wined3d_texture_vk(texture), wined3d_context_vk(context));
 
+        case WINED3D_LOCATION_BUFFER:
+            return wined3d_texture_vk_prepare_buffer_object(wined3d_texture_vk(texture), sub_resource_idx,
+                    wined3d_context_vk(context));
+
         default:
             FIXME("Unhandled location %s.\n", wined3d_debug_location(location));
             return FALSE;
@@ -5141,7 +5238,8 @@ static BOOL wined3d_texture_vk_load_location(struct wined3d_texture *texture,
             return wined3d_texture_vk_load_texture(wined3d_texture_vk(texture), sub_resource_idx, context);
 
         case WINED3D_LOCATION_SYSMEM:
-            return wined3d_texture_vk_load_sysmem(wined3d_texture_vk(texture), sub_resource_idx, context);
+        case WINED3D_LOCATION_BUFFER:
+            return wined3d_texture_vk_load_sysmem(wined3d_texture_vk(texture), sub_resource_idx, context, location);
 
         default:
             FIXME("Unimplemented location %s.\n", wined3d_debug_location(location));
@@ -5154,6 +5252,7 @@ static void wined3d_texture_vk_unload_location(struct wined3d_texture *texture,
 {
     struct wined3d_texture_vk *texture_vk = wined3d_texture_vk(texture);
     struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
+    unsigned int i, sub_count;
 
     TRACE("texture %p, context %p, location %s.\n", texture, context, wined3d_debug_location(location));
 
@@ -5172,6 +5271,17 @@ static void wined3d_texture_vk_unload_location(struct wined3d_texture *texture,
             break;
 
         case WINED3D_LOCATION_BUFFER:
+            sub_count = texture->level_count * texture->layer_count;
+            for (i = 0; i < sub_count; ++i)
+            {
+                if (texture->sub_resources[i].bo.vk.vk_buffer)
+                {
+                    wined3d_context_vk_destroy_bo(context_vk, &texture->sub_resources[i].bo.vk);
+                    texture->sub_resources[i].bo.vk.vk_buffer = VK_NULL_HANDLE;
+                }
+            }
+            break;
+
         case WINED3D_LOCATION_TEXTURE_SRGB:
         case WINED3D_LOCATION_RB_MULTISAMPLE:
         case WINED3D_LOCATION_RB_RESOLVED:
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 6e9f3884724..dab19383b2d 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -313,12 +313,20 @@ extern const GLenum magLookup[WINED3D_TEXF_LINEAR + 1] DECLSPEC_HIDDEN;
 static const uint32_t WINED3D_READ_ONLY_BIND_MASK = WINED3D_BIND_VERTEX_BUFFER | WINED3D_BIND_INDEX_BUFFER
         | WINED3D_BIND_CONSTANT_BUFFER | WINED3D_BIND_SHADER_RESOURCE | WINED3D_BIND_INDIRECT_BUFFER;
 
+static const VkAccessFlags WINED3D_READ_ONLY_ACCESS_FLAGS = VK_ACCESS_INDIRECT_COMMAND_READ_BIT
+        | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT
+        | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
+        | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_HOST_READ_BIT
+        | VK_ACCESS_MEMORY_READ_BIT;
+
 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;
 VkCompareOp vk_compare_op_from_wined3d(enum wined3d_cmp_func op) DECLSPEC_HIDDEN;
 VkImageViewType vk_image_view_type_from_wined3d(enum wined3d_resource_type type, uint32_t flags) DECLSPEC_HIDDEN;
 VkPipelineStageFlags vk_pipeline_stage_mask_from_bind_flags(uint32_t bind_flags) DECLSPEC_HIDDEN;
 VkShaderStageFlagBits vk_shader_stage_from_wined3d(enum wined3d_shader_type shader_type) DECLSPEC_HIDDEN;
+VkAccessFlags vk_access_mask_from_buffer_usage(VkBufferUsageFlags usage) DECLSPEC_HIDDEN;
+VkPipelineStageFlags vk_pipeline_stage_mask_from_buffer_usage(VkBufferUsageFlags usage) DECLSPEC_HIDDEN;
 
 static inline enum wined3d_cmp_func wined3d_sanitize_cmp_func(enum wined3d_cmp_func func)
 {
@@ -4287,7 +4295,11 @@ struct wined3d_texture
         unsigned int map_count;
         uint32_t map_flags;
         DWORD locations;
-        struct wined3d_bo_gl bo;
+        union
+        {
+            struct wined3d_bo_gl gl;
+            struct wined3d_bo_vk vk;
+        } bo;
 
         void *user_memory;
     } *sub_resources;
-- 
2.30.2




More information about the wine-devel mailing list