VK_KHR_maintenance7
此提案详细说明并解决了 VK_KHR_maintenance7
扩展所解决的问题。
1. 问题陈述
随着时间的推移,一些次要功能,没有一个值得单独创建一个完整的扩展,需要创建一个维护扩展。
以下是本提案中考虑的问题列表
-
在渲染时,要求深度和模板方面之间没有访问重叠
-
在通过分层实现提供 Vulkan 实现的环境中,添加一种查询有关底层设备信息的方法。
-
将
VK_RENDERING_CONTENTS_INLINE_BIT_EXT
和VK_SUBPASS_CONTENTS_INLINE_AND_SECONDARY_COMMAND_BUFFERS_EXT
提升为 KHR -
添加一个限制,以报告管道布局中可以包含的最大动态 uniform 缓冲区和动态存储缓冲区的总数。
-
添加一种方法,用于确定实现是否在 32 位时间戳查询溢出时环绕或饱和
-
要求 FSR 附件访问与其它图像访问保持一致以提高稳健性。或许还需要确保数组访问是稳健的 - 不仅仅是宽度/高度。
1.2. 查询底层分层实现的属性
当 Vulkan 驱动程序由分层实现提供时,可能需要查询底层设备的详细信息。例如,在 Mesa/Venus 上运行时,驱动程序 ID 返回为 VK_DRIVER_ID_MESA_VENUS
,但可能需要知道底层真正的驱动程序是什么。
1.3. 渲染通道中混合内联和二级命令缓冲区记录
Vulkan 1.0 要求渲染通道子通道的内容要么完全内联,要么在单个二级命令缓冲区中提供。在某些情况下,能够混合在同一渲染通道子通道内部的内联和二级命令缓冲区,或执行多个二级命令缓冲区可能是有益的。
1.4. 放宽动态 Uniform/存储缓冲区的计数
管线布局中可以包含的最大动态 uniform 缓冲区和动态存储缓冲区的数量是分别报告的。虽然一些实现以相同的方式处理 uniform 缓冲区和存储缓冲区的动态偏移,但报告总数以及最大动态 uniform 和存储缓冲区数量可以放宽限制,更准确地暴露设备功能。
1.5. 片元着色率附件大小不匹配
DirectX 12 可变着色率功能允许应用程序指定一个着色率图像,该图像比为所有渲染的纹素提供着色率所需的图像要小。当在着色率图像覆盖区域之外渲染片段时,将返回默认值,这与图像通常的超出边界值一致,并保证了这一点。
然而,在 Vulkan 中,目前这被完全禁止,使得依赖此功能的应用程序或模拟层难以保证可移植性。
2. 问题详情和解决方案空间
2.2. 查询底层分层实现的属性
包含一组新的结构体,可以通过链接到 VkPhysicalDeviceProperties2 时使用 VkPhysicalDeviceLayeredApiPropertiesListKHR 访问。
2.5. 片元着色率附件大小不匹配
在基本层面上,第一个障碍是允许应用程序指定对于渲染区域来说太小的片元着色率附件,并赋予其某种明确的行为。第二个挑战是确保所有实现都返回预期值。
这可以通过使用新的语言来描述这些查找的具体细节来实现,但值得注意的是,具有鲁棒访问的图像读取已经具有所需的行为。因此,此提案将片元着色率附件读取重新定义为常规图像读取,并保证当启用 VkPhysicalDeviceRobustness2FeaturesEXT::robustImageAccess2 功能时,这些值与 DirectX 12 的保证相匹配。
3. 提案
3.1. 新功能
公开以下功能
typedef struct VkPhysicalDeviceMaintenance7FeaturesKHR {
VkStructureType sType;
void* pNext;
VkBool32 maintenance7;
} VkPhysicalDeviceMaintenance7FeaturesKHR;
-
maintenance7
功能指示对VK_KHR_maintenance7
扩展的支持。
3.2. 新属性
此扩展添加以下属性
typedef struct VkPhysicalDeviceMaintenance7PropertiesKHR {
VkStructureType sType;
void* pNext;
VkBool32 robustFragmentShadingRateAttachmentAccess;
VkBool32 separateDepthStencilAttachmentAccess;
uint32_t maxDescriptorSetTotalUniformBuffersDynamic;
uint32_t maxDescriptorSetTotalStorageBuffersDynamic;
uint32_t maxDescriptorSetTotalBuffersDynamic;
uint32_t maxDescriptorSetUpdateAfterBindTotalUniformBuffersDynamic;
uint32_t maxDescriptorSetUpdateAfterBindTotalStorageBuffersDynamic;
uint32_t maxDescriptorSetUpdateAfterBindTotalBuffersDynamic;
} VkPhysicalDeviceMaintenance7PropertiesKHR;
-
robustFragmentShadingRateAttachmentAccess
指示使用 VkImageSubresourceRange::`baseMipLevel` 等于 0 创建的片元着色率附件是否可以具有太小而无法覆盖指定渲染区域的大小。 -
separateDepthStencilAttachmentAccess
指示对深度/模板附件的读取-修改-写入操作是否被视为对包含深度和模板方面的图像中同级模板或深度附件的写入。 -
maxDescriptorSetTotalUniformBuffersDynamic
指示可以在管线布局中包含的最大动态 uniform 缓冲区的总数。 -
maxDescriptorSetTotalStorageBuffersDynamic
指示可以在管线布局中包含的最大动态存储缓冲区的总数。 -
maxDescriptorSetTotalBuffersDynamic
指示可以在管线布局中包含的最大动态 uniform 缓冲区和存储缓冲区的总数。 -
maxDescriptorSetUpdateAfterBindTotalUniformBuffersDynamic
类似于maxDescriptorSetUniformBuffersDynamic
,但计算使用或不使用设置了VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT
位的描述符集创建的描述符。 -
maxDescriptorSetUpdateAfterBindTotalStorageBuffersDynamic
类似于maxDescriptorSetStorageBuffersDynamic
,但计算使用或不使用设置了VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT
位的描述符集创建的描述符。 -
maxDescriptorSetUpdateAfterBindTotalBuffersDynamic
类似于maxDescriptorSetBuffersDynamic
,但计算使用或不使用设置了VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT
位的描述符集创建的描述符。
3.3. 新标志
从 VK_EXT_nested_command_buffer
扩展提升的 VK_RENDERING_CONTENTS_INLINE_BIT_KHR
标志允许在当前命令缓冲区内内联记录渲染通道实例。与 VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT
位结合使用,可以在内联和使用 vkCmdExecuteCommands
执行的二级命令缓冲区中记录渲染通道实例的内容。
从 VK_EXT_nested_command_buffer
扩展提升的 VK_SUBPASS_CONTENTS_INLINE_AND_SECONDARY_COMMAND_BUFFERS_KHR
标志允许在内联和使用 vkCmdExecuteCommands
执行的二级命令缓冲区中记录渲染通道子通道的内容。
3.4. 新结构体
要查询有关分层实现的信息,请将以下内容链接到 vkGetPhysicalDeviceProperties2
。
typedef struct VkPhysicalDeviceLayeredApiPropertiesListKHR {
VkStructureType sType;
void* pNext;
uint32_t layeredApiCount;
VkPhysicalDeviceLayeredApiPropertiesKHR* pLayeredApis;
} VkPhysicalDeviceLayeredApiPropertiesListKHR;
其中
typedef struct VkPhysicalDeviceLayeredApiPropertiesKHR {
VkStructureType sType;
void* pNext;
uint32_t vendorID;
uint32_t deviceID;
VkPhysicalDeviceLayeredApiKHR layeredAPI;
char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE];
} VkPhysicalDeviceLayeredApiPropertiesKHR;
在上面的内容中,vendorID
、deviceID
和 deviceName
与 VkPhysicalDeviceProperties
中同名的成员类似。layeredAPI
是一个枚举,用于标识分层实现的底层 API,例如,如果该层实现 D3D12 API,则为 VK_PHYSICAL_DEVICE_LAYERED_API_D3D12_KHR
。
在存在多个层的情况下,pLayeredApis[0]
的内容对应于最底层的层,其后的索引(如果有)按层顺序排列。这允许纯粹对执行命令的最终供应商 ID 或 API 感兴趣的应用程序避免查询层计数,始终提供 layeredApiCount
为 1,并且仅检查 pLayeredApis[0]
。
要查询分层实现的 API 特定细节,可以将 API 特定的结构体链接到 VkPhysicalDeviceLayeredApiPropertiesKHR
。对于分层 Vulkan 实现(即 VK_PHYSICAL_DEVICE_LAYERED_API_VULKAN_KHR
),此扩展引入了 VkPhysicalDeviceLayeredApiVulkanPropertiesKHR
进行链接,未来可能会在其他扩展中添加其他 API 的结构体。实现将填充与分层 API 对应的链接结构体,并保持其他 API 的结构体不变。这允许应用程序链接多个 API 的结构体,并在单个查询中检索所有必要的信息。
typedef struct VkPhysicalDeviceLayeredApiVulkanPropertiesKHR {
VkStructureType sType;
void* pNext;
VkPhysicalDeviceProperties2 properties;
} VkPhysicalDeviceLayeredApiVulkanPropertiesKHR;
在上述结构体中,应用程序还可以将 VkPhysicalDeviceDriverProperties
和 VkPhysicalDeviceIDProperties
链接到 properties
,以从底层 Vulkan 设备提取更多信息。但是,properties.properties.limits
和 properties.properties.sparseProperties
将被初始化为 0,并且不包含有意义的值。
例如,一个通过 Mesa 的 Venus,在 Mesa 的 Dozen 之上,并在 Nvidia 的专有 D3D12 实现之上运行的应用程序会收到以下信息:
layers->pLayeredApis[0].layeredAPI = VK_PHYSICAL_DEVICE_LAYERED_API_D3D12_KHR;
// other fields
layers->pLayeredApis[1].layeredAPI = VK_PHYSICAL_DEVICE_LAYERED_API_VULKAN_KHR;
// other fields
// If driverProperties is a VkPhysicalDeviceDriverProperties chained to
// VkPhysicalDeviceLayeredApiVulkanPropertiesKHR::properties that is in turn
// chained to layers->pLayeredApis[1].pNext:
driverProperties->driverID = VK_DRIVER_ID_MESA_DOZEN;
// other fields
在上面的例子中,顶层(Mesa 的 Venus)的属性将像往常一样在 VkPhysicalDeviceProperties2
中返回。注意:如果非 Vulkan 实现下方存在层,则可能在此查询中不可见。例如,如果应用程序通过 Mesa 的 Dozen 运行,并在 VKD3D-proton 等之上运行,则查询可能仅返回分层实现,直到 Mesa 的 Dozen,因为其他 API 可能缺少这样的查询。
VkPhysicalDeviceLayeredApiKHR
枚举定义为:
typedef enum VkPhysicalDeviceLayeredApiKHR {
VK_PHYSICAL_DEVICE_LAYERED_API_VULKAN_KHR = 1,
VK_PHYSICAL_DEVICE_LAYERED_API_D3D12_KHR = 2,
VK_PHYSICAL_DEVICE_LAYERED_API_METAL_KHR = 3,
VK_PHYSICAL_DEVICE_LAYERED_API_OPENGL_KHR = 4,
VK_PHYSICAL_DEVICE_LAYERED_API_OPENGLES_KHR = 5,
} VkPhysicalDeviceLayeredApiKHR;
4. 问题
4.1. 已解决:当在分层实现上运行时,应如何查询底层分层 Vulkan 设备的属性?
应使用专用结构体 VkPhysicalDeviceLayeredApiVulkanPropertiesKHR
,其中包含 VkPhysicalDeviceProperties2
成员。可以通过将 VkPhysicalDeviceDriverProperties
和 VkPhysicalDeviceIDProperties
结构体链接到该成员来查询其他信息。
将 VkPhysicalDeviceProperties2
、VkPhysicalDeviceDriverProperties
和 VkPhysicalDeviceIDProperties
直接链接到 VkPhysicalDeviceLayeredApiPropertiesKHR
可能会因多种原因而令人困惑。特别是,VkPhysicalDeviceProperties2
是一个“根”结构,可以接受其链中的 VkPhysicalDeviceDriverProperties
和 VkPhysicalDeviceIDProperties
;允许将这些结构体链接到 VkPhysicalDeviceLayeredApiPropertiesKHR
意味着应用程序可以创建一个诸如 VkPhysicalDeviceLayeredApiPropertiesKHR
→ VkPhysicalDeviceDriverProperties
→ VkPhysicalDeviceProperties2
的链,这可能会令人困惑。
未来的扩展还可以提供查询其他分层 API(例如 D3D)属性的功能。此扩展允许将 API 特定的结构体链接到 VkPhysicalDeviceLayeredApiPropertiesKHR
,以便于一次查询所有信息,这意味着 VkPhysicalDeviceLayeredApiPropertiesKHR
的 pNext
链可以包括 Vulkan 和 D3D 的属性结构体。允许每个 API 存在多个结构体,并且可能交错,只会增加混乱。
通过将 VkPhysicalDeviceProperties2
包装在 VkPhysicalDeviceLayeredApiVulkanPropertiesKHR
结构体中,VkPhysicalDeviceLayeredApiPropertiesKHR
的 pNext
链每个 API 将仅包含一个结构体,从而避免驱动程序、应用程序和验证层出现混淆。