[英]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 渲染窗口中使用该纹理。
虽然你的问题似乎暗示你想要做相反的事情(使用 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 规范要求图像处于特定状态(布局),然后才能对其执行相应的操作。 因此,为了正确执行此操作(根据我的理解),您需要...
glWaitSemaphoreEXT
函数使 GL 驱动程序等待转换完成。
glWaitSync
(相对于glClientWaitSync
在这方面)。glSignalSemaphoreEXT
函数在 GL 端发出不同的导出信号量信号 那将是一个最佳路径。 或者,快速和肮脏的方法是进行 vulkan 转换,然后执行 queue 和 device waitIdle
命令以确保完成工作,执行 GL 命令,然后执行glFlush
和glFinish
命令以确保 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.