创建输入附件
译者注:示例代码点击此处
附件是我们在绘图命令期间渲染的图像,换句话说它们是渲染目标。
输入附件是图像资源,我们可以从中读取片段着色器内的(未过滤的)数据。只需要记住,我们只能访问已处理片段相对应的一个位置。
通常,对于输入附件,使用先前颜色或深度模版附件的资源。但也可以使用其他图像(及其图像视图)。我们只需要使用VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT用法创建它们。
怎么做...
- 获取执行操作的物理设备,并将其句柄存储在名为physical_device的VkPhysicalDevice类型变量中。
- 选择图像的格式并使用它来初始化名为format的VkFormat类型变量。
- 创建一个名为format_properties的VkFormatProperties类型变量。
- 调用vkGetPhysicalDeviceFormatProperties( physical_device, format, &format_properties )并提供physical_device和format变量以及指向format_properties变量的指针。
- 如果要读取图像的颜色数据,请确保所选格式适合此类用途。为此请检查是否在format_properties变量的optimalTilingFeatures成员设置了VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT位。
- 如果要读取图像的深度或模版数据,请检查所选格式是否可用于读取深度或模版数据。为此请检查format_properties变量的optimalTilingFeatures成员中设置了VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT位。
- 获取从使用的物理设备创建的逻辑设备句柄。将其存储在名为logical_device的VkDevice类型变量。
- 使用logical_device和format变量创建图像,并未图像的其余参数选择适当的值。确保在图像创建期间制定了VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT用法。将创建的句柄存储在名为input_attachment的VkImage类型变量中(请参阅第四章,资源和内存中的创建图像内容)。
- 使用VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT属性分配内存对象(或使用现有内存对象的部分区域)并将其绑定到图像(请参阅第四章,资源和内存中的分配内存对象和将其绑定到图像内容)。
- 使用logical_device、input_attachment和format变量创建图像视图,然后选择图像视图的其余参数。将创建的句柄存储在名为input_attachment_image_view的VkImageView类型变量中(请参阅第四章,资源和内存中的创建图像视图内容)。
这个怎么运作...
输入附件准许我们从用作渲染通道附件的图像中读取片段着色器内的数据(通常,对于输入附件,将使用先前使用颜色或深度模版附件的图像)。
提示:输入附件用VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT类型的描述符。
在Vulkan中,渲染操作被收集到渲染过程中。每个渲染过程至少有一个子通道,但可以有更多。如果我们在一个子通道中呈现一个附件,那么我们可以将它用作输入附件,并在相同渲染过程的后续子通道中读取数据。实际上,它是从给定渲染过程中的附件读取数据的唯一方法,在给定渲染中用作附件的图像只能通过着色器内的输入附件进行访问(它们不能绑定到用于输入附件以外的描述符集)。
从输入附件读取数据时, 我们仅限于读取处理过的片段的位置。这种方法可能比渲染到附件、结束渲染、将图像绑定到设置为采样图像 (纹理) 的描述符以及启动另一个不将给定图像用作其任何附件的渲染传递更理想。
对于输入附件,我们也可以使用其他图像(不必将它们用做颜色或深度/模版附件)。我们只需要使用VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT用法和正确的格式创建它们。对于将从中读取颜色数据的输入附件,必须使用以下格式:
- VK_FORMAT_R5G6B5_UNORM_PACK16
- VK_FORMAT_A1R5G5B5_UNORM_PACK16
- VK_FORMAT_R8_UNORM, VK_FORMAT_R8_UINT and VK_FORMAT_R8_SINT
- VK_FORMAT_R8G8_UNORM, VK_FORMAT_R8G8_UINT, and VK_FORMAT_R8G8_SINT
- VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_UINT, VK_FORMAT_R8G8B8A8_SINT, and VK_FORMAT_R8G8B8A8_SRGB
- VK_FORMAT_B8G8R8A8_UNORM and VK_FORMAT_B8G8R8A8_SRGB
- VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_FORMAT_A8B8G8R8_UINT_PACK32, VK_FORMAT_A8B8G8R8_SINT_PACK32, andVK_FORMAT_A8B8G8R8_SRGB_PACK32
- VK_FORMAT_A2B10G10R10_UNORM_PACK32 and VK_FORMAT_A2B10G10R10_UINT_PACK32
- VK_FORMAT_R16_UINT, VK_FORMAT_R16_SINT and VK_FORMAT_R16_SFLOAT
- VK_FORMAT_R16G16_UINT, VK_FORMAT_R16G16_SINT and VK_FORMAT_R16G16_SFLOAT
- VK_FORMAT_R16G16B16A16_UINT, VK_FORMAT_R16G16B16A16_SINT, and VK_FORMAT_R16G16B16A16_SFLOAT
- VK_FORMAT_R32_UINT, VK_FORMAT_R32_SINT, and VK_FORMAT_R32_SFLOAT
- VK_FORMAT_R32G32_UINT, VK_FORMAT_R32G32_SINT, and VK_FORMAT_R32G32_SFLOAT
- VK_FORMAT_R32G32B32A32_UINT, VK_FORMAT_R32G32B32A32_SINT, and VK_FORMAT_R32G32B32A32_SFLOAT
- VK_FORMAT_D16_UNORM
- VK_FORMAT_X8_D24_UNORM_PACK32 or VK_FORMAT_D32_SFLOAT(必须支持这两种格式中的至少一种)。
- VK_FORMAT_D24_UNORM_S8_UINT or VK_FORMAT_D32_SFLOAT_S8_UINT 必须支持这两种格式中的至少一种)。
也可以支持其他格式,但不保证对它们的支撑。我们可以检查执行应用程序的平台是否支持给定格式:
VkFormatProperties format_properties;
vkGetPhysicalDeviceFormatProperties( physical_device, format, &format_properties );
if( (aspect & VK_IMAGE_ASPECT_COLOR_BIT) &&
!(format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) ) {
std::cout << "Provided format is not supported for an input attachment." << std::endl;
return false;
}
if( (aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_DEPTH_BIT)) &&
!(format_properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) ) {
std::cout << "Provided format is not supported for an input attachment." << std::endl;
return false;
}
接下来,我们只需要创建一个图像,分配一个内存对象(或使用一个现有对象)并将其绑定到图像,然后创建一个图像视图。可以这样做:
if( !CreateImage( logical_device, type, format, size, 1, 1, VK_SAMPLE_COUNT_1_BIT, usage | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, false, input_attachment ) ) {
return false;
}
if( !AllocateAndBindMemoryObjectToImage( physical_device, logical_device, input_attachment, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, memory_object ) ) {
return false;
}
if( !CreateImageView( logical_device, input_attachment, view_type, format, aspect, input_attachment_image_view ) ) {
return false;
}
return true;
想这样创建的图像及其视图可用作输入附件。为此,我们需要装备一个渲染过程的正确描述。并在framebuffers中包含图像视图(请参阅第六章,渲染过程和帧缓冲区中的指定子过程描述和创建帧缓冲区内容)。
提示:在GLSL着色器代码中,引用输入附件的变量是使用subpassInput(可能带有前缀)关键字定义的。
GLSL中定义的输入附件的示例如下:
layout (input_attachment_index=i, set=m, binding=n) uniform subpassInput <variable name>;