繁体   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