OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/common/gpu/media/dxva_video_decode_accelerator_win.h" | 5 #include "content/common/gpu/media/dxva_video_decode_accelerator_win.h" |
6 | 6 |
7 #if !defined(OS_WIN) | 7 #if !defined(OS_WIN) |
8 #error This file should only be built on Windows. | 8 #error This file should only be built on Windows. |
9 #endif // !defined(OS_WIN) | 9 #endif // !defined(OS_WIN) |
10 | 10 |
(...skipping 23 matching lines...) Expand all Loading... |
34 #include "base/trace_event/trace_event.h" | 34 #include "base/trace_event/trace_event.h" |
35 #include "base/win/windows_version.h" | 35 #include "base/win/windows_version.h" |
36 #include "build/build_config.h" | 36 #include "build/build_config.h" |
37 #include "content/public/common/content_switches.h" | 37 #include "content/public/common/content_switches.h" |
38 #include "media/base/win/mf_initializer.h" | 38 #include "media/base/win/mf_initializer.h" |
39 #include "media/video/video_decode_accelerator.h" | 39 #include "media/video/video_decode_accelerator.h" |
40 #include "third_party/angle/include/EGL/egl.h" | 40 #include "third_party/angle/include/EGL/egl.h" |
41 #include "third_party/angle/include/EGL/eglext.h" | 41 #include "third_party/angle/include/EGL/eglext.h" |
42 #include "ui/gl/gl_bindings.h" | 42 #include "ui/gl/gl_bindings.h" |
43 #include "ui/gl/gl_context.h" | 43 #include "ui/gl/gl_context.h" |
| 44 #include "ui/gl/gl_fence.h" |
44 #include "ui/gl/gl_surface_egl.h" | 45 #include "ui/gl/gl_surface_egl.h" |
45 #include "ui/gl/gl_switches.h" | 46 #include "ui/gl/gl_switches.h" |
46 | 47 |
47 namespace { | 48 namespace { |
48 | 49 |
49 // Path is appended on to the PROGRAM_FILES base path. | 50 // Path is appended on to the PROGRAM_FILES base path. |
50 const wchar_t kVPXDecoderDLLPath[] = L"Intel\\Media SDK\\"; | 51 const wchar_t kVPXDecoderDLLPath[] = L"Intel\\Media SDK\\"; |
51 | 52 |
52 const wchar_t kVP8DecoderDLLName[] = | 53 const wchar_t kVP8DecoderDLLName[] = |
53 #if defined(ARCH_CPU_X86) | 54 #if defined(ARCH_CPU_X86) |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 log << ", HRESULT: 0x" << std::hex << result, \ | 156 log << ", HRESULT: 0x" << std::hex << result, \ |
156 error_code, ret); | 157 error_code, ret); |
157 | 158 |
158 enum { | 159 enum { |
159 // Maximum number of iterations we allow before aborting the attempt to flush | 160 // Maximum number of iterations we allow before aborting the attempt to flush |
160 // the batched queries to the driver and allow torn/corrupt frames to be | 161 // the batched queries to the driver and allow torn/corrupt frames to be |
161 // rendered. | 162 // rendered. |
162 kFlushDecoderSurfaceTimeoutMs = 1, | 163 kFlushDecoderSurfaceTimeoutMs = 1, |
163 // Maximum iterations where we try to flush the d3d device. | 164 // Maximum iterations where we try to flush the d3d device. |
164 kMaxIterationsForD3DFlush = 4, | 165 kMaxIterationsForD3DFlush = 4, |
| 166 // Maximum iterations where we try to flush the ANGLE device before reusing |
| 167 // the texture. |
| 168 kMaxIterationsForANGLEReuseFlush = 16, |
165 // We only request 5 picture buffers from the client which are used to hold | 169 // We only request 5 picture buffers from the client which are used to hold |
166 // the decoded samples. These buffers are then reused when the client tells | 170 // the decoded samples. These buffers are then reused when the client tells |
167 // us that it is done with the buffer. | 171 // us that it is done with the buffer. |
168 kNumPictureBuffers = 5, | 172 kNumPictureBuffers = 5, |
169 // The keyed mutex should always be released before the other thread | 173 // The keyed mutex should always be released before the other thread |
170 // attempts to acquire it, so AcquireSync should always return immediately. | 174 // attempts to acquire it, so AcquireSync should always return immediately. |
171 kAcquireSyncWaitMs = 0, | 175 kAcquireSyncWaitMs = 0, |
172 }; | 176 }; |
173 | 177 |
174 static IMFSample* CreateEmptySample() { | 178 static IMFSample* CreateEmptySample() { |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
353 static linked_ptr<DXVAPictureBuffer> Create( | 357 static linked_ptr<DXVAPictureBuffer> Create( |
354 const DXVAVideoDecodeAccelerator& decoder, | 358 const DXVAVideoDecodeAccelerator& decoder, |
355 const media::PictureBuffer& buffer, | 359 const media::PictureBuffer& buffer, |
356 EGLConfig egl_config); | 360 EGLConfig egl_config); |
357 ~DXVAPictureBuffer(); | 361 ~DXVAPictureBuffer(); |
358 | 362 |
359 bool InitializeTexture(const DXVAVideoDecodeAccelerator& decoder, | 363 bool InitializeTexture(const DXVAVideoDecodeAccelerator& decoder, |
360 bool use_rgb); | 364 bool use_rgb); |
361 | 365 |
362 bool ReusePictureBuffer(); | 366 bool ReusePictureBuffer(); |
| 367 void ResetReuseFence(); |
363 // Copies the output sample data to the picture buffer provided by the | 368 // Copies the output sample data to the picture buffer provided by the |
364 // client. | 369 // client. |
365 // The dest_surface parameter contains the decoded bits. | 370 // The dest_surface parameter contains the decoded bits. |
366 bool CopyOutputSampleDataToPictureBuffer( | 371 bool CopyOutputSampleDataToPictureBuffer( |
367 DXVAVideoDecodeAccelerator* decoder, | 372 DXVAVideoDecodeAccelerator* decoder, |
368 IDirect3DSurface9* dest_surface, | 373 IDirect3DSurface9* dest_surface, |
369 ID3D11Texture2D* dx11_texture, | 374 ID3D11Texture2D* dx11_texture, |
370 int input_buffer_id); | 375 int input_buffer_id); |
371 | 376 |
372 bool available() const { | 377 bool available() const { |
373 return available_; | 378 return available_; |
374 } | 379 } |
375 | 380 |
376 void set_available(bool available) { | 381 void set_available(bool available) { |
377 available_ = available; | 382 available_ = available; |
378 } | 383 } |
379 | 384 |
380 int id() const { | 385 int id() const { |
381 return picture_buffer_.id(); | 386 return picture_buffer_.id(); |
382 } | 387 } |
383 | 388 |
384 gfx::Size size() const { | 389 gfx::Size size() const { |
385 return picture_buffer_.size(); | 390 return picture_buffer_.size(); |
386 } | 391 } |
387 | 392 |
| 393 bool waiting_to_reuse() const { return waiting_to_reuse_; } |
| 394 |
| 395 gfx::GLFence* reuse_fence() { return reuse_fence_.get(); } |
| 396 |
388 // Called when the source surface |src_surface| is copied to the destination | 397 // Called when the source surface |src_surface| is copied to the destination |
389 // |dest_surface| | 398 // |dest_surface| |
390 bool CopySurfaceComplete(IDirect3DSurface9* src_surface, | 399 bool CopySurfaceComplete(IDirect3DSurface9* src_surface, |
391 IDirect3DSurface9* dest_surface); | 400 IDirect3DSurface9* dest_surface); |
392 | 401 |
393 private: | 402 private: |
394 explicit DXVAPictureBuffer(const media::PictureBuffer& buffer); | 403 explicit DXVAPictureBuffer(const media::PictureBuffer& buffer); |
395 | 404 |
396 bool available_; | 405 bool available_; |
| 406 |
| 407 // This is true if the decoder is currently waiting on the fence before |
| 408 // reusing the buffer. |
| 409 bool waiting_to_reuse_; |
397 media::PictureBuffer picture_buffer_; | 410 media::PictureBuffer picture_buffer_; |
398 EGLSurface decoding_surface_; | 411 EGLSurface decoding_surface_; |
| 412 scoped_ptr<gfx::GLFence> reuse_fence_; |
399 | 413 |
400 HANDLE texture_share_handle_; | 414 HANDLE texture_share_handle_; |
401 base::win::ScopedComPtr<IDirect3DTexture9> decoding_texture_; | 415 base::win::ScopedComPtr<IDirect3DTexture9> decoding_texture_; |
402 base::win::ScopedComPtr<ID3D11Texture2D> dx11_decoding_texture_; | 416 base::win::ScopedComPtr<ID3D11Texture2D> dx11_decoding_texture_; |
403 | 417 |
404 base::win::ScopedComPtr<IDXGIKeyedMutex> egl_keyed_mutex_; | 418 base::win::ScopedComPtr<IDXGIKeyedMutex> egl_keyed_mutex_; |
405 base::win::ScopedComPtr<IDXGIKeyedMutex> dx11_keyed_mutex_; | 419 base::win::ScopedComPtr<IDXGIKeyedMutex> dx11_keyed_mutex_; |
406 | 420 |
407 // This is the last value that was used to release the keyed mutex. | 421 // This is the last value that was used to release the keyed mutex. |
408 uint64_t keyed_mutex_value_; | 422 uint64_t keyed_mutex_value_; |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 RETURN_ON_HR_FAILURE(hr, "Failed to create texture", false); | 530 RETURN_ON_HR_FAILURE(hr, "Failed to create texture", false); |
517 RETURN_ON_FAILURE(texture_share_handle_, "Failed to query shared handle", | 531 RETURN_ON_FAILURE(texture_share_handle_, "Failed to query shared handle", |
518 false); | 532 false); |
519 } | 533 } |
520 return true; | 534 return true; |
521 } | 535 } |
522 | 536 |
523 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::DXVAPictureBuffer( | 537 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::DXVAPictureBuffer( |
524 const media::PictureBuffer& buffer) | 538 const media::PictureBuffer& buffer) |
525 : available_(true), | 539 : available_(true), |
| 540 waiting_to_reuse_(false), |
526 picture_buffer_(buffer), | 541 picture_buffer_(buffer), |
527 decoding_surface_(NULL), | 542 decoding_surface_(NULL), |
528 texture_share_handle_(nullptr), | 543 texture_share_handle_(nullptr), |
529 keyed_mutex_value_(0), | 544 keyed_mutex_value_(0), |
530 use_rgb_(true) {} | 545 use_rgb_(true) {} |
531 | 546 |
532 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::~DXVAPictureBuffer() { | 547 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::~DXVAPictureBuffer() { |
533 if (decoding_surface_) { | 548 if (decoding_surface_) { |
534 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); | 549 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); |
535 | 550 |
(...skipping 12 matching lines...) Expand all Loading... |
548 bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() { | 563 bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() { |
549 DCHECK(decoding_surface_); | 564 DCHECK(decoding_surface_); |
550 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); | 565 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); |
551 eglReleaseTexImage( | 566 eglReleaseTexImage( |
552 egl_display, | 567 egl_display, |
553 decoding_surface_, | 568 decoding_surface_, |
554 EGL_BACK_BUFFER); | 569 EGL_BACK_BUFFER); |
555 decoder_surface_.Release(); | 570 decoder_surface_.Release(); |
556 target_surface_.Release(); | 571 target_surface_.Release(); |
557 decoder_dx11_texture_.Release(); | 572 decoder_dx11_texture_.Release(); |
| 573 waiting_to_reuse_ = false; |
558 set_available(true); | 574 set_available(true); |
559 if (egl_keyed_mutex_) { | 575 if (egl_keyed_mutex_) { |
560 HRESULT hr = egl_keyed_mutex_->ReleaseSync(++keyed_mutex_value_); | 576 HRESULT hr = egl_keyed_mutex_->ReleaseSync(++keyed_mutex_value_); |
561 RETURN_ON_FAILURE(hr == S_OK, "Could not release sync mutex", false); | 577 RETURN_ON_FAILURE(hr == S_OK, "Could not release sync mutex", false); |
562 } | 578 } |
563 return true; | 579 return true; |
564 } | 580 } |
565 | 581 |
| 582 void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ResetReuseFence() { |
| 583 if (!reuse_fence_ || !reuse_fence_->ResetSupported()) |
| 584 reuse_fence_.reset(gfx::GLFence::Create()); |
| 585 else |
| 586 reuse_fence_->ResetState(); |
| 587 waiting_to_reuse_ = true; |
| 588 } |
| 589 |
566 bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer:: | 590 bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer:: |
567 CopyOutputSampleDataToPictureBuffer( | 591 CopyOutputSampleDataToPictureBuffer( |
568 DXVAVideoDecodeAccelerator* decoder, | 592 DXVAVideoDecodeAccelerator* decoder, |
569 IDirect3DSurface9* dest_surface, | 593 IDirect3DSurface9* dest_surface, |
570 ID3D11Texture2D* dx11_texture, | 594 ID3D11Texture2D* dx11_texture, |
571 int input_buffer_id) { | 595 int input_buffer_id) { |
572 DCHECK(dest_surface || dx11_texture); | 596 DCHECK(dest_surface || dx11_texture); |
573 if (dx11_texture) { | 597 if (dx11_texture) { |
574 // Grab a reference on the decoder texture. This reference will be released | 598 // Grab a reference on the decoder texture. This reference will be released |
575 // when we receive a notification that the copy was completed or when the | 599 // when we receive a notification that the copy was completed or when the |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
747 create_dxgi_device_manager_ = reinterpret_cast<CreateDXGIDeviceManager>( | 771 create_dxgi_device_manager_ = reinterpret_cast<CreateDXGIDeviceManager>( |
748 ::GetProcAddress(dxgi_manager_dll, "MFCreateDXGIDeviceManager")); | 772 ::GetProcAddress(dxgi_manager_dll, "MFCreateDXGIDeviceManager")); |
749 } | 773 } |
750 | 774 |
751 RETURN_AND_NOTIFY_ON_FAILURE( | 775 RETURN_AND_NOTIFY_ON_FAILURE( |
752 gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle, | 776 gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle, |
753 "EGL_ANGLE_surface_d3d_texture_2d_share_handle unavailable", | 777 "EGL_ANGLE_surface_d3d_texture_2d_share_handle unavailable", |
754 PLATFORM_FAILURE, | 778 PLATFORM_FAILURE, |
755 false); | 779 false); |
756 | 780 |
| 781 RETURN_AND_NOTIFY_ON_FAILURE(gfx::GLFence::IsSupported(), |
| 782 "GL fences are unsupported", PLATFORM_FAILURE, |
| 783 false); |
| 784 |
757 State state = GetState(); | 785 State state = GetState(); |
758 RETURN_AND_NOTIFY_ON_FAILURE((state == kUninitialized), | 786 RETURN_AND_NOTIFY_ON_FAILURE((state == kUninitialized), |
759 "Initialize: invalid state: " << state, ILLEGAL_STATE, false); | 787 "Initialize: invalid state: " << state, ILLEGAL_STATE, false); |
760 | 788 |
761 media::InitializeMediaFoundation(); | 789 media::InitializeMediaFoundation(); |
762 | 790 |
763 RETURN_AND_NOTIFY_ON_FAILURE(InitDecoder(config.profile), | 791 RETURN_AND_NOTIFY_ON_FAILURE(InitDecoder(config.profile), |
764 "Failed to initialize decoder", PLATFORM_FAILURE, false); | 792 "Failed to initialize decoder", PLATFORM_FAILURE, false); |
765 | 793 |
766 RETURN_AND_NOTIFY_ON_FAILURE(GetStreamsInfoAndBufferReqs(), | 794 RETURN_AND_NOTIFY_ON_FAILURE(GetStreamsInfoAndBufferReqs(), |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1018 it = stale_output_picture_buffers_.find(picture_buffer_id); | 1046 it = stale_output_picture_buffers_.find(picture_buffer_id); |
1019 RETURN_AND_NOTIFY_ON_FAILURE(it != stale_output_picture_buffers_.end(), | 1047 RETURN_AND_NOTIFY_ON_FAILURE(it != stale_output_picture_buffers_.end(), |
1020 "Invalid picture id: " << picture_buffer_id, INVALID_ARGUMENT,); | 1048 "Invalid picture id: " << picture_buffer_id, INVALID_ARGUMENT,); |
1021 main_thread_task_runner_->PostTask( | 1049 main_thread_task_runner_->PostTask( |
1022 FROM_HERE, | 1050 FROM_HERE, |
1023 base::Bind(&DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer, | 1051 base::Bind(&DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer, |
1024 weak_this_factory_.GetWeakPtr(), picture_buffer_id)); | 1052 weak_this_factory_.GetWeakPtr(), picture_buffer_id)); |
1025 return; | 1053 return; |
1026 } | 1054 } |
1027 | 1055 |
1028 RETURN_AND_NOTIFY_ON_FAILURE(it->second->ReusePictureBuffer(), | 1056 if (it->second->available() || it->second->waiting_to_reuse()) |
| 1057 return; |
| 1058 |
| 1059 if (use_keyed_mutex_ || using_angle_device_) { |
| 1060 RETURN_AND_NOTIFY_ON_FAILURE(it->second->ReusePictureBuffer(), |
| 1061 "Failed to reuse picture buffer", |
| 1062 PLATFORM_FAILURE, ); |
| 1063 |
| 1064 ProcessPendingSamples(); |
| 1065 if (pending_flush_) { |
| 1066 decoder_thread_task_runner_->PostTask( |
| 1067 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, |
| 1068 base::Unretained(this))); |
| 1069 } |
| 1070 } else { |
| 1071 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), |
| 1072 "Failed to make context current", |
| 1073 PLATFORM_FAILURE, ); |
| 1074 it->second->ResetReuseFence(); |
| 1075 |
| 1076 WaitForOutputBuffer(picture_buffer_id, 0); |
| 1077 } |
| 1078 } |
| 1079 |
| 1080 void DXVAVideoDecodeAccelerator::WaitForOutputBuffer(int32_t picture_buffer_id, |
| 1081 int count) { |
| 1082 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
| 1083 OutputBuffers::iterator it = output_picture_buffers_.find(picture_buffer_id); |
| 1084 if (it == output_picture_buffers_.end()) |
| 1085 return; |
| 1086 |
| 1087 DXVAPictureBuffer* picture_buffer = it->second.get(); |
| 1088 |
| 1089 DCHECK(!picture_buffer->available()); |
| 1090 DCHECK(picture_buffer->waiting_to_reuse()); |
| 1091 |
| 1092 gfx::GLFence* fence = picture_buffer->reuse_fence(); |
| 1093 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), |
| 1094 "Failed to make context current", |
| 1095 PLATFORM_FAILURE, ); |
| 1096 if (count <= kMaxIterationsForANGLEReuseFlush && !fence->HasCompleted()) { |
| 1097 main_thread_task_runner_->PostDelayedTask( |
| 1098 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::WaitForOutputBuffer, |
| 1099 weak_this_factory_.GetWeakPtr(), |
| 1100 picture_buffer_id, count + 1), |
| 1101 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); |
| 1102 return; |
| 1103 } |
| 1104 RETURN_AND_NOTIFY_ON_FAILURE(picture_buffer->ReusePictureBuffer(), |
1029 "Failed to reuse picture buffer", | 1105 "Failed to reuse picture buffer", |
1030 PLATFORM_FAILURE, ); | 1106 PLATFORM_FAILURE, ); |
1031 | 1107 |
1032 ProcessPendingSamples(); | 1108 ProcessPendingSamples(); |
1033 if (pending_flush_) { | 1109 if (pending_flush_) { |
1034 decoder_thread_task_runner_->PostTask( | 1110 decoder_thread_task_runner_->PostTask( |
1035 FROM_HERE, | 1111 FROM_HERE, |
1036 base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, | 1112 base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, |
1037 base::Unretained(this))); | 1113 base::Unretained(this))); |
1038 } | 1114 } |
(...skipping 1342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2381 } | 2457 } |
2382 RETURN_ON_HR_FAILURE(hr, "Failed to set output type", false); | 2458 RETURN_ON_HR_FAILURE(hr, "Failed to set output type", false); |
2383 return true; | 2459 return true; |
2384 } | 2460 } |
2385 media_type.Release(); | 2461 media_type.Release(); |
2386 } | 2462 } |
2387 return false; | 2463 return false; |
2388 } | 2464 } |
2389 | 2465 |
2390 } // namespace content | 2466 } // namespace content |
OLD | NEW |