PageRenderTime 25ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/ui/gl/gl_image_dxgi.cc

https://github.com/chromium/chromium
C++ | 406 lines | 332 code | 66 blank | 8 comment | 49 complexity | b9406843771404fcc0c838103f877f8a MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause
  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 =
  57. gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
  58. EGLBoolean result =
  59. eglChooseConfig(display, attrib_list, nullptr, 0, &num_config);
  60. if (result != EGL_TRUE)
  61. return nullptr;
  62. std::vector<EGLConfig> all_configs(num_config);
  63. result =
  64. eglChooseConfig(gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(),
  65. attrib_list, all_configs.data(), num_config, &num_config);
  66. if (result != EGL_TRUE)
  67. return nullptr;
  68. for (EGLConfig config : all_configs) {
  69. EGLint bits;
  70. if (!eglGetConfigAttrib(display, config, EGL_RED_SIZE, &bits) ||
  71. bits != 8) {
  72. continue;
  73. }
  74. if (!eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &bits) ||
  75. bits != 8) {
  76. continue;
  77. }
  78. if (!eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &bits) ||
  79. bits != 8) {
  80. continue;
  81. }
  82. if (HasAlpha(format) &&
  83. (!eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &bits) ||
  84. bits != 8)) {
  85. continue;
  86. }
  87. return config;
  88. }
  89. return nullptr;
  90. }
  91. EGLSurface CreatePbuffer(const Microsoft::WRL::ComPtr<ID3D11Texture2D>& texture,
  92. gfx::BufferFormat format,
  93. EGLConfig config,
  94. unsigned target) {
  95. DCHECK(SupportedBindFormat(format));
  96. D3D11_TEXTURE2D_DESC desc;
  97. texture->GetDesc(&desc);
  98. EGLint width = desc.Width;
  99. EGLint height = desc.Height;
  100. EGLint pBufferAttributes[] = {
  101. EGL_WIDTH,
  102. width,
  103. EGL_HEIGHT,
  104. height,
  105. EGL_TEXTURE_TARGET,
  106. EGL_TEXTURE_2D,
  107. EGL_TEXTURE_FORMAT,
  108. HasAlpha(format) ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB,
  109. EGL_NONE};
  110. return eglCreatePbufferFromClientBuffer(
  111. gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(),
  112. EGL_D3D_TEXTURE_ANGLE, texture.Get(), config, pBufferAttributes);
  113. }
  114. } // namespace
  115. GLImageDXGI::GLImageDXGI(const gfx::Size& size, EGLStreamKHR stream)
  116. : size_(size), stream_(stream) {}
  117. // static
  118. GLImageDXGI* GLImageDXGI::FromGLImage(GLImage* image) {
  119. if (!image || image->GetType() != Type::DXGI_IMAGE)
  120. return nullptr;
  121. return static_cast<GLImageDXGI*>(image);
  122. }
  123. GLImageDXGI::BindOrCopy GLImageDXGI::ShouldBindOrCopy() {
  124. return BIND;
  125. }
  126. bool GLImageDXGI::BindTexImage(unsigned target) {
  127. if (!handle_.Get())
  128. return true;
  129. DCHECK(texture_);
  130. DCHECK(keyed_mutex_);
  131. if (!SupportedBindFormat(buffer_format_))
  132. return false;
  133. // Lazy-initialize surface_, as it is only used for binding.
  134. if (surface_ == EGL_NO_SURFACE) {
  135. EGLConfig config = ChooseCompatibleConfig(buffer_format_);
  136. if (!config)
  137. return false;
  138. surface_ = CreatePbuffer(texture_, buffer_format_, config, target);
  139. if (surface_ == EGL_NO_SURFACE)
  140. return false;
  141. }
  142. // We don't wait, just return immediately.
  143. HRESULT hrWait = keyed_mutex_->AcquireSync(KEY_BIND, 0);
  144. if (hrWait == WAIT_TIMEOUT || hrWait == WAIT_ABANDONED || FAILED(hrWait)) {
  145. NOTREACHED();
  146. return false;
  147. }
  148. return eglBindTexImage(
  149. gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(),
  150. surface_, EGL_BACK_BUFFER) == EGL_TRUE;
  151. }
  152. bool GLImageDXGI::CopyTexImage(unsigned target) {
  153. NOTREACHED();
  154. return false;
  155. }
  156. bool GLImageDXGI::CopyTexSubImage(unsigned target,
  157. const gfx::Point& offset,
  158. const gfx::Rect& rect) {
  159. return false;
  160. }
  161. void GLImageDXGI::Flush() {}
  162. unsigned GLImageDXGI::GetInternalFormat() {
  163. if (!handle_.Get())
  164. return GL_BGRA_EXT;
  165. else
  166. return HasAlpha(buffer_format_) ? GL_RGBA : GL_RGB;
  167. }
  168. unsigned GLImageDXGI::GetDataType() {
  169. return GL_UNSIGNED_BYTE;
  170. }
  171. gfx::Size GLImageDXGI::GetSize() {
  172. return size_;
  173. }
  174. GLImage::Type GLImageDXGI::GetType() const {
  175. return Type::DXGI_IMAGE;
  176. }
  177. void GLImageDXGI::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
  178. uint64_t process_tracing_id,
  179. const std::string& dump_name) {}
  180. void GLImageDXGI::ReleaseTexImage(unsigned target) {
  181. if (!handle_.Get())
  182. return;
  183. DCHECK(texture_);
  184. DCHECK(keyed_mutex_);
  185. keyed_mutex_->ReleaseSync(KEY_RELEASE);
  186. eglReleaseTexImage(gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(),
  187. surface_, EGL_BACK_BUFFER);
  188. }
  189. bool GLImageDXGI::InitializeHandle(base::win::ScopedHandle handle,
  190. uint32_t level,
  191. gfx::BufferFormat format) {
  192. level_ = level;
  193. buffer_format_ = format;
  194. Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
  195. QueryD3D11DeviceObjectFromANGLE();
  196. if (!d3d11_device)
  197. return false;
  198. Microsoft::WRL::ComPtr<ID3D11Device1> d3d11_device1;
  199. if (FAILED(d3d11_device.As(&d3d11_device1)))
  200. return false;
  201. if (FAILED(d3d11_device1->OpenSharedResource1(handle.Get(),
  202. IID_PPV_ARGS(&texture_)))) {
  203. return false;
  204. }
  205. D3D11_TEXTURE2D_DESC desc;
  206. texture_->GetDesc(&desc);
  207. if (desc.ArraySize <= level_)
  208. return false;
  209. if (FAILED(texture_.As(&keyed_mutex_)))
  210. return false;
  211. handle_ = std::move(handle);
  212. return true;
  213. }
  214. void GLImageDXGI::SetTexture(
  215. const Microsoft::WRL::ComPtr<ID3D11Texture2D>& texture,
  216. size_t level) {
  217. texture_ = texture;
  218. level_ = level;
  219. }
  220. GLImageDXGI::~GLImageDXGI() {
  221. if (handle_.Get()) {
  222. if (surface_ != EGL_NO_SURFACE) {
  223. eglDestroySurface(
  224. gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay(), surface_);
  225. }
  226. } else if (stream_) {
  227. EGLDisplay egl_display =
  228. gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
  229. eglDestroyStreamKHR(egl_display, stream_);
  230. }
  231. }
  232. CopyingGLImageDXGI::CopyingGLImageDXGI(
  233. const Microsoft::WRL::ComPtr<ID3D11Device>& d3d11_device,
  234. const gfx::Size& size,
  235. EGLStreamKHR stream)
  236. : GLImageDXGI(size, stream), d3d11_device_(d3d11_device) {}
  237. bool CopyingGLImageDXGI::Initialize() {
  238. D3D11_TEXTURE2D_DESC desc;
  239. desc.Width = size_.width();
  240. desc.Height = size_.height();
  241. desc.MipLevels = 1;
  242. desc.ArraySize = 1;
  243. desc.Format = DXGI_FORMAT_NV12;
  244. desc.SampleDesc.Count = 1;
  245. desc.SampleDesc.Quality = 0;
  246. desc.Usage = D3D11_USAGE_DEFAULT;
  247. desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
  248. desc.CPUAccessFlags = 0;
  249. desc.MiscFlags = 0;
  250. HRESULT hr =
  251. d3d11_device_->CreateTexture2D(&desc, nullptr, &decoder_copy_texture_);
  252. if (FAILED(hr)) {
  253. DLOG(ERROR) << "CreateTexture2D failed: " << std::hex << hr;
  254. return false;
  255. }
  256. EGLDisplay egl_display =
  257. gl::GLSurfaceEGL::GetGLDisplayEGL()->GetHardwareDisplay();
  258. EGLAttrib frame_attributes[] = {
  259. EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 0, EGL_NONE,
  260. };
  261. EGLBoolean result = eglStreamPostD3DTextureANGLE(
  262. egl_display, stream_, static_cast<void*>(decoder_copy_texture_.Get()),
  263. frame_attributes);
  264. if (!result) {
  265. DLOG(ERROR) << "eglStreamPostD3DTextureANGLE failed";
  266. return false;
  267. }
  268. result = eglStreamConsumerAcquireKHR(egl_display, stream_);
  269. if (!result) {
  270. DLOG(ERROR) << "eglStreamConsumerAcquireKHR failed";
  271. return false;
  272. }
  273. d3d11_device_.As(&video_device_);
  274. Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
  275. d3d11_device_->GetImmediateContext(&context);
  276. context.As(&video_context_);
  277. #if DCHECK_IS_ON()
  278. Microsoft::WRL::ComPtr<ID3D10Multithread> multithread;
  279. d3d11_device_.As(&multithread);
  280. DCHECK(multithread->GetMultithreadProtected());
  281. #endif // DCHECK_IS_ON()
  282. return true;
  283. }
  284. bool CopyingGLImageDXGI::InitializeVideoProcessor(
  285. const Microsoft::WRL::ComPtr<ID3D11VideoProcessor>& video_processor,
  286. const Microsoft::WRL::ComPtr<ID3D11VideoProcessorEnumerator>& enumerator) {
  287. output_view_.Reset();
  288. Microsoft::WRL::ComPtr<ID3D11Device> processor_device;
  289. video_processor->GetDevice(&processor_device);
  290. DCHECK_EQ(d3d11_device_.Get(), processor_device.Get());
  291. d3d11_processor_ = video_processor;
  292. enumerator_ = enumerator;
  293. D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC output_view_desc = {
  294. D3D11_VPOV_DIMENSION_TEXTURE2D};
  295. output_view_desc.Texture2D.MipSlice = 0;
  296. Microsoft::WRL::ComPtr<ID3D11VideoProcessorOutputView> output_view;
  297. HRESULT hr = video_device_->CreateVideoProcessorOutputView(
  298. decoder_copy_texture_.Get(), enumerator_.Get(), &output_view_desc,
  299. &output_view_);
  300. if (FAILED(hr)) {
  301. DLOG(ERROR) << "Failed to get output view";
  302. return false;
  303. }
  304. return true;
  305. }
  306. void CopyingGLImageDXGI::UnbindFromTexture() {
  307. copied_ = false;
  308. }
  309. bool CopyingGLImageDXGI::BindTexImage(unsigned target) {
  310. if (copied_)
  311. return true;
  312. DCHECK(video_device_);
  313. Microsoft::WRL::ComPtr<ID3D11Device> texture_device;
  314. texture_->GetDevice(&texture_device);
  315. DCHECK_EQ(d3d11_device_.Get(), texture_device.Get());
  316. D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC input_view_desc = {0};
  317. input_view_desc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D;
  318. input_view_desc.Texture2D.ArraySlice = (UINT)level_;
  319. input_view_desc.Texture2D.MipSlice = 0;
  320. Microsoft::WRL::ComPtr<ID3D11VideoProcessorInputView> input_view;
  321. HRESULT hr = video_device_->CreateVideoProcessorInputView(
  322. texture_.Get(), enumerator_.Get(), &input_view_desc, &input_view);
  323. if (FAILED(hr)) {
  324. DLOG(ERROR) << "Failed to create video processor input view.";
  325. return false;
  326. }
  327. D3D11_VIDEO_PROCESSOR_STREAM streams = {0};
  328. streams.Enable = TRUE;
  329. streams.pInputSurface = input_view.Get();
  330. hr = video_context_->VideoProcessorBlt(d3d11_processor_.Get(),
  331. output_view_.Get(), 0, 1, &streams);
  332. if (FAILED(hr)) {
  333. DLOG(ERROR) << "Failed to process video";
  334. return false;
  335. }
  336. copied_ = true;
  337. return true;
  338. }
  339. CopyingGLImageDXGI::~CopyingGLImageDXGI() {}
  340. } // namespace gl