| 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.h" | 5 #include "content/common/gpu/media/dxva_video_decode_accelerator.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 603 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 614 pictures_requested_(false), | 614 pictures_requested_(false), |
| 615 inputs_before_decode_(0), | 615 inputs_before_decode_(0), |
| 616 sent_drain_message_(false), | 616 sent_drain_message_(false), |
| 617 make_context_current_(make_context_current), | 617 make_context_current_(make_context_current), |
| 618 codec_(media::kUnknownVideoCodec), | 618 codec_(media::kUnknownVideoCodec), |
| 619 decoder_thread_("DXVAVideoDecoderThread"), | 619 decoder_thread_("DXVAVideoDecoderThread"), |
| 620 pending_flush_(false), | 620 pending_flush_(false), |
| 621 use_dx11_(false), | 621 use_dx11_(false), |
| 622 dx11_video_format_converter_media_type_needs_init_(true), | 622 dx11_video_format_converter_media_type_needs_init_(true), |
| 623 gl_context_(gl_context), | 623 gl_context_(gl_context), |
| 624 using_angle_device_(false), |
| 624 weak_this_factory_(this) { | 625 weak_this_factory_(this) { |
| 625 weak_ptr_ = weak_this_factory_.GetWeakPtr(); | 626 weak_ptr_ = weak_this_factory_.GetWeakPtr(); |
| 626 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); | 627 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); |
| 627 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); | 628 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); |
| 628 } | 629 } |
| 629 | 630 |
| 630 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { | 631 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { |
| 631 client_ = NULL; | 632 client_ = NULL; |
| 632 } | 633 } |
| 633 | 634 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 718 } | 719 } |
| 719 | 720 |
| 720 bool DXVAVideoDecodeAccelerator::CreateD3DDevManager() { | 721 bool DXVAVideoDecodeAccelerator::CreateD3DDevManager() { |
| 721 TRACE_EVENT0("gpu", "DXVAVideoDecodeAccelerator_CreateD3DDevManager"); | 722 TRACE_EVENT0("gpu", "DXVAVideoDecodeAccelerator_CreateD3DDevManager"); |
| 722 | 723 |
| 723 HRESULT hr = E_FAIL; | 724 HRESULT hr = E_FAIL; |
| 724 | 725 |
| 725 hr = Direct3DCreate9Ex(D3D_SDK_VERSION, d3d9_.Receive()); | 726 hr = Direct3DCreate9Ex(D3D_SDK_VERSION, d3d9_.Receive()); |
| 726 RETURN_ON_HR_FAILURE(hr, "Direct3DCreate9Ex failed", false); | 727 RETURN_ON_HR_FAILURE(hr, "Direct3DCreate9Ex failed", false); |
| 727 | 728 |
| 728 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 729 base::win::ScopedComPtr<IDirect3DDevice9> angle_device = |
| 729 switches::kDisableD3D11)) { | 730 QueryDeviceObjectFromANGLE<IDirect3DDevice9>(EGL_D3D9_DEVICE_ANGLE); |
| 730 base::win::ScopedComPtr<IDirect3DDevice9> angle_device = | 731 if (angle_device.get()) |
| 731 QueryDeviceObjectFromANGLE<IDirect3DDevice9>(EGL_D3D9_DEVICE_ANGLE); | 732 using_angle_device_ = true; |
| 732 RETURN_ON_FAILURE( | |
| 733 angle_device.get(), | |
| 734 "Failed to query D3D9 device object from ANGLE", | |
| 735 false); | |
| 736 | 733 |
| 734 if (using_angle_device_) { |
| 737 hr = d3d9_device_ex_.QueryFrom(angle_device.get()); | 735 hr = d3d9_device_ex_.QueryFrom(angle_device.get()); |
| 738 RETURN_ON_HR_FAILURE(hr, | 736 RETURN_ON_HR_FAILURE(hr, |
| 739 "QueryInterface for IDirect3DDevice9Ex from angle device failed", | 737 "QueryInterface for IDirect3DDevice9Ex from angle device failed", |
| 740 false); | 738 false); |
| 741 } else { | 739 } else { |
| 742 D3DPRESENT_PARAMETERS present_params = {0}; | 740 D3DPRESENT_PARAMETERS present_params = {0}; |
| 743 present_params.BackBufferWidth = 1; | 741 present_params.BackBufferWidth = 1; |
| 744 present_params.BackBufferHeight = 1; | 742 present_params.BackBufferHeight = 1; |
| 745 present_params.BackBufferFormat = D3DFMT_UNKNOWN; | 743 present_params.BackBufferFormat = D3DFMT_UNKNOWN; |
| 746 present_params.BackBufferCount = 1; | 744 present_params.BackBufferCount = 1; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 786 d3d11_device_manager_.Receive()); | 784 d3d11_device_manager_.Receive()); |
| 787 RETURN_ON_HR_FAILURE(hr, "MFCreateDXGIDeviceManager failed", false); | 785 RETURN_ON_HR_FAILURE(hr, "MFCreateDXGIDeviceManager failed", false); |
| 788 | 786 |
| 789 base::win::ScopedComPtr<ID3D11Device> angle_device = | 787 base::win::ScopedComPtr<ID3D11Device> angle_device = |
| 790 QueryDeviceObjectFromANGLE<ID3D11Device>(EGL_D3D11_DEVICE_ANGLE); | 788 QueryDeviceObjectFromANGLE<ID3D11Device>(EGL_D3D11_DEVICE_ANGLE); |
| 791 RETURN_ON_FAILURE( | 789 RETURN_ON_FAILURE( |
| 792 angle_device.get(), | 790 angle_device.get(), |
| 793 "Failed to query DX11 device object from ANGLE", | 791 "Failed to query DX11 device object from ANGLE", |
| 794 false); | 792 false); |
| 795 | 793 |
| 794 using_angle_device_ = true; |
| 796 d3d11_device_ = angle_device; | 795 d3d11_device_ = angle_device; |
| 797 d3d11_device_->GetImmediateContext(d3d11_device_context_.Receive()); | 796 d3d11_device_->GetImmediateContext(d3d11_device_context_.Receive()); |
| 798 RETURN_ON_FAILURE( | 797 RETURN_ON_FAILURE( |
| 799 d3d11_device_context_.get(), | 798 d3d11_device_context_.get(), |
| 800 "Failed to query DX11 device context from ANGLE device", | 799 "Failed to query DX11 device context from ANGLE device", |
| 801 false); | 800 false); |
| 802 | 801 |
| 803 // Enable multithreaded mode on the context. This ensures that accesses to | 802 // Enable multithreaded mode on the context. This ensures that accesses to |
| 804 // context are synchronized across threads. We have multiple threads | 803 // context are synchronized across threads. We have multiple threads |
| 805 // accessing the context, the media foundation decoder threads and the | 804 // accessing the context, the media foundation decoder threads and the |
| 806 // decoder thread via the video format conversion transform. | 805 // decoder thread via the video format conversion transform. |
| 807 base::win::ScopedComPtr<ID3D10Multithread> multi_threaded; | 806 hr = multi_threaded_.QueryFrom(d3d11_device_context_.get()); |
| 808 hr = multi_threaded.QueryFrom(d3d11_device_context_.get()); | |
| 809 RETURN_ON_HR_FAILURE(hr, "Failed to query ID3D10Multithread", false); | 807 RETURN_ON_HR_FAILURE(hr, "Failed to query ID3D10Multithread", false); |
| 810 multi_threaded->SetMultithreadProtected(TRUE); | 808 multi_threaded_->SetMultithreadProtected(TRUE); |
| 811 | 809 |
| 812 hr = d3d11_device_manager_->ResetDevice(d3d11_device_.get(), | 810 hr = d3d11_device_manager_->ResetDevice(d3d11_device_.get(), |
| 813 dx11_dev_manager_reset_token_); | 811 dx11_dev_manager_reset_token_); |
| 814 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); | 812 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); |
| 815 | 813 |
| 816 D3D11_QUERY_DESC query_desc; | 814 D3D11_QUERY_DESC query_desc; |
| 817 query_desc.Query = D3D11_QUERY_EVENT; | 815 query_desc.Query = D3D11_QUERY_EVENT; |
| 818 query_desc.MiscFlags = 0; | 816 query_desc.MiscFlags = 0; |
| 819 hr = d3d11_device_->CreateQuery( | 817 hr = d3d11_device_->CreateQuery( |
| 820 &query_desc, | 818 &query_desc, |
| (...skipping 670 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1491 client_ = NULL; | 1489 client_ = NULL; |
| 1492 | 1490 |
| 1493 if (GetState() != kUninitialized) { | 1491 if (GetState() != kUninitialized) { |
| 1494 Invalidate(); | 1492 Invalidate(); |
| 1495 } | 1493 } |
| 1496 } | 1494 } |
| 1497 | 1495 |
| 1498 void DXVAVideoDecodeAccelerator::Invalidate() { | 1496 void DXVAVideoDecodeAccelerator::Invalidate() { |
| 1499 if (GetState() == kUninitialized) | 1497 if (GetState() == kUninitialized) |
| 1500 return; | 1498 return; |
| 1499 |
| 1501 decoder_thread_.Stop(); | 1500 decoder_thread_.Stop(); |
| 1502 weak_this_factory_.InvalidateWeakPtrs(); | 1501 weak_this_factory_.InvalidateWeakPtrs(); |
| 1503 output_picture_buffers_.clear(); | 1502 output_picture_buffers_.clear(); |
| 1504 stale_output_picture_buffers_.clear(); | 1503 stale_output_picture_buffers_.clear(); |
| 1505 pending_output_samples_.clear(); | 1504 pending_output_samples_.clear(); |
| 1506 pending_input_buffers_.clear(); | 1505 pending_input_buffers_.clear(); |
| 1507 decoder_.Release(); | 1506 decoder_.Release(); |
| 1508 | 1507 |
| 1509 if (use_dx11_) { | 1508 if (use_dx11_) { |
| 1510 if (video_format_converter_mft_.get()) { | 1509 if (video_format_converter_mft_.get()) { |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1847 | 1846 |
| 1848 HRESULT hr = d3d9_device_ex_->StretchRect(src_surface, NULL, dest_surface, | 1847 HRESULT hr = d3d9_device_ex_->StretchRect(src_surface, NULL, dest_surface, |
| 1849 NULL, D3DTEXF_NONE); | 1848 NULL, D3DTEXF_NONE); |
| 1850 RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed",); | 1849 RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed",); |
| 1851 | 1850 |
| 1852 // Ideally, this should be done immediately before the draw call that uses | 1851 // Ideally, this should be done immediately before the draw call that uses |
| 1853 // the texture. Flush it once here though. | 1852 // the texture. Flush it once here though. |
| 1854 hr = query_->Issue(D3DISSUE_END); | 1853 hr = query_->Issue(D3DISSUE_END); |
| 1855 RETURN_ON_HR_FAILURE(hr, "Failed to issue END",); | 1854 RETURN_ON_HR_FAILURE(hr, "Failed to issue END",); |
| 1856 | 1855 |
| 1856 // If we are sharing the ANGLE device we don't need to wait for the Flush to |
| 1857 // complete. |
| 1858 if (using_angle_device_) { |
| 1859 main_thread_task_runner_->PostTask( |
| 1860 FROM_HERE, |
| 1861 base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, |
| 1862 weak_this_factory_.GetWeakPtr(), |
| 1863 src_surface, |
| 1864 dest_surface, |
| 1865 picture_buffer_id, |
| 1866 input_buffer_id)); |
| 1867 return; |
| 1868 } |
| 1869 |
| 1857 // Flush the decoder device to ensure that the decoded frame is copied to the | 1870 // Flush the decoder device to ensure that the decoded frame is copied to the |
| 1858 // target surface. | 1871 // target surface. |
| 1859 decoder_thread_task_runner_->PostDelayedTask( | 1872 decoder_thread_task_runner_->PostDelayedTask( |
| 1860 FROM_HERE, | 1873 FROM_HERE, |
| 1861 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, | 1874 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, |
| 1862 base::Unretained(this), 0, src_surface, dest_surface, | 1875 base::Unretained(this), 0, src_surface, dest_surface, |
| 1863 picture_buffer_id, input_buffer_id), | 1876 picture_buffer_id, input_buffer_id), |
| 1864 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); | 1877 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); |
| 1865 } | 1878 } |
| 1866 | 1879 |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2004 // TODO(ananta) | 2017 // TODO(ananta) |
| 2005 // Remove this CHECK when the change to use DX11 for H/W decoding | 2018 // Remove this CHECK when the change to use DX11 for H/W decoding |
| 2006 // stablizes. | 2019 // stablizes. |
| 2007 CHECK(false); | 2020 CHECK(false); |
| 2008 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2021 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
| 2009 "Failed to create output sample.", PLATFORM_FAILURE,); | 2022 "Failed to create output sample.", PLATFORM_FAILURE,); |
| 2010 } | 2023 } |
| 2011 | 2024 |
| 2012 output_sample->AddBuffer(output_buffer.get()); | 2025 output_sample->AddBuffer(output_buffer.get()); |
| 2013 | 2026 |
| 2027 // Lock the device here as we are accessing the destination texture created |
| 2028 // on the main thread. |
| 2029 multi_threaded_->Enter(); |
| 2030 |
| 2014 DWORD status = 0; | 2031 DWORD status = 0; |
| 2015 MFT_OUTPUT_DATA_BUFFER format_converter_output = {}; | 2032 MFT_OUTPUT_DATA_BUFFER format_converter_output = {}; |
| 2016 format_converter_output.pSample = output_sample.get(); | 2033 format_converter_output.pSample = output_sample.get(); |
| 2017 hr = video_format_converter_mft_->ProcessOutput( | 2034 hr = video_format_converter_mft_->ProcessOutput( |
| 2018 0, // No flags | 2035 0, // No flags |
| 2019 1, // # of out streams to pull from | 2036 1, // # of out streams to pull from |
| 2020 &format_converter_output, | 2037 &format_converter_output, |
| 2021 &status); | 2038 &status); |
| 2022 | 2039 |
| 2023 d3d11_device_context_->Flush(); | 2040 d3d11_device_context_->Flush(); |
| 2024 d3d11_device_context_->End(d3d11_query_.get()); | 2041 d3d11_device_context_->End(d3d11_query_.get()); |
| 2025 | 2042 |
| 2043 multi_threaded_->Leave(); |
| 2044 |
| 2026 if (FAILED(hr)) { | 2045 if (FAILED(hr)) { |
| 2027 base::debug::Alias(&hr); | 2046 base::debug::Alias(&hr); |
| 2028 // TODO(ananta) | 2047 // TODO(ananta) |
| 2029 // Remove this CHECK when the change to use DX11 for H/W decoding | 2048 // Remove this CHECK when the change to use DX11 for H/W decoding |
| 2030 // stablizes. | 2049 // stablizes. |
| 2031 CHECK(false); | 2050 CHECK(false); |
| 2032 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2051 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
| 2033 "Failed to convert output sample format.", PLATFORM_FAILURE,); | 2052 "Failed to convert output sample format.", PLATFORM_FAILURE,); |
| 2034 } | 2053 } |
| 2035 | 2054 |
| 2036 decoder_thread_task_runner_->PostDelayedTask( | 2055 main_thread_task_runner_->PostTask( |
| 2037 FROM_HERE, | 2056 FROM_HERE, |
| 2038 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, | 2057 base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, |
| 2039 base::Unretained(this), 0, | 2058 weak_this_factory_.GetWeakPtr(), |
| 2040 reinterpret_cast<IDirect3DSurface9*>(NULL), | 2059 nullptr, |
| 2041 reinterpret_cast<IDirect3DSurface9*>(NULL), | 2060 nullptr, |
| 2042 picture_buffer_id, input_buffer_id), | 2061 picture_buffer_id, |
| 2043 base::TimeDelta::FromMilliseconds( | 2062 input_buffer_id)); |
| 2044 kFlushDecoderSurfaceTimeoutMs)); | |
| 2045 } | 2063 } |
| 2046 | 2064 |
| 2047 void DXVAVideoDecodeAccelerator::FlushDecoder( | 2065 void DXVAVideoDecodeAccelerator::FlushDecoder( |
| 2048 int iterations, | 2066 int iterations, |
| 2049 IDirect3DSurface9* src_surface, | 2067 IDirect3DSurface9* src_surface, |
| 2050 IDirect3DSurface9* dest_surface, | 2068 IDirect3DSurface9* dest_surface, |
| 2051 int picture_buffer_id, | 2069 int picture_buffer_id, |
| 2052 int input_buffer_id) { | 2070 int input_buffer_id) { |
| 2053 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 2071 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 2054 | 2072 |
| 2055 // The DXVA decoder has its own device which it uses for decoding. ANGLE | 2073 // The DXVA decoder has its own device which it uses for decoding. ANGLE |
| 2056 // has its own device which we don't have access to. | 2074 // has its own device which we don't have access to. |
| 2057 // The above code attempts to copy the decoded picture into a surface | 2075 // The above code attempts to copy the decoded picture into a surface |
| 2058 // which is owned by ANGLE. As there are multiple devices involved in | 2076 // which is owned by ANGLE. As there are multiple devices involved in |
| 2059 // this, the StretchRect call above is not synchronous. | 2077 // this, the StretchRect call above is not synchronous. |
| 2060 // We attempt to flush the batched operations to ensure that the picture is | 2078 // We attempt to flush the batched operations to ensure that the picture is |
| 2061 // copied to the surface owned by ANGLE. | 2079 // copied to the surface owned by ANGLE. |
| 2062 // We need to do this in a loop and call flush multiple times. | 2080 // We need to do this in a loop and call flush multiple times. |
| 2063 // We have seen the GetData call for flushing the command buffer fail to | 2081 // We have seen the GetData call for flushing the command buffer fail to |
| 2064 // return success occassionally on multi core machines, leading to an | 2082 // return success occassionally on multi core machines, leading to an |
| 2065 // infinite loop. | 2083 // infinite loop. |
| 2066 // Workaround is to have an upper limit of 4 on the number of iterations to | 2084 // Workaround is to have an upper limit of 4 on the number of iterations to |
| 2067 // wait for the Flush to finish. | 2085 // wait for the Flush to finish. |
| 2086 DCHECK(!use_dx11_); |
| 2087 |
| 2068 HRESULT hr = E_FAIL; | 2088 HRESULT hr = E_FAIL; |
| 2069 | 2089 |
| 2070 if (use_dx11_) { | 2090 hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH); |
| 2071 BOOL query_data = 0; | 2091 |
| 2072 hr = d3d11_device_context_->GetData(d3d11_query_.get(), &query_data, | |
| 2073 sizeof(BOOL), 0); | |
| 2074 if (FAILED(hr)) { | |
| 2075 base::debug::Alias(&hr); | |
| 2076 // TODO(ananta) | |
| 2077 // Remove this CHECK when the change to use DX11 for H/W decoding | |
| 2078 // stablizes. | |
| 2079 CHECK(false); | |
| 2080 } | |
| 2081 } else { | |
| 2082 hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH); | |
| 2083 } | |
| 2084 if ((hr == S_FALSE) && (++iterations < kMaxIterationsForD3DFlush)) { | 2092 if ((hr == S_FALSE) && (++iterations < kMaxIterationsForD3DFlush)) { |
| 2085 decoder_thread_task_runner_->PostDelayedTask( | 2093 decoder_thread_task_runner_->PostDelayedTask( |
| 2086 FROM_HERE, | 2094 FROM_HERE, |
| 2087 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, | 2095 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, |
| 2088 base::Unretained(this), iterations, src_surface, | 2096 base::Unretained(this), iterations, src_surface, |
| 2089 dest_surface, picture_buffer_id, input_buffer_id), | 2097 dest_surface, picture_buffer_id, input_buffer_id), |
| 2090 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); | 2098 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); |
| 2091 return; | 2099 return; |
| 2092 } | 2100 } |
| 2093 | 2101 |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2265 D3DSURFACE_DESC surface_desc; | 2273 D3DSURFACE_DESC surface_desc; |
| 2266 hr = surface->GetDesc(&surface_desc); | 2274 hr = surface->GetDesc(&surface_desc); |
| 2267 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); | 2275 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); |
| 2268 *width = surface_desc.Width; | 2276 *width = surface_desc.Width; |
| 2269 *height = surface_desc.Height; | 2277 *height = surface_desc.Height; |
| 2270 } | 2278 } |
| 2271 return true; | 2279 return true; |
| 2272 } | 2280 } |
| 2273 | 2281 |
| 2274 } // namespace content | 2282 } // namespace content |
| OLD | NEW |