是否可以从Vulkan渲染到OpenGL?
似乎nVidia有一些东西:https: //lunarg.com/faqs/mix-opengl-vulkan-rendering/
可以为其他GPU做到吗?
是的,如果 Vulkan实现和OpenGL实现都具有适当的扩展,则可能.
这是我编写的一个示例应用程序的屏幕截图,它使用OpenGL为纹理渲染一个简单的shadertoy,然后在Vulkan渲染窗口中使用该纹理.
虽然你的问题似乎暗示你想要反过来(使用Vulkan渲染到某些内容然后使用OpenGL显示结果),但同样的概念适用....在一个API中填充纹理,使用同步来确保GPU的工作是完成,然后在其他API中使用纹理.您也可以使用缓冲区执行相同的操作,例如,您可以使用Vulkan进行计算操作,然后在OpenGL渲染中使用结果.
这样做需要OpenGL和Vulkan实现都支持所需的扩展,但是,根据这个站点,这些扩展在操作系统版本和GPU供应商中得到广泛支持,只要你使用最近的(> 1.0.51) Vulkan的版本.
您需要OpenGL 的External Objects扩展和Vulkan 的External 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
});
Run Code Online (Sandbox Code Playgroud)
这是使用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 );
Run Code Online (Sandbox Code Playgroud)
这里最棘手的是同步.Vulkan规范要求图像处于某些状态(布局),然后才能对它们执行相应的操作.所以为了做到这一点(基于我的理解),你需要......
glWaitSemaphoreEXT函数使GL驱动程序等待转换完成.
glWaitSync(相反glClientWaitSync)相似.glSignalSemaphoreEXT函数在GL侧发信号通知不同的导出信号量那将是一条最佳路径.或者,快速和脏的方法是进行vulkan转换,然后执行队列和设备waitIdle命令以确保完成工作,执行GL命令,然后执行glFlush&glFinish命令以确保GPU完成该工作,然后恢复你的Vulkan命令.这更像是一种蛮力方法,并且可能会产生比正确同步更差的性能.
NVIDIA 创建了一个 OpenGL 扩展 NV_draw_vulkan_image,它可以VkImage在 OpenGL 中渲染。它甚至有一些与 Vulkan 信号量等交互的机制。
但是,根据文档,您必须绕过所有 Vulkan 层,因为层可以修改不可调度的句柄,而 OpenGL 扩展不知道这些修改。他们推荐的方法是将glGetVkProcAddrNV用于您的所有 Vulkan 功能。
这也意味着您无法访问任何依赖于 Vulkan 层的调试。