转过头再找个复杂的播放程序验证一下,还是用我比较熟悉的MediaSDK的播放程序。基本思路就是
- 在初始化解码输出显示的窗口的时候同时也初始化一个vulkan显示的窗口
- 初始化d3d11设备的时候初始化vulkan, 同时多创建一个D3D11Texture2D的共享纹理
- 最后在MSDK每个frame在解码结束,把视频帧输出到DXGI的back buffer的同时,也把视频帧用VideoProcessorBlt()的方法更新进共享纹理里去
- 通过以上3步,应该那个vulkan的窗口里的纹理也会正常显示出我的解码图像了
实现的时候基本难度不大,有了前面共享opengl和opencl的经验,很快就集成好了。集成的过程里有2个坑:
- 在集成的时候,发现在sample_decode的程序里创建的D3D11Texture2D的属性MiscFlags如果有D3D11_RESOURCE_MISC_SHARED_KEYMUTEX则这个Texture2D对象创建失败,CreateTexture2D()返回E_INVALIDARG;但是如果MiscFlags的属性是 D3D11_RESOURCE_MISC_SHARED则没有问题。同时前一篇文章里基于vulkan tutorial的测试代码则没有问题。
hres = CreateDXGIFactory(__uuidof(IDXGIFactory2), (void**)(&m_pDXGIFactory));
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
hres = m_pDXGIFactory->EnumAdapters(nAdapterNum,&m_pAdapter);
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
hres = D3D11CreateDevice(m_pAdapter ,
D3D_DRIVER_TYPE_UNKNOWN,
NULL,
0,
FeatureLevels,
MSDK_ARRAY_LEN(FeatureLevels),
D3D11_SDK_VERSION,
&m_pD3D11Device,
&pFeatureLevelsOut,
&m_pD3D11Ctx);
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
#if 1
CD3D11_TEXTURE2D_DESC TextureDesc2(DXGI_FORMAT_R8G8B8A8_UNORM, SHARED_TEXTURE_WIDTH, SHARED_TEXTURE_HEIGHT, 1, 1);
TextureDesc2.BindFlags = D3D11_BIND_RENDER_TARGET;
//当MiscFlags有D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX时
TextureDesc2.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX | D3D11_RESOURCE_MISC_SHARED_NTHANDLE;
hres = m_pD3D11Device->CreateTexture2D(&TextureDesc2, 0, &Shared_Texture);
//这里hres返回E_INVALIDARG
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
#endif
经过反复比对,最终定位到了这个函数,MediaSDK sample_decode调用的是
hres = CreateDXGIFactory(__uuidof(IDXGIFactory2), (void**)(&m_pDXGIFactory) );
vulkan tutorial调用的是
VERIFY(SUCCEEDED(CreateDXGIFactory2(0, IID_PPV_ARGS(&DxgiFactory))));
上网搜索了一下,在这里找到了答案
最后验证一下,把原来代码里的 hres = CreateDXGIFactory(__uuidof(IDXGIFactory2), (void**)(&m_pDXGIFactory) );
改成hres = CreateDXGIFactory1(__uuidof(IDXGIFactory2), (void**)(&m_pDXGIFactory) );
下面的CreateTexture2D()就返回S_OK了
- 代码编译过去以后在链接的时候报错,报一些标准库函数找不到
查了一下,主要原因是MediaSDK的sample_decode/sample_common工程的编译参数里Runtime Library设置的是Multi-threaded. 而link的GLFW库我在编译的时候用的是默认设置,Runtime Library用的是Multi-threaded DLL设置,所以把GLFW项目设置成Multi-threaded, 重新编译一遍就链接成功了
最后运行一下编译出的代码,
一切正常,收工 :)
最后按照惯例,源码奉上,仅供参考
PS 最后补上一段后续的更新:
前面研究的一直是通过DX Texture2D创建buffer再共享给Vulkan,这条路虽然有一些坑,但是看来是通的。另外有条路是在Vulkan一边的vkAllocateMemory()创建一个buffer再通过vkGetMemoryWin32HandleKHR()走D3d11Device->OpenSharedResource()来共享给DX。这条路目前死活走不通,大概的思路是在VK侧获取的sharedHandle, 在DX侧OpenSharedResource()来创建基于共享buffer的DX Texture2D, 但是这步始终返回E_INVALIDARG, 看上去是DX的API不认识这个handle。
在Direct3D VkExternalMemoryHandleTypeFlagBits documentation is misleading #1551 这里看到的讨论,我的理解是Vulkan是不支持export出一个D3D的handle的,不知道我的理解对不对,反正目前在Intel的集显上,我尝试了各种参数设置,但是都是在OpenSharedResource()这步报错,估计这条路暂时是调不通了,只能留待以后慢慢研究了。如果有走通的大侠在这里能指点1,2。