受保护的内存
检查支持
受保护的内存是在 Vulkan 1.1 中添加的,之前没有扩展。这意味着任何 Vulkan 1.0 设备都无法支持受保护的内存。要检查支持,应用程序必须查询并启用 `VkPhysicalDeviceProtectedMemoryFeatures::protectedMemory` 字段。
受保护的队列
受保护的队列可以读取受保护和未受保护的内存,但只能写入受保护的内存。如果一个队列可以写入未受保护的内存,那么它也不能从受保护的内存中读取。
通常,为了防止侧信道攻击,性能计数器和其他计时测量系统对于受保护的队列是禁用或精度较低的。 |
使用 `vkGetPhysicalDeviceQueueFamilyProperties` 获取每个队列的 `VkQueueFlags`,应用程序可以找到一个具有 `VK_QUEUE_PROTECTED_BIT` 标志的队列族。这**并不**意味着来自该族的队列始终受保护,而是意味着这些队列**可以**成为受保护的队列。
要告诉驱动程序使 `VkQueue` 受保护,需要在 `vkCreateDevice` 期间的 `VkDeviceQueueCreateInfo` 中使用 `VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT`。
以下伪代码说明应用程序如何从同一个队列族请求创建 2 个受保护的 `VkQueue` 对象
VkDeviceQueueCreateInfo queueCreateInfo[1];
queueCreateInfo[0].flags = VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT;
queueCreateInfo[0].queueFamilyIndex = queueFamilyFound;
queueCreateInfo[0].queueCount = 2; // assuming 2 queues are in the queue family
VkDeviceCreateInfo deviceCreateInfo = {};
deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
deviceCreateInfo.queueCreateInfoCount = 1;
vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &deviceHandle);
也可以将一个队列族中的队列拆分,使一些受保护,而另一些不受保护。以下伪代码说明应用程序如何从同一个队列族请求创建 1 个受保护的 `VkQueue` 和 1 个未受保护的 `VkQueue` 对象
VkDeviceQueueCreateInfo queueCreateInfo[2];
queueCreateInfo[0].flags = VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT;
queueCreateInfo[0].queueFamilyIndex = queueFamilyFound;
queueCreateInfo[0].queueCount = 1;
queueCreateInfo[1].flags = 0; // unprotected because the protected flag is not set
queueCreateInfo[1].queueFamilyIndex = queueFamilyFound;
queueCreateInfo[1].queueCount = 1;
VkDeviceCreateInfo deviceCreateInfo = {};
deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
deviceCreateInfo.queueCreateInfoCount = 2;
vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &deviceHandle);
现在,应用程序必须使用 `vkGetDeviceQueue2` 来传递 `VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT` 标志,而不是使用 `vkGetDeviceQueue` 来获取 `VkQueue` 句柄。
VkDeviceQueueInfo2 info = {};
info.queueFamilyIndex = queueFamilyFound;
info.queueIndex = 0;
info.flags = VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT;
vkGetDeviceQueue2(deviceHandle, &info, &protectedQueue);
受保护的资源
当创建 `VkImage` 或 `VkBuffer` 以使其受保护时,只需分别设置 `VK_IMAGE_CREATE_PROTECTED_BIT` 和 `VK_BUFFER_CREATE_PROTECTED_BIT` 即可。
当将内存绑定到受保护的资源时,必须已从具有 `VK_MEMORY_PROPERTY_PROTECTED_BIT` 位的 `VkMemoryType` 分配了 `VkDeviceMemory`。
受保护的交换链
当创建交换链时,使用 `VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR` 位来创建受保护的交换链。
从使用受保护交换链的 `vkGetSwapchainImagesKHR` 中的所有 `VkImage` 都与使用 `VK_IMAGE_CREATE_PROTECTED_BIT` 创建的图像相同。
有时,是否可以使用设置的 `VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR` 标志创建交换链是未知的。在可能未知的情况下,会公开VK_KHR_surface_protected_capabilities扩展。
受保护的命令缓冲区
使用受保护的 `VkQueue`,应用程序还可以在创建 `VkCommandPool` 时使用 `VK_COMMAND_POOL_CREATE_PROTECTED_BIT`。
VkCommandPoolCreateInfo info = {};
info.flags = VK_COMMAND_POOL_CREATE_PROTECTED_BIT;
info.queueFamilyIndex = queueFamilyFound; // protected queue
vkCreateCommandPool(deviceHandle, &info, nullptr, &protectedCommandPool);
从受保护的命令池分配的所有命令缓冲区都将成为“受保护的命令缓冲区”。
VkCommandBufferAllocateInfo info = {};
info.commandPool = protectedCommandPool;
vkAllocateCommandBuffers(deviceHandle, &info, &protectedCommandBuffers);
提交受保护的工作
当提交工作以进行保护时,提交的所有 `VkCommandBuffer` 也必须是受保护的。
VkProtectedSubmitInfo protectedSubmitInfo = {};
protectedSubmitInfo.protectedSubmit = true;
VkSubmitInfo submitInfo = {};
submitInfo.pNext = &protectedSubmitInfo;
submitInfo.pCommandBuffers = protectedCommandBuffers;
vkQueueSubmit(protectedQueue, 1, &submitInfo, fence));
VkSubmitInfo2KHR submitInfo = {}
submitInfo.flags = VK_SUBMIT_PROTECTED_BIT_KHR;
vkQueueSubmit2KHR(protectedQueue, 1, submitInfo, fence);