Vulkan: Image Views
The ownership of image views depends on how they are used. When used as an framebuffer attachment the image view is owned by the framebuffer. When used as a image/texture in a shader the ownership of the image view is the texture itself. Pull Request: https://projects.blender.org/blender/blender/pulls/108765
This commit is contained in:
@@ -215,6 +215,7 @@ set(VULKAN_SRC
|
||||
vulkan/vk_drawlist.cc
|
||||
vulkan/vk_fence.cc
|
||||
vulkan/vk_framebuffer.cc
|
||||
vulkan/vk_image_view.cc
|
||||
vulkan/vk_immediate.cc
|
||||
vulkan/vk_index_buffer.cc
|
||||
vulkan/vk_memory.cc
|
||||
@@ -250,6 +251,7 @@ set(VULKAN_SRC
|
||||
vulkan/vk_drawlist.hh
|
||||
vulkan/vk_fence.hh
|
||||
vulkan/vk_framebuffer.hh
|
||||
vulkan/vk_image_view.hh
|
||||
vulkan/vk_immediate.hh
|
||||
vulkan/vk_index_buffer.hh
|
||||
vulkan/vk_memory.hh
|
||||
|
||||
@@ -174,7 +174,7 @@ void VKDescriptorSetTracker::update(VKContext &context)
|
||||
binding.texture->layout_ensure(context, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
VkDescriptorImageInfo image_info = {};
|
||||
image_info.sampler = binding.vk_sampler;
|
||||
image_info.imageView = binding.texture->vk_image_view_handle();
|
||||
image_info.imageView = binding.texture->image_view_get().vk_handle();
|
||||
image_info.imageLayout = binding.texture->current_layout_get();
|
||||
image_infos.append(image_info);
|
||||
|
||||
|
||||
@@ -372,6 +372,8 @@ void VKFrameBuffer::render_pass_create()
|
||||
std::array<VkAttachmentDescription, GPU_FB_MAX_ATTACHMENT> attachment_descriptions;
|
||||
std::array<VkImageView, GPU_FB_MAX_ATTACHMENT> image_views;
|
||||
std::array<VkAttachmentReference, GPU_FB_MAX_ATTACHMENT> attachment_references;
|
||||
image_views_.clear();
|
||||
|
||||
bool has_depth_attachment = false;
|
||||
bool found_attachment = false;
|
||||
int depth_location = -1;
|
||||
@@ -402,7 +404,8 @@ void VKFrameBuffer::render_pass_create()
|
||||
/* Ensure texture is allocated to ensure the image view. */
|
||||
VKTexture &texture = *static_cast<VKTexture *>(unwrap(attachment.tex));
|
||||
texture.ensure_allocated();
|
||||
image_views[attachment_location] = texture.vk_image_view_handle();
|
||||
image_views_.append(VKImageView(texture, attachment.mip, name_));
|
||||
image_views[attachment_location] = image_views_.last().vk_handle();
|
||||
|
||||
VkAttachmentDescription &attachment_description =
|
||||
attachment_descriptions[attachment_location];
|
||||
@@ -411,10 +414,10 @@ void VKFrameBuffer::render_pass_create()
|
||||
attachment_description.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
attachment_description.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
attachment_description.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachment_description.initialLayout = texture.current_layout_get();
|
||||
attachment_description.finalLayout = texture.current_layout_get();
|
||||
|
||||
/* Create the attachment reference. */
|
||||
const bool is_depth_attachment = ELEM(
|
||||
@@ -497,6 +500,7 @@ void VKFrameBuffer::render_pass_free()
|
||||
vkDestroyRenderPass(device.device_get(), vk_render_pass_, vk_allocation_callbacks);
|
||||
vkDestroyFramebuffer(device.device_get(), vk_framebuffer_, vk_allocation_callbacks);
|
||||
}
|
||||
image_views_.clear();
|
||||
vk_render_pass_ = VK_NULL_HANDLE;
|
||||
vk_framebuffer_ = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "gpu_framebuffer_private.hh"
|
||||
|
||||
#include "vk_common.hh"
|
||||
#include "vk_image_view.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
@@ -41,6 +42,8 @@ class VKFrameBuffer : public FrameBuffer {
|
||||
*/
|
||||
bool flip_viewport_ = false;
|
||||
|
||||
Vector<VKImageView, GPU_FB_MAX_ATTACHMENT> image_views_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create a conventional framebuffer to attach texture to.
|
||||
|
||||
68
source/blender/gpu/vulkan/vk_image_view.cc
Normal file
68
source/blender/gpu/vulkan/vk_image_view.cc
Normal file
@@ -0,0 +1,68 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#include "vk_image_view.hh"
|
||||
#include "vk_backend.hh"
|
||||
#include "vk_debug.hh"
|
||||
#include "vk_device.hh"
|
||||
#include "vk_memory.hh"
|
||||
#include "vk_texture.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
VKImageView::VKImageView(VKTexture &texture, int mip_level, StringRefNull name)
|
||||
: vk_image_view_(create_vk_image_view(texture, mip_level, name))
|
||||
{
|
||||
BLI_assert(vk_image_view_ != VK_NULL_HANDLE);
|
||||
}
|
||||
|
||||
VKImageView::VKImageView(VkImageView vk_image_view) : vk_image_view_(vk_image_view)
|
||||
{
|
||||
BLI_assert(vk_image_view_ != VK_NULL_HANDLE);
|
||||
}
|
||||
|
||||
VKImageView::VKImageView(VKImageView &&other)
|
||||
{
|
||||
vk_image_view_ = other.vk_image_view_;
|
||||
other.vk_image_view_ = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VKImageView::~VKImageView()
|
||||
{
|
||||
if (vk_image_view_ != VK_NULL_HANDLE) {
|
||||
VK_ALLOCATION_CALLBACKS
|
||||
const VKDevice &device = VKBackend::get().device_get();
|
||||
vkDestroyImageView(device.device_get(), vk_image_view_, vk_allocation_callbacks);
|
||||
}
|
||||
}
|
||||
VkImageView VKImageView::create_vk_image_view(VKTexture &texture,
|
||||
int mip_level,
|
||||
StringRefNull name)
|
||||
{
|
||||
|
||||
VK_ALLOCATION_CALLBACKS
|
||||
VkImageViewCreateInfo image_view_info = {};
|
||||
image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
image_view_info.image = texture.vk_image_handle();
|
||||
image_view_info.viewType = to_vk_image_view_type(texture.type_get());
|
||||
image_view_info.format = to_vk_format(texture.format_get());
|
||||
image_view_info.components = to_vk_component_mapping(texture.format_get());
|
||||
image_view_info.subresourceRange.aspectMask = to_vk_image_aspect_flag_bits(texture.format_get());
|
||||
image_view_info.subresourceRange.baseMipLevel = mip_level;
|
||||
image_view_info.subresourceRange.levelCount = 1;
|
||||
image_view_info.subresourceRange.baseArrayLayer = 0;
|
||||
image_view_info.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
||||
|
||||
const VKDevice &device = VKBackend::get().device_get();
|
||||
VkImageView image_view = VK_NULL_HANDLE;
|
||||
vkCreateImageView(device.device_get(), &image_view_info, vk_allocation_callbacks, &image_view);
|
||||
debug::object_label(image_view, name.c_str());
|
||||
return image_view;
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
||||
44
source/blender/gpu/vulkan/vk_image_view.hh
Normal file
44
source/blender/gpu/vulkan/vk_image_view.hh
Normal file
@@ -0,0 +1,44 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vk_common.hh"
|
||||
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_utility_mixins.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
class VKTexture;
|
||||
|
||||
class VKImageView : NonCopyable {
|
||||
VkImageView vk_image_view_ = VK_NULL_HANDLE;
|
||||
|
||||
public:
|
||||
VKImageView(VKTexture &texture, int mip_level, StringRefNull name);
|
||||
|
||||
/**
|
||||
* Wrap the given vk_image_view handle. Note that the vk_image_view handle ownership is
|
||||
* transferred to VKImageView.
|
||||
*/
|
||||
VKImageView(VkImageView vk_image_view);
|
||||
|
||||
VKImageView(VKImageView &&other);
|
||||
~VKImageView();
|
||||
|
||||
VkImageView vk_handle() const
|
||||
{
|
||||
BLI_assert(vk_image_view_ != VK_NULL_HANDLE);
|
||||
return vk_image_view_;
|
||||
}
|
||||
|
||||
private:
|
||||
static VkImageView create_vk_image_view(VKTexture &texture, int mip_level, StringRefNull name);
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
||||
@@ -25,11 +25,9 @@ namespace blender::gpu {
|
||||
|
||||
VKTexture::~VKTexture()
|
||||
{
|
||||
VK_ALLOCATION_CALLBACKS
|
||||
if (is_allocated()) {
|
||||
const VKDevice &device = VKBackend::get().device_get();
|
||||
vmaDestroyImage(device.mem_allocator_get(), vk_image_, allocation_);
|
||||
vkDestroyImageView(device.device_get(), vk_image_view_, vk_allocation_callbacks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +81,9 @@ void VKTexture::generate_mipmap()
|
||||
*this,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
Span<VkImageBlit>(&image_blit, 1));
|
||||
/* TODO: Until we do actual command encoding we need to submit each transfer operation
|
||||
* individually. */
|
||||
command_buffer.submit();
|
||||
}
|
||||
/* Ensure that all mipmap levels are in `VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL`. All miplevels are
|
||||
* except the last one. */
|
||||
@@ -148,9 +149,12 @@ void VKTexture::swizzle_set(const char /*swizzle_mask*/[4])
|
||||
NOT_YET_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void VKTexture::mip_range_set(int /*min*/, int /*max*/)
|
||||
void VKTexture::mip_range_set(int min, int max)
|
||||
{
|
||||
NOT_YET_IMPLEMENTED;
|
||||
mip_min_ = min;
|
||||
mip_max_ = max;
|
||||
|
||||
flags_ |= IMAGE_VIEW_DIRTY;
|
||||
}
|
||||
|
||||
void VKTexture::read_sub(int mip, eGPUDataFormat format, const int area[4], void *r_data)
|
||||
@@ -430,20 +434,6 @@ bool VKTexture::allocate()
|
||||
/* Promote image to the correct layout. */
|
||||
layout_ensure(context, VK_IMAGE_LAYOUT_GENERAL);
|
||||
|
||||
VK_ALLOCATION_CALLBACKS
|
||||
VkImageViewCreateInfo image_view_info = {};
|
||||
image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
image_view_info.image = vk_image_;
|
||||
image_view_info.viewType = to_vk_image_view_type(type_);
|
||||
image_view_info.format = to_vk_format(format_);
|
||||
image_view_info.components = to_vk_component_mapping(format_);
|
||||
image_view_info.subresourceRange.aspectMask = to_vk_image_aspect_flag_bits(format_);
|
||||
image_view_info.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
|
||||
image_view_info.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
||||
|
||||
result = vkCreateImageView(
|
||||
device.device_get(), &image_view_info, vk_allocation_callbacks, &vk_image_view_);
|
||||
debug::object_label(vk_image_view_, name_);
|
||||
return result == VK_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -525,6 +515,48 @@ void VKTexture::layout_ensure(VKContext &context,
|
||||
barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
||||
context.command_buffer_get().pipeline_barrier(Span<VkImageMemoryBarrier>(&barrier, 1));
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Image Views
|
||||
* \{ */
|
||||
|
||||
void VKTexture::image_view_ensure()
|
||||
{
|
||||
if (flags_ & IMAGE_VIEW_DIRTY) {
|
||||
image_view_update();
|
||||
flags_ &= ~IMAGE_VIEW_DIRTY;
|
||||
}
|
||||
}
|
||||
|
||||
void VKTexture::image_view_update()
|
||||
{
|
||||
VK_ALLOCATION_CALLBACKS
|
||||
VkImageViewCreateInfo image_view_info = {};
|
||||
image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
image_view_info.image = vk_image_;
|
||||
image_view_info.viewType = to_vk_image_view_type(type_);
|
||||
image_view_info.format = to_vk_format(format_);
|
||||
image_view_info.components = to_vk_component_mapping(format_);
|
||||
image_view_info.subresourceRange.aspectMask = to_vk_image_aspect_flag_bits(format_);
|
||||
IndexRange mip_range = mip_map_range();
|
||||
image_view_info.subresourceRange.baseMipLevel = mip_range.first();
|
||||
image_view_info.subresourceRange.levelCount = mip_range.size();
|
||||
image_view_info.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
||||
|
||||
const VKDevice &device = VKBackend::get().device_get();
|
||||
VkImageView image_view = VK_NULL_HANDLE;
|
||||
vkCreateImageView(device.device_get(), &image_view_info, vk_allocation_callbacks, &image_view);
|
||||
debug::object_label(image_view, name_);
|
||||
image_view_.emplace(image_view);
|
||||
}
|
||||
|
||||
IndexRange VKTexture::mip_map_range() const
|
||||
{
|
||||
return IndexRange(mip_min_, mip_max_ - mip_min_ + 1);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "gpu_texture_private.hh"
|
||||
|
||||
#include "vk_context.hh"
|
||||
#include "vk_image_view.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
@@ -17,15 +19,23 @@ class VKSampler;
|
||||
|
||||
class VKTexture : public Texture {
|
||||
VkImage vk_image_ = VK_NULL_HANDLE;
|
||||
VkImageView vk_image_view_ = VK_NULL_HANDLE;
|
||||
VmaAllocation allocation_ = VK_NULL_HANDLE;
|
||||
|
||||
/* Image view when used in a shader. */
|
||||
std::optional<VKImageView> image_view_;
|
||||
|
||||
/* Last image layout of the texture. Frame-buffer and barriers can alter/require the actual
|
||||
* layout to be changed. During this it requires to set the current layout in order to know which
|
||||
* conversion should happen. #current_layout_ keep track of the layout so the correct conversion
|
||||
* can be done. */
|
||||
VkImageLayout current_layout_ = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
enum eDirtyFlags {
|
||||
IMAGE_VIEW_DIRTY = (1 << 0),
|
||||
};
|
||||
|
||||
int flags_ = IMAGE_VIEW_DIRTY;
|
||||
|
||||
public:
|
||||
VKTexture(const char *name) : Texture(name) {}
|
||||
|
||||
@@ -58,11 +68,6 @@ class VKTexture : public Texture {
|
||||
BLI_assert(vk_image_ != VK_NULL_HANDLE);
|
||||
return vk_image_;
|
||||
}
|
||||
VkImageView vk_image_view_handle() const
|
||||
{
|
||||
BLI_assert(is_allocated());
|
||||
return vk_image_view_;
|
||||
}
|
||||
|
||||
void ensure_allocated();
|
||||
|
||||
@@ -123,6 +128,23 @@ class VKTexture : public Texture {
|
||||
VkImageLayout requested_layout);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Image Views
|
||||
* \{ */
|
||||
public:
|
||||
VKImageView &image_view_get()
|
||||
{
|
||||
image_view_ensure();
|
||||
return *image_view_;
|
||||
}
|
||||
|
||||
private:
|
||||
IndexRange mip_map_range() const;
|
||||
void image_view_ensure();
|
||||
void image_view_update();
|
||||
|
||||
/** \} */
|
||||
};
|
||||
|
||||
static inline VKTexture *unwrap(Texture *tex)
|
||||
|
||||
Reference in New Issue
Block a user