如何使用 glImportMemoryWin32HandleEXT 与 OpenGL 共享 ID3D11Texture2D KeyedMutex 共享句柄?
How to use glImportMemoryWin32HandleEXT to share an ID3D11Texture2D KeyedMutex Shared handle with OpenGL?
我正在研究如何使用 EXT_external_objects
, EXT_external_objects_win32
and EXT_win32_keyed_mutex
OpenGL extensions. My goal is to share a B8G8R8A8_UNORM texture (an external library expects BGRA and I can not change it. What's relevant here is the byte depth of 4) with 1 Mip-level allocated and written to offscreen with D3D11 by one application, and render it with OpenGL in another. Because the texture is being drawn to off-process, I can not use WGL_NV_DX_interop2.
与 OpenGL 和 Direct3D 11 进行跨进程互操作
我的实际代码可以看here,是用C#写的Silk.NET。不过为了说明的目的,我将在 psuedo-C(++) 中描述我的问题。
首先,我使用 D3D11 在进程 A 中创建我的纹理,并获取它的共享句柄,并将其发送到进程 B。
#define WIDTH 100
#define HEIGHT 100
#define BPP 4 // BGRA8 is 4 bytes per pixel
ID3D11Texture2D *texture;
D3D11_TEXTURE2D_DESC texDesc = {
.Width = WIDTH,
.Height = HEIGHT,
.MipLevels = 1,
.ArraySize = 1,
.Format = DXGI_FORMAT_B8G8R8A8_UNORM,
.SampleDesc = { .Count = 1, .Quality = 0 }
.Usage = USAGE_DEFAULT,
.BindFlags = BIND_SHADER_RESOURCE
.CPUAccessFlags = 0,
.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX
};
device->CreateTexture2D(&texDesc, NULL, &texture);
HANDLE sharedHandle;
texture->CreateSharedHandle(NULL, DXGI_SHARED_RESOURCE_READ, NULL, &sharedHandle);
SendToProcessB(sharedHandle, pid);
在进程 B 中,我首先复制句柄以获得进程本地句柄。
HANDLE localSharedHandle;
HANDLE hProcA = OpenProcess(PROCESS_DUP_HANDLE, false, processAPID);
DuplicateHandle(hProcA, sharedHandle, GetCurrentProcess(), &localSharedHandle, 0, false, DUPLICATE_SAME_ACCESS);
CloseHandle(hProcA)
此时,我在 localSharedHandle
中有一个有效的 DXGI 资源共享句柄。我有一个 ProcessB 的 D3D11 实现,它能够在使用 OpenSharedResource1
打开后成功渲染共享纹理。然而,我的问题是 OpenGL。
这就是我目前为 OpenGL 做的事情
GLuint sharedTexture, memObj;
glCreateTextures(GL_TEXTURE_2D, 1, &sharedTexture);
glTextureParameteri(sharedTexture, TEXTURE_TILING_EXT, OPTIMAL_TILING_EXT); // D3D11 side is D3D11_TEXTURE_LAYOUT_UNDEFINED
// Create the memory object handle
glCreateMemoryObjectsEXT(1, &memObj);
// I am not actually sure what the size parameter here is referring to.
// Since the source texture is DX11, there's no way to get the allocation size,
// I make a guess of W * H * BPP
// According to docs for VkExternalMemoryHandleTypeFlagBitsNV, NtHandle Shared Resources use HANDLE_TYPE_D3D11_IMAGE_EXT
glImportMemoryWin32HandleEXT(memObj, WIDTH * HEIGHT * BPP, GL_HANDLE_TYPE_D3D11_IMAGE_EXT, (void*)localSharedHandle);
DBG_GL_CHECK_ERROR(); // GL_NO_ERROR
沿途检查错误似乎表明导入成功。但是我无法绑定纹理。
if (glAcquireKeyedMutexWin32EXT(memObj, 0, (UINT)-1) {
DBG_GL_CHECK_ERROR(); // GL_NO_ERROR
glTextureStorageMem2D(sharedTexture, 1, GL_RGBA8, WIDTH, HEIGHT, memObj, 0);
DBG_GL_CHECK_ERROR(); // GL_INVALID_VALUE
glReleaseKeyedMutexWin32EXT(memObj, 0);
}
对 glTextureStorageMem2D 的调用出了问题。正在正确获取和释放共享的 KeyedMutex。扩展文档不清楚我应该如何正确绑定此纹理并绘制它。
经过更多调试后,我设法从调试上下文中获取了 [DebugSeverityHigh] DebugSourceApi: DebugTypeError, id: 1281: GL_INVALID_VALUE error generated. Memory object too small
。通过将我的宽度分成两半,我能够在屏幕上得到一些乱码输出。
事实证明导入纹理所需的大小不是 WIDTH * HEIGHT * BPP
,(在本例中 BGRA 的 BPP = 4
),而是 WIDTH * HEIGHT * BPP * 2
。导入大小为 WIDTH * HEIGHT * BPP * 2
的句柄允许纹理正确绑定和正确渲染。
我正在研究如何使用 EXT_external_objects
, EXT_external_objects_win32
and EXT_win32_keyed_mutex
OpenGL extensions. My goal is to share a B8G8R8A8_UNORM texture (an external library expects BGRA and I can not change it. What's relevant here is the byte depth of 4) with 1 Mip-level allocated and written to offscreen with D3D11 by one application, and render it with OpenGL in another. Because the texture is being drawn to off-process, I can not use WGL_NV_DX_interop2.
我的实际代码可以看here,是用C#写的Silk.NET。不过为了说明的目的,我将在 psuedo-C(++) 中描述我的问题。
首先,我使用 D3D11 在进程 A 中创建我的纹理,并获取它的共享句柄,并将其发送到进程 B。
#define WIDTH 100
#define HEIGHT 100
#define BPP 4 // BGRA8 is 4 bytes per pixel
ID3D11Texture2D *texture;
D3D11_TEXTURE2D_DESC texDesc = {
.Width = WIDTH,
.Height = HEIGHT,
.MipLevels = 1,
.ArraySize = 1,
.Format = DXGI_FORMAT_B8G8R8A8_UNORM,
.SampleDesc = { .Count = 1, .Quality = 0 }
.Usage = USAGE_DEFAULT,
.BindFlags = BIND_SHADER_RESOURCE
.CPUAccessFlags = 0,
.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX
};
device->CreateTexture2D(&texDesc, NULL, &texture);
HANDLE sharedHandle;
texture->CreateSharedHandle(NULL, DXGI_SHARED_RESOURCE_READ, NULL, &sharedHandle);
SendToProcessB(sharedHandle, pid);
在进程 B 中,我首先复制句柄以获得进程本地句柄。
HANDLE localSharedHandle;
HANDLE hProcA = OpenProcess(PROCESS_DUP_HANDLE, false, processAPID);
DuplicateHandle(hProcA, sharedHandle, GetCurrentProcess(), &localSharedHandle, 0, false, DUPLICATE_SAME_ACCESS);
CloseHandle(hProcA)
此时,我在 localSharedHandle
中有一个有效的 DXGI 资源共享句柄。我有一个 ProcessB 的 D3D11 实现,它能够在使用 OpenSharedResource1
打开后成功渲染共享纹理。然而,我的问题是 OpenGL。
这就是我目前为 OpenGL 做的事情
GLuint sharedTexture, memObj;
glCreateTextures(GL_TEXTURE_2D, 1, &sharedTexture);
glTextureParameteri(sharedTexture, TEXTURE_TILING_EXT, OPTIMAL_TILING_EXT); // D3D11 side is D3D11_TEXTURE_LAYOUT_UNDEFINED
// Create the memory object handle
glCreateMemoryObjectsEXT(1, &memObj);
// I am not actually sure what the size parameter here is referring to.
// Since the source texture is DX11, there's no way to get the allocation size,
// I make a guess of W * H * BPP
// According to docs for VkExternalMemoryHandleTypeFlagBitsNV, NtHandle Shared Resources use HANDLE_TYPE_D3D11_IMAGE_EXT
glImportMemoryWin32HandleEXT(memObj, WIDTH * HEIGHT * BPP, GL_HANDLE_TYPE_D3D11_IMAGE_EXT, (void*)localSharedHandle);
DBG_GL_CHECK_ERROR(); // GL_NO_ERROR
沿途检查错误似乎表明导入成功。但是我无法绑定纹理。
if (glAcquireKeyedMutexWin32EXT(memObj, 0, (UINT)-1) {
DBG_GL_CHECK_ERROR(); // GL_NO_ERROR
glTextureStorageMem2D(sharedTexture, 1, GL_RGBA8, WIDTH, HEIGHT, memObj, 0);
DBG_GL_CHECK_ERROR(); // GL_INVALID_VALUE
glReleaseKeyedMutexWin32EXT(memObj, 0);
}
对 glTextureStorageMem2D 的调用出了问题。正在正确获取和释放共享的 KeyedMutex。扩展文档不清楚我应该如何正确绑定此纹理并绘制它。
经过更多调试后,我设法从调试上下文中获取了 [DebugSeverityHigh] DebugSourceApi: DebugTypeError, id: 1281: GL_INVALID_VALUE error generated. Memory object too small
。通过将我的宽度分成两半,我能够在屏幕上得到一些乱码输出。
事实证明导入纹理所需的大小不是 WIDTH * HEIGHT * BPP
,(在本例中 BGRA 的 BPP = 4
),而是 WIDTH * HEIGHT * BPP * 2
。导入大小为 WIDTH * HEIGHT * BPP * 2
的句柄允许纹理正确绑定和正确渲染。