gl_image_dxgi.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/gl/gl_image_dxgi.h"
  5. #include <d3d11_1.h>
  6. #include "base/debug/alias.h"
  7. #include "third_party/khronos/EGL/egl.h"
  8. #include "third_party/khronos/EGL/eglext.h"
  9. #include "ui/gfx/buffer_format_util.h"
  10. #include "ui/gl/gl_angle_util_win.h"
  11. #include "ui/gl/gl_bindings.h"
  12. #include "ui/gl/gl_image.h"
  13. #include "ui/gl/gl_surface_egl.h"
  14. #ifndef EGL_ANGLE_d3d_texture_client_buffer
  15. #define EGL_ANGLE_d3d_texture_client_buffer 1
  16. #define EGL_D3D_TEXTURE_ANGLE 0x33A3
  17. #endif /* EGL_ANGLE_d3d_texture_client_buffer */
  18. namespace gl {
  19. namespace {
  20. // Keys used to acquire and release the keyed mutex. Will need to be kept in
  21. // sync with any other code that reads from or draws to the same DXGI handle.
  22. const static UINT64 KEY_BIND = 0;
  23. const static UINT64 KEY_RELEASE = 1;
  24. bool SupportedBindFormat(gfx::BufferFormat format) {
  25. switch (format) {
  26. case gfx::BufferFormat::RGBA_8888:
  27. case gfx::BufferFormat::RGBX_8888:
  28. return true;
  29. default:
  30. return false;
  31. };
  32. }
  33. bool HasAlpha(gfx::BufferFormat format) {
  34. DCHECK(SupportedBindFormat(format));
  35. return gfx::AlphaBitsForBufferFormat(format) > 0;
  36. }
  37. EGLConfig ChooseCompatibleConfig(gfx::BufferFormat format) {
  38. DCHECK(SupportedBindFormat(format));
  39. const EGLint buffer_bind_to_texture =
  40. HasAlpha(format) ? EGL_BIND_TO_TEXTURE_RGBA : EGL_BIND_TO_TEXTURE_RGB;
  41. const EGLint buffer_size = HasAlpha(format) ? 32 : 24;
  42. EGLint const attrib_list[] = {EGL_RED_SIZE,
  43. 8,
  44. EGL_GREEN_SIZE,
  45. 8,
  46. EGL_BLUE_SIZE,
  47. 8,
  48. EGL_SURFACE_TYPE,
  49. EGL_PBUFFER_BIT,
  50. buffer_bind_to_texture,
  51. EGL_TRUE,
  52. EGL_BUFFER_SIZE,
  53. buffer_size,
  54. EGL_NONE};
  55. EGLint num_config;
  56. EGLDisplay display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
  57. EGLBoolean result =
  58. eglChooseConfig(display, attrib_list, nullptr, 0, &num_config);
  59. if (result != EGL_TRUE)
  60. return nullptr;
  61. std::vector<EGLConfig> all_configs(num_config);
  62. result = eglChooseConfig(display, attrib_list, all_configs.data(), num_config,
  63. &num_config);
  64. if (result != EGL_TRUE)
  65. return nullptr;
  66. for (EGLConfig config : all_configs) {
  67. EGLint bits;
  68. if (!eglGetConfigAttrib(display, config, EGL_RED_SIZE, &bits) ||
  69. bits != 8) {
  70. continue;
  71. }
  72. if (!eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &bits) ||
  73. bits != 8) {
  74. continue;
  75. }
  76. if (!eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &bits) ||
  77. bits != 8) {
  78. continue;
  79. }
  80. if (HasAlpha(format) &&
  81. (!eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &bits) ||
  82. bits != 8)) {
  83. continue;
  84. }
  85. return config;
  86. }
  87. return nullptr;
  88. }
  89. EGLSurface CreatePbuffer(const Microsoft::WRL::ComPtr<ID3D11Texture2D>& texture,
  90. gfx::BufferFormat format,
  91. EGLConfig config,
  92. unsigned target) {
  93. DCHECK(SupportedBindFormat(format));
  94. D3D11_TEXTURE2D_DESC desc;
  95. texture->GetDesc(&desc);
  96. EGLint width = desc.Width;
  97. EGLint height = desc.Height;
  98. EGLint pBufferAttributes[] = {
  99. EGL_WIDTH,
  100. width,
  101. EGL_HEIGHT,
  102. height,
  103. EGL_TEXTURE_TARGET,
  104. EGL_TEXTURE_2D,
  105. EGL_TEXTURE_FORMAT,
  106. HasAlpha(format) ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB,
  107. EGL_NONE};
  108. return eglCreatePbufferFromClientBuffer(
  109. gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(), EGL_D3D_TEXTURE_ANGLE,
  110. texture.Get(), config, pBufferAttributes);
  111. }
  112. } // namespace
  113. GLImageDXGI::GLImageDXGI(const gfx::Size& size, EGLStreamKHR stream)
  114. : size_(size), stream_(stream) {}
  115. // static
  116. GLImageDXGI* GLImageDXGI::FromGLImage(GLImage* image) {
  117. if (!image || image->GetType() != Type::DXGI_IMAGE)
  118. return nullptr;
  119. return static_cast<GLImageDXGI*>(image);
  120. }
  121. GLImageDXGI::BindOrCopy GLImageDXGI::ShouldBindOrCopy() {
  122. return BIND;
  123. }
  124. bool GLImageDXGI::BindTexImage(unsigned target) {
  125. if (!handle_.Get())
  126. return true;
  127. DCHECK(texture_);
  128. DCHECK(keyed_mutex_);
  129. if (!SupportedBindFormat(buffer_format_))
  130. return false;
  131. // Lazy-initialize surface_, as it is only used for binding.
  132. if (surface_ == EGL_NO_SURFACE) {
  133. EGLConfig config = ChooseCompatibleConfig(buffer_format_);
  134. if (!config)
  135. return false;
  136. surface_ = CreatePbuffer(texture_, buffer_format_, config, target);
  137. if (surface_ == EGL_NO_SURFACE)
  138. return false;
  139. }
  140. // We don't wait, just return immediately.
  141. HRESULT hrWait = keyed_mutex_->AcquireSync(KEY_BIND, 0);
  142. if (hrWait == WAIT_TIMEOUT || hrWait == WAIT_ABANDONED || FAILED(hrWait)) {
  143. NOTREACHED();
  144. return false;
  145. }
  146. return eglBindTexImage(gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(),
  147. surface_, EGL_BACK_BUFFER) == EGL_TRUE;
  148. }
  149. bool GLImageDXGI::CopyTexImage(unsigned target) {
  150. NOTREACHED();
  151. return false;
  152. }
  153. bool GLImageDXGI::CopyTexSubImage(unsigned target,
  154. const gfx::Point& offset,
  155. const gfx::Rect& rect) {
  156. return false;
  157. }
  158. void GLImageDXGI::Flush() {}
  159. unsigned GLImageDXGI::GetInternalFormat() {
  160. if (!handle_.Get())
  161. return GL_BGRA_EXT;
  162. else
  163. return HasAlpha(buffer_format_) ? GL_RGBA : GL_RGB;
  164. }
  165. unsigned GLImageDXGI::GetDataType() {
  166. return GL_UNSIGNED_BYTE;
  167. }
  168. gfx::Size GLImageDXGI::GetSize() {
  169. return size_;
  170. }
  171. GLImage::Type GLImageDXGI::GetType() const {
  172. return Type::DXGI_IMAGE;
  173. }
  174. void GLImageDXGI::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
  175. uint64_t process_tracing_id,
  176. const std::string& dump_name) {}
  177. void GLImageDXGI::ReleaseTexImage(unsigned target) {
  178. if (!handle_.Get())
  179. return;
  180. DCHECK(texture_);
  181. DCHECK(keyed_mutex_);
  182. keyed_mutex_->ReleaseSync(KEY_RELEASE);
  183. eglReleaseTexImage(gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(),
  184. surface_, EGL_BACK_BUFFER);
  185. }
  186. bool GLImageDXGI::InitializeHandle(base::win::ScopedHandle handle,
  187. uint32_t level,
  188. gfx::BufferFormat format) {
  189. level_ = level;
  190. buffer_format_ = format;
  191. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  192. QueryD3D11DeviceObjectFromANGLE();
  193. if (!d3d11_device)
  194. return false;
  195. Microsoft::WRL::ComPtr<ID3D11Device1> d3d11_device1;
  196. if (FAILED(d3d11_device.As(&d3d11_device1)))
  197. return false;
  198. if (FAILED(d3d11_device1->OpenSharedResource1(handle.Get(),
  199. IID_PPV_ARGS(&texture_)))) {
  200. return false;
  201. }
  202. D3D11_TEXTURE2D_DESC desc;
  203. texture_->GetDesc(&desc);
  204. if (desc.ArraySize <= level_)
  205. return false;
  206. if (FAILED(texture_.As(&keyed_mutex_)))
  207. return false;
  208. handle_ = std::move(handle);
  209. return true;
  210. }
  211. void GLImageDXGI::SetTexture(
  212. const Microsoft::WRL::ComPtr<ID3D11Texture2D>& texture,
  213. size_t level) {
  214. texture_ = texture;
  215. level_ = level;
  216. }
  217. GLImageDXGI::~GLImageDXGI() {
  218. if (handle_.Get()) {
  219. if (surface_ != EGL_NO_SURFACE) {
  220. eglDestroySurface(gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(),
  221. surface_);
  222. }
  223. } else if (stream_) {
  224. eglDestroyStreamKHR(gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay(),
  225. stream_);
  226. }
  227. }
  228. CopyingGLImageDXGI::CopyingGLImageDXGI(
  229. const Microsoft::WRL::ComPtr<ID3D11Device>& d3d11_device,
  230. const gfx::Size& size,
  231. EGLStreamKHR stream)
  232. : GLImageDXGI(size, stream), d3d11_device_(d3d11_device) {}
  233. bool CopyingGLImageDXGI::Initialize() {
  234. D3D11_TEXTURE2D_DESC desc;
  235. desc.Width = size_.width();
  236. desc.Height = size_.height();
  237. desc.MipLevels = 1;
  238. desc.ArraySize = 1;
  239. desc.Format = DXGI_FORMAT_NV12;
  240. desc.SampleDesc.Count = 1;
  241. desc.SampleDesc.Quality = 0;
  242. desc.Usage = D3D11_USAGE_DEFAULT;
  243. desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
  244. desc.CPUAccessFlags = 0;
  245. desc.MiscFlags = 0;
  246. HRESULT hr =
  247. d3d11_device_->CreateTexture2D(&desc, nullptr, &decoder_copy_texture_);
  248. if (FAILED(hr)) {
  249. DLOG(ERROR) << "CreateTexture2D failed: " << std::hex << hr;
  250. return false;
  251. }
  252. EGLDisplay egl_display = gl::GLSurfaceEGL::GetGLDisplayEGL()->GetDisplay();
  253. EGLAttrib frame_attributes[] = {
  254. EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 0, EGL_NONE,
  255. };
  256. EGLBoolean result = eglStreamPostD3DTextureANGLE(
  257. egl_display, stream_, static_cast<void*>(decoder_copy_texture_.Get()),
  258. frame_attributes);
  259. if (!result) {
  260. DLOG(ERROR) << "eglStreamPostD3DTextureANGLE failed";
  261. return false;
  262. }
  263. result = eglStreamConsumerAcquireKHR(egl_display, stream_);
  264. if (!result) {
  265. DLOG(ERROR) << "eglStreamConsumerAcquireKHR failed";
  266. return false;
  267. }
  268. d3d11_device_.As(&video_device_);
  269. Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
  270. d3d11_device_->GetImmediateContext(&context);
  271. context.As(&video_context_);
  272. #if DCHECK_IS_ON()
  273. Microsoft::WRL::ComPtr<ID3D10Multithread> multithread;
  274. d3d11_device_.As(&multithread);
  275. DCHECK(multithread->GetMultithreadProtected());
  276. #endif // DCHECK_IS_ON()
  277. return true;
  278. }
  279. bool CopyingGLImageDXGI::InitializeVideoProcessor(
  280. const Microsoft::WRL::ComPtr<ID3D11VideoProcessor>& video_processor,
  281. const Microsoft::WRL::ComPtr<ID3D11VideoProcessorEnumerator>& enumerator) {
  282. output_view_.Reset();
  283. Microsoft::WRL::ComPtr<ID3D11Device> processor_device;
  284. video_processor->GetDevice(&processor_device);
  285. DCHECK_EQ(d3d11_device_.Get(), processor_device.Get());
  286. d3d11_processor_ = video_processor;
  287. enumerator_ = enumerator;
  288. D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC output_view_desc = {
  289. D3D11_VPOV_DIMENSION_TEXTURE2D};
  290. output_view_desc.Texture2D.MipSlice = 0;
  291. Microsoft::WRL::ComPtr<ID3D11VideoProcessorOutputView> output_view;
  292. HRESULT hr = video_device_->CreateVideoProcessorOutputView(
  293. decoder_copy_texture_.Get(), enumerator_.Get(), &output_view_desc,
  294. &output_view_);
  295. if (FAILED(hr)) {
  296. DLOG(ERROR) << "Failed to get output view";
  297. return false;
  298. }
  299. return true;
  300. }
  301. void CopyingGLImageDXGI::UnbindFromTexture() {
  302. copied_ = false;
  303. }
  304. bool CopyingGLImageDXGI::BindTexImage(unsigned target) {
  305. if (copied_)
  306. return true;
  307. DCHECK(video_device_);
  308. Microsoft::WRL::ComPtr<ID3D11Device> texture_device;
  309. texture_->GetDevice(&texture_device);
  310. DCHECK_EQ(d3d11_device_.Get(), texture_device.Get());
  311. D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC input_view_desc = {0};
  312. input_view_desc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D;
  313. input_view_desc.Texture2D.ArraySlice = (UINT)level_;
  314. input_view_desc.Texture2D.MipSlice = 0;
  315. Microsoft::WRL::ComPtr<ID3D11VideoProcessorInputView> input_view;
  316. HRESULT hr = video_device_->CreateVideoProcessorInputView(
  317. texture_.Get(), enumerator_.Get(), &input_view_desc, &input_view);
  318. if (FAILED(hr)) {
  319. DLOG(ERROR) << "Failed to create video processor input view.";
  320. return false;
  321. }
  322. D3D11_VIDEO_PROCESSOR_STREAM streams = {0};
  323. streams.Enable = TRUE;
  324. streams.pInputSurface = input_view.Get();
  325. hr = video_context_->VideoProcessorBlt(d3d11_processor_.Get(),
  326. output_view_.Get(), 0, 1, &streams);
  327. if (FAILED(hr)) {
  328. DLOG(ERROR) << "Failed to process video";
  329. return false;
  330. }
  331. copied_ = true;
  332. return true;
  333. }
  334. CopyingGLImageDXGI::~CopyingGLImageDXGI() {}
  335. } // namespace gl