Vulkan-官方示例解读-descriptorSet(描述符集)以及Descriptorpool(描述符池)


前言

描述符用于将数据传递给着色器绑定点。设置描述符集、布局、池,基于集合布局创建单个管道,并使用不同的描述符集渲染多个对象。也是用来传递layout的方式,如:layout (set = 0, binding = 0) uniform UBOMatrices


一、descriptorSets.cpp

本示例使用了两个cube进行测试

1.类以及击沉变量

class VulkanExample : public VulkanExampleBase
{
public:
	bool animate = true;

	struct Cube {
		struct Matrices {
			glm::mat4 projection;
			glm::mat4 view;
			glm::mat4 model;
		} matrices;
		VkDescriptorSet descriptorSet;
		vks::Texture2D texture;
		vks::Buffer uniformBuffer;
		glm::vec3 rotation;
	};
	std::array<Cube, 2> cubes;

	vkglTF::Model model;

	VkPipeline pipeline;
	VkPipelineLayout pipelineLayout;

	VkDescriptorSetLayout descriptorSetLayout;

2.函数

创建命令缓冲:在这里在进行了绑定了渲染通道和渲染管线以及创建可视窗口(viewport)、为命令缓冲区动态设置剪刀矩形(scissor)等操作之后,在进行绘制模型之前进行了绑定描述符集合的操作(绑定多维数据集的描述符集。这将告诉命令缓冲区使用为此多维数据集设置的统一缓冲区和图像)。

	void buildCommandBuffers()
	{
		VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();

		VkClearValue clearValues[2];
		clearValues[0].color = defaultClearColor;
		clearValues[1].depthStencil = { 1.0f, 0 };

		VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo();
		renderPassBeginInfo.renderPass = renderPass;
		renderPassBeginInfo.renderArea.offset.x = 0;
		renderPassBeginInfo.renderArea.offset.y = 0;
		renderPassBeginInfo.renderArea.extent.width = width;
		renderPassBeginInfo.renderArea.extent.height = height;
		renderPassBeginInfo.clearValueCount = 2;
		renderPassBeginInfo.pClearValues = clearValues;

		for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) {
			renderPassBeginInfo.framebuffer = frameBuffers[i];

			VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));

			vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);

			vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);

			VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
			vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);

			VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0);
			vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);

			VkDeviceSize offsets[1] = { 0 };
			model.bindBuffers(drawCmdBuffers[i]);

			/*
				[POI] Render cubes with separate descriptor sets
			*/
			for (auto cube : cubes) {
				// Bind the cube's descriptor set. This tells the command buffer to use the uniform buffer and image set for this cube
				vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &cube.descriptorSet, 0, nullptr);
				model.draw(drawCmdBuffers[i]);
			}

			drawUI(drawCmdBuffers[i]);

			vkCmdEndRenderPass(drawCmdBuffers[i]);

			VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
		}
	}
  • 建立描述符集:布局描述用于特定描述符布局的着色器绑定和类型,因此必须与着色器绑定匹配。比如此示例中的描述符匹配如下:set0 binding0 绑定了uniformbuffer。而set0 binding1绑定了图片示例
  • 描述符池:实际描述符是从描述符池中分配的,告诉驱动程序什么类型和多少此应用程序将使用的描述符。一个应用程序可以有多个池(例如,用于多个线程),只要不超过设备限制,就可以使用任意数量的描述符类型。最好使用实际需要的描述符类型和计数来分配池。比如此示例中使用的descriptorPoolSizes就用了 Uniform buffers : 1 for scene and 1 per object (scene and local matrices);Combined image samples : 1 per mesh texture。这两个描述符组合成的描述符池。
  • 使用共享描述符集布局和描述符池,我们现在将分配描述符集。描述符集包含在渲染时使用的对象(缓冲区、图像)的实际描述符。
  • 使用集布局从池中分配一个空描述符集,而不使用实际描述符.注意descriptorSet就在cube当中。
	void setupDescriptors()
	{
		/*

			Descriptor set layout

			The layout describes the shader bindings and types used for a certain descriptor layout and as such must match the shader bindings

			Shader bindings used in this example:

			VS:
				layout (set = 0, binding = 0) uniform UBOMatrices ...

			FS :
				layout (set = 0, binding = 1) uniform sampler2D ...;

		*/

		std::array<VkDescriptorSetLayoutBinding,2> setLayoutBindings{};

		/*
			Binding 0: Uniform buffers (used to pass matrices)
		*/
		setLayoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
		// Shader binding point
		setLayoutBindings[0].binding = 0;
		// Accessible from the vertex shader only (flags can be combined to make it accessible to multiple shader stages)
		setLayoutBindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
		// Binding contains one element (can be used for array bindings)
		setLayoutBindings[0].descriptorCount = 1;

		/*
			Binding 1: Combined image sampler (used to pass per object texture information)
		*/
		setLayoutBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
		setLayoutBindings[1].binding = 1;
		// Accessible from the fragment shader only
		setLayoutBindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
		setLayoutBindings[1].descriptorCount = 1;

		// Create the descriptor set layout
		VkDescriptorSetLayoutCreateInfo descriptorLayoutCI{};
		descriptorLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
		descriptorLayoutCI.bindingCount = static_cast<uint32_t>(setLayoutBindings.size());
		descriptorLayoutCI.pBindings = setLayoutBindings.data();

		VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, nullptr, &descriptorSetLayout));

		/*

			Descriptor pool

			Actual descriptors are allocated from a descriptor pool telling the driver what types and how many
			descriptors this application will use

			An application can have multiple pools (e.g. for multiple threads) with any number of descriptor types
			as long as device limits are not surpassed

			It's good practice to allocate pools with actually required descriptor types and counts

		*/

		std::array<VkDescriptorPoolSize, 2> descriptorPoolSizes{};

		// Uniform buffers : 1 for scene and 1 per object (scene and local matrices)
		descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
		descriptorPoolSizes[0].descriptorCount = 1 +  static_cast<uint32_t>(cubes.size());

		// Combined image samples : 1 per mesh texture
		descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
		descriptorPoolSizes[1].descriptorCount = static_cast<uint32_t>(cubes.size());

		// Create the global descriptor pool
		VkDescriptorPoolCreateInfo descriptorPoolCI = {};
		descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
		descriptorPoolCI.poolSizeCount = static_cast<uint32_t>(descriptorPoolSizes.size());
		descriptorPoolCI.pPoolSizes = descriptorPoolSizes.data();
		// Max. number of descriptor sets that can be allocated from this pool (one per object)
		descriptorPoolCI.maxSets = static_cast<uint32_t>(cubes.size());

		VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolCI, nullptr, &descriptorPool));

		/*

			Descriptor sets

			Using the shared descriptor set layout and the descriptor pool we will now allocate the descriptor sets.

			Descriptor sets contain the actual descriptor for the objects (buffers, images) used at render time.

		*/

		for (auto &cube: cubes) {

			// Allocates an empty descriptor set without actual descriptors from the pool using the set layout
			VkDescriptorSetAllocateInfo allocateInfo{};
			allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
			allocateInfo.descriptorPool = descriptorPool;
			allocateInfo.descriptorSetCount = 1;
			allocateInfo.pSetLayouts = &descriptorSetLayout;
			VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocateInfo, &cube.descriptorSet));

			// Update the descriptor set with the actual descriptors matching shader bindings set in the layout

			std::array<VkWriteDescriptorSet, 2> writeDescriptorSets{};

			/*
				Binding 0: Object matrices Uniform buffer
			*/
			writeDescriptorSets[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
			writeDescriptorSets[0].dstSet = cube.descriptorSet;
			writeDescriptorSets[0].dstBinding = 0;
			writeDescriptorSets[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
			writeDescriptorSets[0].pBufferInfo = &cube.uniformBuffer.descriptor;
			writeDescriptorSets[0].descriptorCount = 1;

			/*
				Binding 1: Object texture
			*/
			writeDescriptorSets[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
			writeDescriptorSets[1].dstSet = cube.descriptorSet;
			writeDescriptorSets[1].dstBinding = 1;
			writeDescriptorSets[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
			// Images use a different descriptor structure, so we use pImageInfo instead of pBufferInfo
			writeDescriptorSets[1].pImageInfo = &cube.texture.descriptor;
			writeDescriptorSets[1].descriptorCount = 1;

			// Execute the writes to update descriptors for this set
			// Note that it's also possible to gather all writes and only run updates once, even for multiple sets
			// This is possible because each VkWriteDescriptorSet also contains the destination set to be updated
			// For simplicity we will update once per set instead

			vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr);
		}

	}

注意在创建渲染管线的手要确定Layout。管道布局基于我们上面创建的描述符集布局。

	void preparePipelines()
	{
		/*
			[POI] Create a pipeline layout used for our graphics pipeline
		*/
		VkPipelineLayoutCreateInfo pipelineLayoutCI{};
		pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
		// The pipeline layout is based on the descriptor set layout we created above
		pipelineLayoutCI.setLayoutCount = 1;
		pipelineLayoutCI.pSetLayouts = &descriptorSetLayout;
		VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout));

二、着色器

1.cube.vert

代码如下(示例):

#version 450

layout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inNormal;
layout (location = 2) in vec2 inUV;
layout (location = 3) in vec3 inColor;

layout (set = 0, binding = 0) uniform UBOMatrices {
	mat4 projection;
	mat4 view;
	mat4 model;
} uboMatrices;

layout (location = 0) out vec3 outNormal;
layout (location = 1) out vec3 outColor;
layout (location = 2) out vec2 outUV;

out gl_PerVertex {
	vec4 gl_Position;
};

void main() 
{
	outNormal = inNormal;
	outColor = inColor;
	outUV = inUV;
	gl_Position = uboMatrices.projection * uboMatrices.view * uboMatrices.model * vec4(inPos.xyz, 1.0);
}

2.cube.frag

代码如下(示例):

#version 450

layout (set = 0, binding = 1) uniform sampler2D samplerColorMap;

layout (location = 0) in vec3 inNormal;
layout (location = 1) in vec3 inColor;
layout (location = 2) in vec2 inUV;

layout (location = 0) out vec4 outFragColor;

void main() 
{
	outFragColor = texture(samplerColorMap, inUV) * vec4(inColor, 1.0);
}

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
realesrgan-ncnn-vulkan-20211212-windows是一个基于ncnn框架和Vulkan图形API开发的图像超分辨率增强模型。它是由GitHub用户realsrgan开发的最新版本,最新发布日期为2021年12月12日,专为Windows操作系统而设计。 该模型的主要应用是图像超分辨率增强,通过提高图像的分辨率和细节,使图像看起来更加清晰和真实。它采用深度学习和卷积神经网络等先进的技术,能够将低分辨率的图像转换成高分辨率的图像,从而提升图像的质量和视觉效果。 realesrgan-ncnn-vulkan-20211212-windows的开发使用了ncnn框架和Vulkan图形API,这使得它能够在Windows系统上实现快速且高效的图像处理。ncnn是一个轻量级的深度学习框架,专注于在移动平台和嵌入式设备上实现高性能和低延迟的推理。而Vulkan图形API是一种跨平台的图形渲染和计算API,可以充分利用计算设备的性能,提供高效的图像处理和渲染能力。 realesrgan-ncnn-vulkan-20211212-windows的使用可以通过命令行或者图形界面进行,用户可以根据自己的需求和偏好选择适合的方式。该模型提供了训练好的权重参数,用户可以直接加载这些参数并进行图像超分辨率增强。此外,该模型还支持批量处理和视频处理,方便用户对多个图像进行处理。 总之,realesrgan-ncnn-vulkan-20211212-windows是一个高效、快速且易于使用的图像超分辨率增强模型,适用于Windows系统,并利用了ncnn框架和Vulkan图形API的优势,为用户提供了出色的图像处理效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值