デバイスメモリは「保護されたデバイスメモリ」と「保護されていないデバイスメモリ」に分けられます。
ほとんどの OS は、明示的に共有(たとえば 外部メモリ を介して)されていない限り、あるアプリケーションが別のアプリケーションの GPU メモリにアクセスすることを許可しません。保護されたメモリの一般的な例は、DRM コンテンツを格納するためのものです。プロセスは、(イメージフィルタリング、再生コントロールやクローズドキャプションの合成などのために)変更を許可されるかもしれませんが、保護されていないメモリに抽出することはできません。データは暗号化されて送られ、ディスプレイ上のピクセルに届くまで暗号化されたままです。
Vulkan Spec では、「保護されたデバイスメモリ」が実行することを詳しく説明しています。以下では、保護されたメモリを使用して保護されたサブミットを適切に有効化するために必要なことを示します。
保護されたメモリは Vulkan 1.1で追加されたもので、それ以前には拡張機能もありませんでした。つまり、Vulkan 1.0のデバイスは、保護されたメモリをサポートしていません。対応を確認するには、VkPhysicalDeviceProtectedMemoryFeatures::protectedMemory
フィールドをクエリして有効にする必要があります。
保護されたキューは、保護されたメモリと保護されていないメモリの両方を読むことができますが、保護されたメモリにのみ書き込むことができます。キューが保護されていないメモリへの書き込みが可能な場合、保護されたメモリからの読み込みもできません。
Note
|
サイドチャネル攻撃を防ぐために、保護されたキューでは、パフォーマンスカウンタやその他のタイミング測定システムが無効になったり、精度が低くなったりすることがあります。 |
各キューの VkQueueFlags
を取得するために vkGetPhysicalDeviceQueueFamilyProperties
を使用すると、VK_QUEUE_PROTECTED_BIT
フラグが公開されているキューファミリを見つけることができます。これは、そのファミリからのキューが常に保護されていることを意味するのではなく、そのキューが保護されたキューになれることを意味しています。
ドライバに VkQueue
の保護を指示するためには、vkCreateDevice
の際に VkDeviceQueueCreateInfo
の VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT
が必要となります。
以下の疑似コードは、同じキューファミリから保護された VkQueue
オブジェクトを2つ作成する方法です。
VkDeviceQueueCreateInfo queueCreateInfo[1];
queueCreateInfo[0].flags = VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT;
queueCreateInfo[0].queueFamilyIndex = queueFamilyFound;
queueCreateInfo[0].queueCount = 2; // 2つのキューがキューファミリに入っていると仮定する
VkDeviceCreateInfo deviceCreateInfo = {};
deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
deviceCreateInfo.queueCreateInfoCount = 1;
vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &deviceHandle);
また、キューファミリ内のキューを分割して、一部は保護され、一部は保護されないようにすることも可能です。以下の疑似コードは、同じキューファミリから、保護された VkQueue
オブジェクト1つと保護されていない VkQueue
オブジェクト1つを作成する方法です。
VkDeviceQueueCreateInfo queueCreateInfo[2];
queueCreateInfo[0].flags = VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT;
queueCreateInfo[0].queueFamilyIndex = queueFamilyFound;
queueCreateInfo[0].queueCount = 1;
queueCreateInfo[1].flags = 0; // 保護フラグが設定していないため保護されない
queueCreateInfo[1].queueFamilyIndex = queueFamilyFound;
queueCreateInfo[1].queueCount = 1;
VkDeviceCreateInfo deviceCreateInfo = {};
deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
deviceCreateInfo.queueCreateInfoCount = 2;
vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &deviceHandle);
現在、VkQueue
ハンドルを取得する際に VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT
フラグを渡すために、vkGetDeviceQueue
ではなく vkGetDeviceQueue2
を使用する必要があります。
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
を設定するだけです。
保護されたリソースにメモリをバインドする場合、VkDeviceMemory
は VK_MEMORY_PROPERTY_PROTECTED_BIT
ビットを持つ VkMemoryType
から割り当てられたものでなければなりません。
保護されたスワップチェーンを作成するには、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; // 保護されたキュー
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));
または、VK_KHR_synchronization2 を使用します。
VkSubmitInfo2KHR submitInfo = {}
submitInfo.flags = VK_SUBMIT_PROTECTED_BIT_KHR;
vkQueueSubmit2KHR(protectedQueue, 1, submitInfo, fence);