如何从Vulkan渲染到OpenGL?

时间:2016-08-11 23:46:50

标签: opengl vulkan

是否可以从Vulkan渲染到OpenGL?

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

可以为其他GPU做到吗?

3 个答案:

答案 0 :(得分:6)

是的,可能如果 Vulkan实现和OpenGL实现都有适当的扩展可用。

这是我编写的example app的屏幕截图,它使用OpenGL将简单的shadertoy渲染到纹理,然后在Vulkan渲染窗口中使用该纹理。

gl to vulkan example

虽然你的问题似乎暗示你想要反过来(使用Vulkan渲染到某些内容然后使用OpenGL显示结果),但同样的概念适用....在一个API中填充纹理,使用同步来确保GPU工作完成,然后在其他API中使用纹理。您也可以使用缓冲区执行相同的操作,例如,您可以使用Vulkan进行计算操作,然后在OpenGL渲染中使用结果。

要求

这样做要求OpenGL和Vulkan实现都支持所需的扩展,但是,根据this site,这些扩展在OS版本和GPU供应商中得到广泛支持,只要您使用最近的(> 1.0.51)版本的Vulkan。

您需要OpenGL的External Objects扩展名和Vulkan的外部Memory / Fence / Sempahore扩展名。

扩展的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转换,然后执行队列和设备waitIdle命令以确保完成工作,执行GL命令,然后执行glFlush& glFinish命令确保使用 工作完成GPU,然后恢复Vulkan命令。这更像是一种蛮力方法,并且可能会产生比正确同步更差的性能。

答案 1 :(得分:3)

NVIDIA创建了一个OpenGL扩展NV_draw_vulkan_image,它可以在OpenGL中呈现VkImage。它甚至还有一些与Vulkan信号量等交互的机制。

但是,according to the documentation必须绕过所有Vulkan图层,因为图层可以修改不可分派的句柄,而OpenGL扩展程序也不知道所述修改。他们建议的方法是将glGetVkProcAddrNV用于所有Vulkan函数。

这也意味着您无法访问任何依赖于Vulkan图层的调试。

答案 2 :(得分:0)

SIGGRAPH 2016最新slide deck中提供了更多信息。幻灯片63-65描述了如何将Vulkan图像blit到OpenGL后备缓冲区。我的观点是NVIDIA可能很容易支持这一点,因为Vulkan驱动程序包含在libGL.so中(在Linux上)。因此,将Vulkan图像句柄提供给驱动程序的GL端并使其有用可能并不困难。

另一个答案指出,仍然没有正式注册的多供应商互操作扩展。这种方法适用于NVIDIA。