简体   繁体   English

如何从 Vulkan 渲染到 OpenGL?

[英]How to render to OpenGL from Vulkan?

Is it possible to render to OpenGL from Vulkan?是否可以从 Vulkan 渲染到 OpenGL?

It seems nVidia has something: https://lunarg.com/faqs/mix-opengl-vulkan-rendering/似乎 nVidia 有一些东西: https : //lunarg.com/faqs/mix-opengl-vulkan-rendering/

Can it be done for other GPU's?可以为其他GPU完成吗?

Yes, it's possible if the Vulkan implementation and the OpenGL implementation both have the appropriate extensions available.是的,如果Vulkan 实现和 OpenGL 实现都有适当的可用扩展,这是可能的。

Here is a screenshot from an example app in the Vulkan Samples repository which uses OpenGL to render a simple shadertoy to a texture, and then uses that texture in a Vulkan rendered window.这是 Vulkan Samples 存储库中示例应用程序的屏幕截图,该应用程序使用 OpenGL 将简单的着色玩具渲染为纹理,然后在 Vulkan 渲染窗口中使用该纹理。

gl 到 vulkan 示例

Although your question seems to suggest you want to do the reverse (render to something using Vulkan and then display the results using OpenGL), the same concepts apply.... populate a texture in one API, use synchronization to ensure the GPU work is complete, and then use the texture in the other API.虽然你的问题似乎暗示你想要做相反的事情(使用 Vulkan 渲染某些东西,然后使用 OpenGL 显示结果),但同样的概念也适用......在一个 API 中填充纹理,使用同步来确保 GPU 工作完成,然后使用其他 API 中的纹理。 You can also do the same thing with buffers, so for instance you could use Vulkan for compute operations and then use the results in an OpenGL render.你也可以用缓冲区做同样的事情,例如你可以使用 Vulkan 进行计算操作,然后在 OpenGL 渲染中使用结果。

Requirements要求

Doing this requires that both the OpenGL and Vulkan implementations support the required extensions, however, according to this site , these extensions are widely supported across OS versions and GPU vendors, as long as you're working with a recent (> 1.0.51) version of Vulkan.这样做需要 OpenGL 和 Vulkan 实现都支持所需的扩展,但是,根据这个站点,这些扩展在操作系统版本和 GPU 供应商之间得到广泛支持,只要您使用的是最近的 (> 1.0.51) Vulkan 版本。

You need the the External Objects extension for OpenGL and the External Memory / Fence / Sempahore extensions for Vulkan.您需要 OpenGL 的外部对象扩展和 Vulkan 的外部内存/ 栅栏/ 信号量扩展。

The Vulkan side of the extensions allow you to allocate memory, create semaphores or fences while marking the resulting objects as exportable.扩展的 Vulkan 端允许您分配内存、创建信号量或栅栏,同时将结果对象标记为可导出。 The corresponding GL extensions allow you to take the objects and manipulate them with new GL commands which allow you to wait on fences, signal and wait on semaphores, or use Vulkan allocated memory to back an OpenGL texture.相应的 GL 扩展允许您获取对象并使用新的 GL 命令操作它们,这些命令允许您等待栅栏、发出信号并等待信号量,或使用 Vulkan 分配的内存来支持 OpenGL 纹理。 By using such a texture in an OpenGL framebuffer, you can pretty much render whatever you want to it, and then use the rendered results in Vulkan.通过在 OpenGL 帧缓冲区中使用这样的纹理,您几乎可以渲染任何您想要的内容,然后在 Vulkan 中使用渲染结果。

Export / Import example code导出/导入示例代码

For example, on the Vulkan side, when you're allocating memory for an image you can do this...例如,在 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 
});

This is using the C++ interface and is using the Win32 variation of the extensions.这是使用 C++ 接口并使用扩展的 Win32 变体。 For Posix platforms there are alternative methods for getting file descriptors instead of WIN32 handles.对于 Posix 平台,有获取文件描述符而不是 WIN32 句柄的替代方法。

The sharedMemoryHandle is the value that you'll need to pass to OpenGL, along with the actual allocation size. sharedMemoryHandle是您需要传递给 OpenGL 的值以及实际分配大小。 On the GL side you can then do this...在 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 );

Synchronization同步

The trickiest bit here is synchronization.这里最棘手的一点是同步。 The Vulkan specification requires images to be in certain states (layouts) before corresponding operations can be performed on them. Vulkan 规范要求图像处于特定状态(布局),然后才能对其执行相应的操作。 So in order to do this properly (based on my understanding), you would need to...因此,为了正确执行此操作(根据我的理解),您需要...

  • In Vulkan, create a command buffer that transitions the image to ColorAttachmentOptimal layout在 Vulkan 中,创建一个命令缓冲区,将图像转换为 ColorAttachmentOptimal 布局
  • Submit the command buffer so that it signals a semaphore that has similarly been exported to OpenGL提交命令缓冲区,以便它发出一个信号量,该信号量已类似地导出到 OpenGL
  • In OpenGL, use the glWaitSemaphoreEXT function to cause the GL driver to wait for the transition to complete.在 OpenGL 中,使用glWaitSemaphoreEXT函数使 GL 驱动程序等待转换完成。
    • Note that this is a GPU side wait, so the function will not block at all.请注意,这是 GPU 端等待,因此该函数根本不会阻塞。 It's similar to glWaitSync (as opposed to glClientWaitSync )in this regard.它类似于glWaitSync (相对于glClientWaitSync在这方面)。
  • Execute your GL commands that render to the framebuffer执行渲染到帧缓冲区的 GL 命令
  • Signal a different exported Semaphore on the GL side with the glSignalSemaphoreEXT function使用glSignalSemaphoreEXT函数在 GL 端发出不同的导出信号量信号
  • In Vulkan, execute another image layout transition from ColorAttachmentOptimal to ShaderReadOnlyOptimal在 Vulkan 中,执行另一个从 ColorAttachmentOptimal 到 ShaderReadOnlyOptimal 的图像布局转换
  • Submit the transition command buffer with the wait semaphore set to the one you just signaled from the GL side.提交转换命令缓冲区,等待信号量设置为您刚刚从 GL 端发出信号的信号量。

That's would be an optimal path.那将是一个最佳路径。 Alternatively, the quick and dirty method would be to do the vulkan transition, and then execute queue and device waitIdle commands to ensure the work is done, execute the GL commands, followed by glFlush & glFinish commands to ensure the GPU is done with that work, and then resume your Vulkan commands.或者,快速和肮脏的方法是进行 vulkan 转换,然后执行 queue 和 device waitIdle命令以确保完成工作,执行 GL 命令,然后执行glFlushglFinish命令以确保 GPU 完成工作,然后恢复您的 Vulkan 命令。 This is more of a brute force approach and will likely produce poorer performance than doing the proper synchronization.这更像是一种蛮力方法,并且可能会产生比正确同步更差的性能。

NVIDIA has created an OpenGL extension, NV_draw_vulkan_image, which can render a VkImage in OpenGL. NVIDIA 已经创建了一个 OpenGL 扩展,NV_draw_vulkan_image,它可以在 OpenGL 中渲染一个VkImage It even has some mechanisms for interacting with Vulkan semaphores and the like.它甚至有一些与 Vulkan 信号量等交互的机制。

However, according to the documentation , you must bypass all Vulkan layers, since layers can modify non-dispatchable handles and the OpenGL extension doesn't know about said modifications.但是, 根据文档,您必须绕过所有 Vulkan 层,因为层可以修改不可调度的句柄,而 OpenGL 扩展不知道所述修改。 And their recommended means of doing so is to use the glGetVkProcAddrNV for all of your Vulkan functions.他们推荐的方法是对所有 Vulkan 函数使用glGetVkProcAddrNV

Which also means that you can't get access to any debugging that relies on Vulkan layers.这也意味着您无法访问任何依赖于 Vulkan 层的调试。

There is some more information in this more recent slide deck from SIGGRAPH 2016. Slides 63-65 describe how to blit a Vulkan image to an OpenGL backbuffer.在 SIGGRAPH 2016 的最新幻灯片中还有更多信息。幻灯片 63-65 描述了如何将 Vulkan 图像 blit 到 OpenGL 后台缓冲区。 My opinion is that it may have been pretty easy for NVIDIA to support this since the Vulkan driver is contained in libGL.so (on Linux).我的观点是 NVIDIA 可能很容易支持这一点,因为 Vulkan 驱动程序包含在 libGL.so(在 Linux 上)中。 So it may not have been that hard to give the Vulkan image handle to the GL side of the driver and have it be useful.因此,将 Vulkan 图像句柄提供给驱动程序的 GL 端并使其有用可能并不难。

As another answer pointed out, there are still no official registered multi-vendor interop extensions.正如另一个答案所指出的,仍然没有官方注册的多供应商互操作扩展。 This approach just works on NVIDIA.这种方法只适用于 NVIDIA。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM