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

Henri Verbeet hverbeet at gmail.com
Thu Sep 9 11:55:12 CDT 2021


On Thu, 2 Sept 2021 at 15:14, Jan Sikorski <jsikorski at codeweavers.com> wrote:
>  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;
> +
It's perhaps a bit of a hack that the existing code was never updated
to avoid using "gl_info" in what is now backend independent code, but
this change doesn't make it better. This should probably just store
something in the wined3d_d3d_info structure, similar to what we do
with e.g. "texture_npot".

> @@ -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);
> +
This seems fine, but is somewhat of an independent change.

> @@ -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;
> -    }
> -
Likewise, I think it would make sense for "Implement support for
buffer objects in wined3d_texture_vk_upload_data()" to be a separate
commit.

> -    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;
>      }
The staging bo would not have been created yet above.

> -    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);
> +
I assume we're ending the current render pass (if any) for
vkCmdCopyBufferToImage(). In principle
wined3d_context_vk_image_barrier() already takes care of that, but I
suppose it makes sense to be explicit about it. Perhaps it wouldn't
hurt to add a comment mentioning the reason we need to end the render
pass; I didn't add those for the existing instances of
wined3d_context_vk_end_current_render_pass(), and that may have been a
mistake. In any case, this too is somewhat of an independent change.

>      {
> -        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;
> +
This adds a barrier for the entire bo, not just the part we're reading
from. Perhaps that's ok though.

> -    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;

That ignores "src_bo_addr->addr". Currently that's probably always
going to be 0 in practice, but it wouldn't necessarily be if we e.g.
switched to using a single bo per texture instead of using a bo for
each sub-resource.

> +    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);
> +    }

Alternatively, we also sometimes write checks like these as "if
(src_bo == &staging_bo)". That may be slightly clearer, but I don't
feel strongly about it.

> @@ -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;
> -    }
> -
Some of the comments for wined3d_texture_vk_upload_data() apply to
wined3d_texture_vk_download_data() as well.

> +    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));
>      }

Do we need the HOST_READ bits in this patch? This seems like something
that belongs in 3/4, and should probably only be done for bo's that
have the "host_synced" flag set.

> @@ -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;
>
This is probably fine for the moment, but ideally we'd avoid backend
specific fields in the wined3d_texture_sub_resource structure.
Relatedly, we may want to use a single bo for the entire texture,
similar to how we use a single allocation for the system memory
location.



More information about the wine-devel mailing list