vulkan中的texture(VkImage、VkImageView、VkSampler、VkDeviceMemory)

在Vulkan中,以下是这几个概念的简要说明以及它们之间的关系:

  1. Texture2D

    • 纹理在vulkan API中并没有一个结构体来表示,它是着色器语言中(比如GLSL)的一种概念。在着色器中, sampler2D 类型的变量表示一个二维纹理。
  2. VkImage

    • 它是Vulkan中表示图像的对象,负责存储图像的元数据(metadata),但不存储像素的具体值,比如宽度、高度、格式等。
    • 类似于 VkBuffer 对象,VkImage 也只是一个句柄(handle),它本身并不包含实际的像素数据。相应地,你需要通过 vkBindImageMemory() 函数将 VkImage 与实际的 VkDeviceMemory 对象关联起来,以便在这块内存中存储图像的像素数据。具体可以参考一下这个文章
    • 一旦完成关联,后续的vkCmdCopyImage等类似的指令,就以该VkImage作为句柄来对该图像数据进行引用了。当然,在事后资源释放时,需要分别销毁vulkan对象(VkDestroyImage)以及释放设备内存(VkFreeMemory)

在 Vulkan 中,对于很多对象(比如 VkBuffer 和 VkImage),数据存储和句柄是分离的,这为开发者提供了更多的灵活性。这样的设计允许你更精细地控制数据的存储位置、布局和访问权限。

  1. VkImageView

    • VkImageView 是对 VkImage 的一个视图或描述。它指定了如何从底层的 VkImage 中读取数据,包括图像的格式、范围等。在Vulkan中,你通常需要使用 VkImageView 来对 VkImage 进行采样操作。
  2. VkSampler

    • VkSampler 是一个对象,用于描述纹理采样的方式。它定义了纹理采样时的过滤方式、边界模式、各向异性过滤等参数。VkSampler 通常与 VkImageView 一起用于纹理采样操作。
  3. VkDeviceMemory

    • VkDeviceMemory 用于表示 Vulkan 设备上的内存对象,它是用于存储 VkImage 或其他 Vulkan 对象数据的实际内存。在 Vulkan 中,你需要显式地为图像数据分配GPU内存,完成数据的写入(从CPU端内存到GPU),然后将该内存绑定到相应的 VkImage 对象上。

关系总结:

  • VkImage 是底层图像数据的表示,它包含像素数据和图像的元数据。
  • VkImageView 是对 VkImage 的描述,它提供了访问图像数据的视图,用于采样等操作。
  • VkSampler 描述了纹理采样的方式,包括过滤方式、边界模式等。
  • VkDeviceMemory 是分配给 VkImage 或其他 Vulkan 对象的实际内存,用于存储底层数据。

在实际使用中,通常流程是:
创建 VkImage 对象 → \to 分配相应的 VkDeviceMemory → \to 创建 VkImageViewVkSampler 以便在着色器中进行纹理采样操作。

一般在游戏引擎里,也会有个Texture2D的类,用来封装一些图像的操作和数据,如:

struct TextureSpecification
{
	ImageFormat Format = ImageFormat::RGBA;
	uint32_t Width = 1;
	uint32_t Height = 1;
	TextureWrap SamplerWrap = TextureWrap::Repeat;
	TextureFilter SamplerFilter = TextureFilter::Linear;
	
	bool GenerateMips = true;
	bool SRGB = false;
	bool Storage = false;
	bool StoreLocally = false;

	std::string DebugName;
};
class VulkanTexture2D : public Texture2D
{
public:
	VulkanTexture2D(const TextureSpecification& specification, const std::filesystem::path& filepath);
	VulkanTexture2D(const TextureSpecification& specification, Buffer data = Buffer());
	~VulkanTexture2D() override;
	
	virtual void Resize(const glm::uvec2& size) override;
	virtual void Resize(uint32_t width, uint32_t height) override;

	void Invalidate();

	virtual ImageFormat GetFormat() const override { return m_Specification.Format; }
	virtual uint32_t GetWidth() const override { return m_Specification.Width; }
	virtual uint32_t GetHeight() const override { return m_Specification.Height; }
	virtual glm::uvec2 GetSize() const override { return { m_Specification.Width, m_Specification.Height }; }

	virtual void Bind(uint32_t slot = 0) const override;

	virtual Ref<Image2D> GetImage() const override { return m_Image; }
	virtual ResourceDescriptorInfo GetDescriptorInfo() const override { return m_Image.As<VulkanImage2D>()->GetDescriptorInfo(); }
	const VkDescriptorImageInfo& GetDescriptorInfoVulkan() const { return *(VkDescriptorImageInfo*)GetDescriptorInfo(); }

	void Lock() override;
	void Unlock() override;

	Buffer GetWriteableBuffer() override;
	bool Loaded() const override { return m_ImageData; }
	const std::filesystem::path& GetPath() const override;
	uint32_t GetMipLevelCount() const override;
	virtual std::pair<uint32_t, uint32_t> GetMipSize(uint32_t mip) const override;

	void GenerateMips();

	virtual uint64_t GetHash() const { return (uint64_t)m_Image.As<VulkanImage2D>()->GetDescriptorInfoVulkan().imageView; }

	void CopyToHostBuffer(Buffer& buffer);
private:
	std::filesystem::path m_Path;
	TextureSpecification m_Specification;

	Buffer m_ImageData; // CPU端内存,存放图像文件中读取的数据

	Ref<Image2D> m_Image;	// Image2D也是自定义的类型看下面
};

VulkanImage2D这又是一层封装,核心内容是

  • VkImage Image = nullptr;
  • VkImageView ImageView = nullptr;
  • VkSampler Sampler = nullptr;
  • VmaAllocation MemoryAlloc = nullptr;

然后是其他的一些相关特性、操作的东西

class VulkanImage2D : public Image2D
{
public:
	VulkanImage2D(const ImageSpecification& specification);
	virtual ~VulkanImage2D() override;

	virtual void Resize(const glm::uvec2& size) override
	{
		Resize(size.x, size.y);
	}
	virtual void Resize(const uint32_t width, const uint32_t height) override
	{
		m_Specification.Width = width;
		m_Specification.Height = height;
		Invalidate();
	}
	virtual void Invalidate() override;
	virtual void Release() override;

	virtual uint32_t GetWidth() const override { return m_Specification.Width; }
	virtual uint32_t GetHeight() const override { return m_Specification.Height; }
	virtual glm::uvec2 GetSize() const override { return { m_Specification.Width, m_Specification.Height };}

	virtual float GetAspectRatio() const override { return (float)m_Specification.Width / (float)m_Specification.Height; }

	virtual ImageSpecification& GetSpecification() override { return m_Specification; }
	virtual const ImageSpecification& GetSpecification() const override { return m_Specification; }

	void RT_Invalidate();

	virtual void CreatePerLayerImageViews() override;
	void RT_CreatePerLayerImageViews();
	void RT_CreatePerSpecificLayerImageViews(const std::vector<uint32_t>& layerIndices);

	virtual VkImageView GetLayerImageView(uint32_t layer)
	{
		HZ_CORE_ASSERT(layer < m_PerLayerImageViews.size());
		return m_PerLayerImageViews[layer];
	}

	VkImageView GetMipImageView(uint32_t mip);
	VkImageView RT_GetMipImageView(uint32_t mip);

	VulkanImageInfo& GetImageInfo() { return m_Info; }
	const VulkanImageInfo& GetImageInfo() const { return m_Info; }

	virtual ResourceDescriptorInfo GetDescriptorInfo() const override { return (ResourceDescriptorInfo)&m_DescriptorImageInfo; }
	const VkDescriptorImageInfo& GetDescriptorInfoVulkan() const { return *(VkDescriptorImageInfo*)GetDescriptorInfo(); }

	virtual Buffer GetBuffer() const override { return m_ImageData; }
	virtual Buffer& GetBuffer() override { return m_ImageData; }

	virtual uint64_t GetHash() const override { return (uint64_t)m_Info.Image; }

	void UpdateDescriptor();

	// Debug
	static const std::map<VkImage, WeakRef<VulkanImage2D>>& GetImageRefs();

	void CopyToHostBuffer(Buffer& buffer);
private:
	ImageSpecification m_Specification;

	Buffer m_ImageData;

	VkImage Image = nullptr;
	VkImageView ImageView = nullptr;
	VkSampler Sampler = nullptr;
	VmaAllocation MemoryAlloc = nullptr;
	VkDeviceSize m_GPUAllocationSize;
	
	std::vector<VkImageView> m_PerLayerImageViews;
	std::map<uint32_t, VkImageView> m_PerMipImageViews;
	VkDescriptorImageInfo m_DescriptorImageInfo = {};
};

你可能感兴趣的:(Vulkan,c++,游戏引擎)