共享纹理使用场景:
当硬解码的纹理跨两个device对象(对应一张显卡)传递,比如解码是device1,渲染是device2,此时需要通过共享纹理将解码得到的纹理先拷贝到共享纹理上,然后获取纹理句柄,将该句柄传递给渲染的device2,渲染的device2打开该句柄就可以得到一个纹理进行采样渲染了。
如果不加锁,绘制大分辨率的视频或者输出大分辨的画面时就会有撕裂现象。
具体步骤如下:
1.获取解码的纹理。
ID3D11VideoDecoderOutputView* srcSurface = (ID3D11VideoDecoderOutputView*)(uintptr_t)frame->m_frame->data[3];
D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
srcSurface->GetDesc(&viewDesc);
int slice = viewDesc.Texture2D.ArraySlice;
ComPtr<ID3D11Texture2D> srcTexture;
srcSurface->GetResource((ID3D11Resource**)srcTexture.GetAddressOf());
2.创建共享纹理
D3D11_TEXTURE2D_DESC dstTexDesc;
ZeroMemory(&dstTexDesc, sizeof(dstTexDesc));
dstTexDesc.Width = frame->getWidth();
dstTexDesc.Height = frame->getHeight();
dstTexDesc.MipLevels = 1;
dstTexDesc.ArraySize = 1;
dstTexDesc.Format = DXGI_FORMAT_NV12;
dstTexDesc.SampleDesc.Count = 1;
dstTexDesc.Usage = D3D11_USAGE_DEFAULT;
dstTexDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE| D3D11_BIND_RENDER_TARGET;
dstTexDesc.CPUAccessFlags = 0;
dstTexDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX; //带锁的共享纹理 注意:D3D11_RESOURCE_MISC_SHARED_NTHANDLE该标志会导致花瓶,谨慎使用
//dstTexDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
HRESULT hr = m_device->CreateTexture2D(&dstTexDesc, nullptr, m_sharedTexture_HW.ReleaseAndGetAddressOf());
3.获取共享纹理句柄和锁
//获取纹理的锁
m_sharedTexture_HW.As(&m_sharedkeyMutex0);
//获取纹理的句柄
ComPtr<IDXGIResource1> sharedResource = nullptr;
m_sharedTexture_HW->QueryInterface(__uuidof(IDXGIResource1), reinterpret_cast<void**>(sharedResource.ReleaseAndGetAddressOf()));
//D3D11_RESOURCE_MISC_SHARED_NTHANDLE 该标志使用下面的方式获取纹理句柄
//sharedResource->CreateSharedHandle(nullptr, DXGI_SHARED_RESOURCE_READ, nullptr, &m_sharedHandle0_SW);
sharedResource->GetSharedHandle(&m_sharedHandle_HW);
sharedResource.Reset();
5.更新纹理时加锁
//blt转换方式更新纹理
m_sharedkeyMutex0->AcquireSync(0, INFINITE);
bool processFlag = m_d3d11VideoPorcessor->process(srcTexture.Get(), viewDesc.Texture2D.ArraySlice);
m_sharedkeyMutex0->ReleaseSync(0);
//另一种copy方式更新纹理
m_sharedkeyMutex0->AcquireSync(0, INFINITE);
m_pd3dDeviceContext->CopySubresourceRegion( m_sharedTexture_HW.Get(), 0, 0, 0, 0, srcTexture.Get(), slice, nullptr);
m_sharedkeyMutex0->ReleaseSync(0);
6.渲染设备打开共享纹理句柄
ComPtr<ID3D11Texture2D> pTexture0;
ComPtr<IDXGIKeyedMutex> sharedkeyMutex;
HRESULT hr = m_pd3dDevice->OpenSharedResource(m_sharedHandle_HW, __uuidof(ID3D11Texture2D), (void**)(&pTexture0));
pTexture0.As(&sharedkeyMutex);
7.绘制前加锁,绘制完解锁
sharedkeyMutex->AcquireSync(0, INFINITE);
deviceContext->DrawIndexed(m_IndexCount, 0, 0);
sharedkeyMutex->ReleaseSync(0);