簡體   English   中英

如何從 Vulkan 渲染到 OpenGL?

[英]How to render to OpenGL from Vulkan?

是否可以從 Vulkan 渲染到 OpenGL?

似乎 nVidia 有一些東西: https : //lunarg.com/faqs/mix-opengl-vulkan-rendering/

可以為其他GPU完成嗎?

是的,如果Vulkan 實現和 OpenGL 實現都有適當的可用擴展,這是可能的。

這是 Vulkan Samples 存儲庫中示例應用程序的屏幕截圖,該應用程序使用 OpenGL 將簡單的着色玩具渲染為紋理,然后在 Vulkan 渲染窗口中使用該紋理。

gl 到 vulkan 示例

雖然你的問題似乎暗示你想要做相反的事情(使用 Vulkan 渲染某些東西,然后使用 OpenGL 顯示結果),但同樣的概念也適用......在一個 API 中填充紋理,使用同步來確保 GPU 工作完成,然后使用其他 API 中的紋理。 你也可以用緩沖區做同樣的事情,例如你可以使用 Vulkan 進行計算操作,然后在 OpenGL 渲染中使用結果。

要求

這樣做需要 OpenGL 和 Vulkan 實現都支持所需的擴展,但是,根據這個站點,這些擴展在操作系統版本和 GPU 供應商之間得到廣泛支持,只要您使用的是最近的 (> 1.0.51) Vulkan 版本。

您需要 OpenGL 的外部對象擴展和 Vulkan 的外部內存/ 柵欄/ 信號量擴展。

擴展的 Vulkan 端允許您分配內存、創建信號量或柵欄,同時將結果對象標記為可導出。 相應的 GL 擴展允許您獲取對象並使用新的 GL 命令操作它們,這些命令允許您等待柵欄、發出信號並等待信號量,或使用 Vulkan 分配的內存來支持 OpenGL 紋理。 通過在 OpenGL 幀緩沖區中使用這樣的紋理,您幾乎可以渲染任何您想要的內容,然后在 Vulkan 中使用渲染結果。

導出/導入示例代碼

例如,在 Vulkan 方面,當您為圖像分配內存時,您可以這樣做......

vk::Image image;
... // create the image as normal
vk::MemoryRequirements memReqs = device.getImageMemoryRequirements(image);
vk::MemoryAllocateInfo memAllocInfo;
vk::ExportMemoryAllocateInfo exportAllocInfo{
  vk::ExternalMemoryHandleTypeFlagBits::eOpaqueWin32 
};
memAllocInfo.pNext = &exportAllocInfo;
memAllocInfo.allocationSize = memReqs.size;
memAllocInfo.memoryTypeIndex = context.getMemoryType(
  memReqs.memoryTypeBits, vk::MemoryPropertyFlagBits::eDeviceLocal);
vk::DeviceMemory memory;
memory = device.allocateMemory(memAllocInfo);
device.bindImageMemory(image, memory, 0);
HANDLE sharedMemoryHandle = device.getMemoryWin32HandleKHR({ 
  texture.memory, vk::ExternalMemoryHandleTypeFlagBits::eOpaqueWin32 
});

這是使用 C++ 接口並使用擴展的 Win32 變體。 對於 Posix 平台,有獲取文件描述符而不是 WIN32 句柄的替代方法。

sharedMemoryHandle是您需要傳遞給 OpenGL 的值以及實際分配大小。 在 GL 方面,您可以執行此操作...

// These values should be populated by the vulkan code
HANDLE sharedMemoryHandle;
GLuint64 sharedMemorySize;

// Create a 'memory object' in OpenGL, and associate it with the memory 
// allocated in vulkan
GLuint mem;
glCreateMemoryObjectsEXT(1, mem);
glImportMemoryWin32HandleEXT(mem, sharedMemorySize,
  GL_HANDLE_TYPE_OPAQUE_WIN32_EXT, sharedMemoryHandle);

// Having created the memory object we can now create a texture and use
// the memory object for backing it
glCreateTextures(GL_TEXTURE_2D, 1, &color);
// The internalFormat here should correspond to the format of 
// the Vulkan image.  Similarly, the w & h values should correspond to 
// the extent of the Vulkan image
glTextureStorageMem2DEXT(color, 1, GL_RGBA8, w, h, mem, 0 );

同步

這里最棘手的一點是同步。 Vulkan 規范要求圖像處於特定狀態(布局),然后才能對其執行相應的操作。 因此,為了正確執行此操作(根據我的理解),您需要...

  • 在 Vulkan 中,創建一個命令緩沖區,將圖像轉換為 ColorAttachmentOptimal 布局
  • 提交命令緩沖區,以便它發出一個信號量,該信號量已類似地導出到 OpenGL
  • 在 OpenGL 中,使用glWaitSemaphoreEXT函數使 GL 驅動程序等待轉換完成。
    • 請注意,這是 GPU 端等待,因此該函數根本不會阻塞。 它類似於glWaitSync (相對於glClientWaitSync在這方面)。
  • 執行渲染到幀緩沖區的 GL 命令
  • 使用glSignalSemaphoreEXT函數在 GL 端發出不同的導出信號量信號
  • 在 Vulkan 中,執行另一個從 ColorAttachmentOptimal 到 ShaderReadOnlyOptimal 的圖像布局轉換
  • 提交轉換命令緩沖區,等待信號量設置為您剛剛從 GL 端發出信號的信號量。

那將是一個最佳路徑。 或者,快速和骯臟的方法是進行 vulkan 轉換,然后執行 queue 和 device waitIdle命令以確保完成工作,執行 GL 命令,然后執行glFlushglFinish命令以確保 GPU 完成工作,然后恢復您的 Vulkan 命令。 這更像是一種蠻力方法,並且可能會產生比正確同步更差的性能。

NVIDIA 已經創建了一個 OpenGL 擴展,NV_draw_vulkan_image,它可以在 OpenGL 中渲染一個VkImage 它甚至有一些與 Vulkan 信號量等交互的機制。

但是, 根據文檔,您必須繞過所有 Vulkan 層,因為層可以修改不可調度的句柄,而 OpenGL 擴展不知道所述修改。 他們推薦的方法是對所有 Vulkan 函數使用glGetVkProcAddrNV

這也意味着您無法訪問任何依賴於 Vulkan 層的調試。

在 SIGGRAPH 2016 的最新幻燈片中還有更多信息。幻燈片 63-65 描述了如何將 Vulkan 圖像 blit 到 OpenGL 后台緩沖區。 我的觀點是 NVIDIA 可能很容易支持這一點,因為 Vulkan 驅動程序包含在 libGL.so(在 Linux 上)中。 因此,將 Vulkan 圖像句柄提供給驅動程序的 GL 端並使其有用可能並不難。

正如另一個答案所指出的,仍然沒有官方注冊的多供應商互操作擴展。 這種方法只適用於 NVIDIA。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM