D3D11GraphicsDevice.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #include "pch.h"
  2. #include <third_party/libyuv/include/libyuv/convert.h>
  3. #include "D3D11GraphicsDevice.h"
  4. #include "D3D11Texture2D.h"
  5. #include "GraphicsDevice/Cuda/GpuMemoryBufferCudaHandle.h"
  6. #include "GraphicsDevice/GraphicsUtility.h"
  7. #include "NvCodecUtils.h"
  8. using namespace ::webrtc;
  9. using namespace Microsoft::WRL;
  10. namespace unity
  11. {
  12. namespace webrtc
  13. {
  14. D3D11GraphicsDevice::D3D11GraphicsDevice(
  15. ID3D11Device* nativeDevice, UnityGfxRenderer renderer, ProfilerMarkerFactory* profiler)
  16. : IGraphicsDevice(renderer, profiler)
  17. , m_d3d11Device(nativeDevice)
  18. , m_isCudaSupport(false)
  19. {
  20. // Enable multithread protection
  21. ComPtr<ID3D11Multithread> thread;
  22. m_d3d11Device->QueryInterface<ID3D11Multithread>(&thread);
  23. thread->SetMultithreadProtected(true);
  24. }
  25. D3D11GraphicsDevice::~D3D11GraphicsDevice() { }
  26. bool D3D11GraphicsDevice::InitV()
  27. {
  28. CUresult ret = m_cudaContext.Init(m_d3d11Device);
  29. if (ret == CUDA_SUCCESS)
  30. {
  31. m_isCudaSupport = true;
  32. }
  33. return true;
  34. }
  35. //---------------------------------------------------------------------------------------------------------------------
  36. void D3D11GraphicsDevice::ShutdownV() { m_cudaContext.Shutdown(); }
  37. //---------------------------------------------------------------------------------------------------------------------
  38. ITexture2D*
  39. D3D11GraphicsDevice::CreateDefaultTextureV(uint32_t w, uint32_t h, UnityRenderingExtTextureFormat textureFormat)
  40. {
  41. ID3D11Texture2D* texture = nullptr;
  42. D3D11_TEXTURE2D_DESC desc = {};
  43. desc.Width = w;
  44. desc.Height = h;
  45. desc.MipLevels = 1;
  46. desc.ArraySize = 1;
  47. desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
  48. desc.SampleDesc.Count = 1;
  49. desc.Usage = D3D11_USAGE_DEFAULT;
  50. desc.BindFlags = 0;
  51. desc.CPUAccessFlags = 0;
  52. HRESULT result = m_d3d11Device->CreateTexture2D(&desc, nullptr, &texture);
  53. if (result != S_OK)
  54. {
  55. RTC_LOG(LS_INFO) << "CreateTexture2D failed. error:" << result;
  56. return nullptr;
  57. }
  58. return new D3D11Texture2D(w, h, texture);
  59. }
  60. //---------------------------------------------------------------------------------------------------------------------
  61. ITexture2D*
  62. D3D11GraphicsDevice::CreateCPUReadTextureV(uint32_t w, uint32_t h, UnityRenderingExtTextureFormat textureFormat)
  63. {
  64. ID3D11Texture2D* texture = nullptr;
  65. D3D11_TEXTURE2D_DESC desc = {};
  66. desc.Width = w;
  67. desc.Height = h;
  68. desc.MipLevels = 1;
  69. desc.ArraySize = 1;
  70. desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
  71. desc.SampleDesc.Count = 1;
  72. desc.Usage = D3D11_USAGE_STAGING;
  73. desc.BindFlags = 0;
  74. desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
  75. HRESULT hr = m_d3d11Device->CreateTexture2D(&desc, nullptr, &texture);
  76. if (hr != S_OK)
  77. {
  78. return nullptr;
  79. }
  80. return new D3D11Texture2D(w, h, texture);
  81. }
  82. //---------------------------------------------------------------------------------------------------------------------
  83. bool D3D11GraphicsDevice::CopyResourceV(ITexture2D* dest, ITexture2D* src)
  84. {
  85. ID3D11Resource* nativeDest = reinterpret_cast<ID3D11Resource*>(dest->GetNativeTexturePtrV());
  86. ID3D11Resource* nativeSrc = reinterpret_cast<ID3D11Texture2D*>(src->GetNativeTexturePtrV());
  87. if (nativeSrc == nativeDest)
  88. return false;
  89. if (nativeSrc == nullptr || nativeDest == nullptr)
  90. return false;
  91. ComPtr<ID3D11DeviceContext> context;
  92. m_d3d11Device->GetImmediateContext(context.GetAddressOf());
  93. context->CopyResource(nativeDest, nativeSrc);
  94. // todo(kazuki): Flush incurs a significant amount of overhead.
  95. // Should run the process of copying texture asyncnously.
  96. HRESULT hr = WaitFlush();
  97. if (hr != S_OK)
  98. {
  99. RTC_LOG(LS_INFO) << "WaitFlush failed. error:" << hr;
  100. return false;
  101. }
  102. return true;
  103. }
  104. //---------------------------------------------------------------------------------------------------------------------
  105. bool D3D11GraphicsDevice::CopyResourceFromNativeV(ITexture2D* dest, void* nativeTexturePtr)
  106. {
  107. ID3D11Resource* nativeDest = reinterpret_cast<ID3D11Resource*>(dest->GetNativeTexturePtrV());
  108. ID3D11Resource* nativeSrc = reinterpret_cast<ID3D11Resource*>(nativeTexturePtr);
  109. if (nativeSrc == nativeDest)
  110. return false;
  111. if (nativeSrc == nullptr || nativeDest == nullptr)
  112. return false;
  113. ComPtr<ID3D11DeviceContext> context;
  114. m_d3d11Device->GetImmediateContext(context.GetAddressOf());
  115. context->CopyResource(nativeDest, nativeSrc);
  116. // todo(kazuki): Flush incurs a significant amount of overhead.
  117. // Should run the process of copying texture asyncnously.
  118. HRESULT hr = WaitFlush();
  119. if (hr != S_OK)
  120. {
  121. RTC_LOG(LS_INFO) << "WaitFlush failed. error:" << hr;
  122. return false;
  123. }
  124. return true;
  125. }
  126. HRESULT D3D11GraphicsDevice::WaitFlush()
  127. {
  128. ComPtr<ID3D11DeviceContext> context;
  129. m_d3d11Device->GetImmediateContext(context.GetAddressOf());
  130. context->Flush();
  131. D3D11_QUERY_DESC queryDesc = { D3D11_QUERY_EVENT, 0 };
  132. ComPtr<ID3D11Query> query;
  133. HRESULT hr = m_d3d11Device->CreateQuery(&queryDesc, query.GetAddressOf());
  134. if (hr != S_OK)
  135. {
  136. return hr;
  137. }
  138. context->End(query.Get());
  139. while (S_OK != context->GetData(query.Get(), nullptr, 0, 0))
  140. ;
  141. return S_OK;
  142. }
  143. //---------------------------------------------------------------------------------------------------------------------
  144. rtc::scoped_refptr<I420Buffer> D3D11GraphicsDevice::ConvertRGBToI420(ITexture2D* tex)
  145. {
  146. D3D11_MAPPED_SUBRESOURCE pMappedResource;
  147. ID3D11Resource* pResource = reinterpret_cast<ID3D11Resource*>(tex->GetNativeTexturePtrV());
  148. if (nullptr == pResource)
  149. return nullptr;
  150. ComPtr<ID3D11DeviceContext> context;
  151. m_d3d11Device->GetImmediateContext(context.GetAddressOf());
  152. const HRESULT hr = context->Map(pResource, 0, D3D11_MAP_READ, 0, &pMappedResource);
  153. if (hr != S_OK)
  154. return nullptr;
  155. const int32_t width = static_cast<int32_t>(tex->GetWidth());
  156. const int32_t height = static_cast<int32_t>(tex->GetHeight());
  157. rtc::scoped_refptr<webrtc::I420Buffer> i420_buffer = webrtc::I420Buffer::Create(width, height);
  158. libyuv::ARGBToI420(
  159. static_cast<uint8_t*>(pMappedResource.pData),
  160. static_cast<int32_t>(pMappedResource.RowPitch),
  161. i420_buffer->MutableDataY(),
  162. i420_buffer->StrideY(),
  163. i420_buffer->MutableDataU(),
  164. i420_buffer->StrideU(),
  165. i420_buffer->MutableDataV(),
  166. i420_buffer->StrideV(),
  167. width,
  168. height);
  169. context->Unmap(pResource, 0);
  170. return i420_buffer;
  171. }
  172. std::unique_ptr<GpuMemoryBufferHandle> D3D11GraphicsDevice::Map(ITexture2D* texture)
  173. {
  174. if (!IsCudaSupport())
  175. return nullptr;
  176. CUgraphicsResource resource;
  177. ID3D11Resource* pResource = static_cast<ID3D11Resource*>(texture->GetNativeTexturePtrV());
  178. // set context on the thread.
  179. cuCtxPushCurrent(GetCUcontext());
  180. CUresult result =
  181. cuGraphicsD3D11RegisterResource(&resource, pResource, CU_GRAPHICS_REGISTER_FLAGS_SURFACE_LDST);
  182. if (result != CUDA_SUCCESS)
  183. {
  184. RTC_LOG(LS_ERROR) << "cuGraphicsD3D11RegisterResource";
  185. throw;
  186. }
  187. result = cuGraphicsMapResources(1, &resource, nullptr);
  188. if (result != CUDA_SUCCESS)
  189. {
  190. RTC_LOG(LS_ERROR) << "cuGraphicsMapResources";
  191. throw;
  192. }
  193. CUarray mappedArray;
  194. result = cuGraphicsSubResourceGetMappedArray(&mappedArray, resource, 0, 0);
  195. if (result != CUDA_SUCCESS)
  196. {
  197. RTC_LOG(LS_ERROR) << "cuGraphicsSubResourceGetMappedArray";
  198. throw;
  199. }
  200. cuCtxPopCurrent(nullptr);
  201. std::unique_ptr<GpuMemoryBufferCudaHandle> handle = std::make_unique<GpuMemoryBufferCudaHandle>();
  202. handle->context = GetCUcontext();
  203. handle->mappedArray = mappedArray;
  204. handle->resource = resource;
  205. return std::move(handle);
  206. }
  207. } // end namespace webrtc
  208. } // end namespace unity