Chromium Code Reviews| 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 dx11_disabled_(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 dx11_disabled_ = base::CommandLine::ForCurrentProcess()->HasSwitch( |
|
jbauman
2015/11/02 22:55:43
I'm not sure why we're checking this command line
ananta
2015/11/02 23:11:54
Done.
| |
| 729 switches::kDisableD3D11)) { | 730 switches::kDisableD3D11); |
| 731 if (dx11_disabled_) { | |
| 730 base::win::ScopedComPtr<IDirect3DDevice9> angle_device = | 732 base::win::ScopedComPtr<IDirect3DDevice9> angle_device = |
| 731 QueryDeviceObjectFromANGLE<IDirect3DDevice9>(EGL_D3D9_DEVICE_ANGLE); | 733 QueryDeviceObjectFromANGLE<IDirect3DDevice9>(EGL_D3D9_DEVICE_ANGLE); |
| 732 RETURN_ON_FAILURE( | 734 RETURN_ON_FAILURE( |
| 733 angle_device.get(), | 735 angle_device.get(), |
| 734 "Failed to query D3D9 device object from ANGLE", | 736 "Failed to query D3D9 device object from ANGLE", |
| 735 false); | 737 false); |
| 736 | 738 |
| 737 hr = d3d9_device_ex_.QueryFrom(angle_device.get()); | 739 hr = d3d9_device_ex_.QueryFrom(angle_device.get()); |
| 738 RETURN_ON_HR_FAILURE(hr, | 740 RETURN_ON_HR_FAILURE(hr, |
| 739 "QueryInterface for IDirect3DDevice9Ex from angle device failed", | 741 "QueryInterface for IDirect3DDevice9Ex from angle device failed", |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 797 d3d11_device_->GetImmediateContext(d3d11_device_context_.Receive()); | 799 d3d11_device_->GetImmediateContext(d3d11_device_context_.Receive()); |
| 798 RETURN_ON_FAILURE( | 800 RETURN_ON_FAILURE( |
| 799 d3d11_device_context_.get(), | 801 d3d11_device_context_.get(), |
| 800 "Failed to query DX11 device context from ANGLE device", | 802 "Failed to query DX11 device context from ANGLE device", |
| 801 false); | 803 false); |
| 802 | 804 |
| 803 // Enable multithreaded mode on the context. This ensures that accesses to | 805 // Enable multithreaded mode on the context. This ensures that accesses to |
| 804 // context are synchronized across threads. We have multiple threads | 806 // context are synchronized across threads. We have multiple threads |
| 805 // accessing the context, the media foundation decoder threads and the | 807 // accessing the context, the media foundation decoder threads and the |
| 806 // decoder thread via the video format conversion transform. | 808 // decoder thread via the video format conversion transform. |
| 807 base::win::ScopedComPtr<ID3D10Multithread> multi_threaded; | 809 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); | 810 RETURN_ON_HR_FAILURE(hr, "Failed to query ID3D10Multithread", false); |
| 810 multi_threaded->SetMultithreadProtected(TRUE); | 811 multi_threaded_->SetMultithreadProtected(TRUE); |
| 811 | 812 |
| 812 hr = d3d11_device_manager_->ResetDevice(d3d11_device_.get(), | 813 hr = d3d11_device_manager_->ResetDevice(d3d11_device_.get(), |
| 813 dx11_dev_manager_reset_token_); | 814 dx11_dev_manager_reset_token_); |
| 814 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); | 815 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); |
| 815 | 816 |
| 816 D3D11_QUERY_DESC query_desc; | 817 D3D11_QUERY_DESC query_desc; |
| 817 query_desc.Query = D3D11_QUERY_EVENT; | 818 query_desc.Query = D3D11_QUERY_EVENT; |
| 818 query_desc.MiscFlags = 0; | 819 query_desc.MiscFlags = 0; |
| 819 hr = d3d11_device_->CreateQuery( | 820 hr = d3d11_device_->CreateQuery( |
| 820 &query_desc, | 821 &query_desc, |
| (...skipping 670 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1491 client_ = NULL; | 1492 client_ = NULL; |
| 1492 | 1493 |
| 1493 if (GetState() != kUninitialized) { | 1494 if (GetState() != kUninitialized) { |
| 1494 Invalidate(); | 1495 Invalidate(); |
| 1495 } | 1496 } |
| 1496 } | 1497 } |
| 1497 | 1498 |
| 1498 void DXVAVideoDecodeAccelerator::Invalidate() { | 1499 void DXVAVideoDecodeAccelerator::Invalidate() { |
| 1499 if (GetState() == kUninitialized) | 1500 if (GetState() == kUninitialized) |
| 1500 return; | 1501 return; |
| 1502 | |
| 1501 decoder_thread_.Stop(); | 1503 decoder_thread_.Stop(); |
| 1502 weak_this_factory_.InvalidateWeakPtrs(); | 1504 weak_this_factory_.InvalidateWeakPtrs(); |
| 1503 output_picture_buffers_.clear(); | 1505 output_picture_buffers_.clear(); |
| 1504 stale_output_picture_buffers_.clear(); | 1506 stale_output_picture_buffers_.clear(); |
| 1505 pending_output_samples_.clear(); | 1507 pending_output_samples_.clear(); |
| 1506 pending_input_buffers_.clear(); | 1508 pending_input_buffers_.clear(); |
| 1507 decoder_.Release(); | 1509 decoder_.Release(); |
| 1508 | 1510 |
| 1509 if (use_dx11_) { | 1511 if (use_dx11_) { |
| 1510 if (video_format_converter_mft_.get()) { | 1512 if (video_format_converter_mft_.get()) { |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1847 | 1849 |
| 1848 HRESULT hr = d3d9_device_ex_->StretchRect(src_surface, NULL, dest_surface, | 1850 HRESULT hr = d3d9_device_ex_->StretchRect(src_surface, NULL, dest_surface, |
| 1849 NULL, D3DTEXF_NONE); | 1851 NULL, D3DTEXF_NONE); |
| 1850 RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed",); | 1852 RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed",); |
| 1851 | 1853 |
| 1852 // Ideally, this should be done immediately before the draw call that uses | 1854 // Ideally, this should be done immediately before the draw call that uses |
| 1853 // the texture. Flush it once here though. | 1855 // the texture. Flush it once here though. |
| 1854 hr = query_->Issue(D3DISSUE_END); | 1856 hr = query_->Issue(D3DISSUE_END); |
| 1855 RETURN_ON_HR_FAILURE(hr, "Failed to issue END",); | 1857 RETURN_ON_HR_FAILURE(hr, "Failed to issue END",); |
| 1856 | 1858 |
| 1859 // If we are running in pure D3D9 mode we don't need to wait for the Flush to | |
| 1860 // complete as we are sharing the ANGLE device. | |
| 1861 if (dx11_disabled_) { | |
| 1862 main_thread_task_runner_->PostTask( | |
| 1863 FROM_HERE, | |
| 1864 base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, | |
| 1865 weak_this_factory_.GetWeakPtr(), | |
| 1866 src_surface, | |
| 1867 dest_surface, | |
| 1868 picture_buffer_id, | |
| 1869 input_buffer_id)); | |
| 1870 return; | |
| 1871 } | |
| 1872 | |
| 1857 // Flush the decoder device to ensure that the decoded frame is copied to the | 1873 // Flush the decoder device to ensure that the decoded frame is copied to the |
| 1858 // target surface. | 1874 // target surface. |
| 1859 decoder_thread_task_runner_->PostDelayedTask( | 1875 decoder_thread_task_runner_->PostDelayedTask( |
| 1860 FROM_HERE, | 1876 FROM_HERE, |
| 1861 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, | 1877 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, |
| 1862 base::Unretained(this), 0, src_surface, dest_surface, | 1878 base::Unretained(this), 0, src_surface, dest_surface, |
| 1863 picture_buffer_id, input_buffer_id), | 1879 picture_buffer_id, input_buffer_id), |
| 1864 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); | 1880 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); |
| 1865 } | 1881 } |
| 1866 | 1882 |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2004 // TODO(ananta) | 2020 // TODO(ananta) |
| 2005 // Remove this CHECK when the change to use DX11 for H/W decoding | 2021 // Remove this CHECK when the change to use DX11 for H/W decoding |
| 2006 // stablizes. | 2022 // stablizes. |
| 2007 CHECK(false); | 2023 CHECK(false); |
| 2008 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2024 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
| 2009 "Failed to create output sample.", PLATFORM_FAILURE,); | 2025 "Failed to create output sample.", PLATFORM_FAILURE,); |
| 2010 } | 2026 } |
| 2011 | 2027 |
| 2012 output_sample->AddBuffer(output_buffer.get()); | 2028 output_sample->AddBuffer(output_buffer.get()); |
| 2013 | 2029 |
| 2030 // Lock the device here as we are accessing the destination texture created | |
| 2031 // on the main thread. | |
| 2032 multi_threaded_->Enter(); | |
| 2033 | |
| 2014 DWORD status = 0; | 2034 DWORD status = 0; |
| 2015 MFT_OUTPUT_DATA_BUFFER format_converter_output = {}; | 2035 MFT_OUTPUT_DATA_BUFFER format_converter_output = {}; |
| 2016 format_converter_output.pSample = output_sample.get(); | 2036 format_converter_output.pSample = output_sample.get(); |
| 2017 hr = video_format_converter_mft_->ProcessOutput( | 2037 hr = video_format_converter_mft_->ProcessOutput( |
| 2018 0, // No flags | 2038 0, // No flags |
| 2019 1, // # of out streams to pull from | 2039 1, // # of out streams to pull from |
| 2020 &format_converter_output, | 2040 &format_converter_output, |
| 2021 &status); | 2041 &status); |
| 2022 | 2042 |
| 2023 d3d11_device_context_->Flush(); | 2043 d3d11_device_context_->Flush(); |
| 2024 d3d11_device_context_->End(d3d11_query_.get()); | 2044 d3d11_device_context_->End(d3d11_query_.get()); |
| 2025 | 2045 |
| 2046 multi_threaded_->Leave(); | |
| 2047 | |
| 2026 if (FAILED(hr)) { | 2048 if (FAILED(hr)) { |
| 2027 base::debug::Alias(&hr); | 2049 base::debug::Alias(&hr); |
| 2028 // TODO(ananta) | 2050 // TODO(ananta) |
| 2029 // Remove this CHECK when the change to use DX11 for H/W decoding | 2051 // Remove this CHECK when the change to use DX11 for H/W decoding |
| 2030 // stablizes. | 2052 // stablizes. |
| 2031 CHECK(false); | 2053 CHECK(false); |
| 2032 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, | 2054 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, |
| 2033 "Failed to convert output sample format.", PLATFORM_FAILURE,); | 2055 "Failed to convert output sample format.", PLATFORM_FAILURE,); |
| 2034 } | 2056 } |
| 2035 | 2057 |
| 2036 decoder_thread_task_runner_->PostDelayedTask( | 2058 main_thread_task_runner_->PostTask( |
| 2037 FROM_HERE, | 2059 FROM_HERE, |
| 2038 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, | 2060 base::Bind(&DXVAVideoDecodeAccelerator::CopySurfaceComplete, |
| 2039 base::Unretained(this), 0, | 2061 weak_this_factory_.GetWeakPtr(), |
| 2040 reinterpret_cast<IDirect3DSurface9*>(NULL), | 2062 nullptr, |
| 2041 reinterpret_cast<IDirect3DSurface9*>(NULL), | 2063 nullptr, |
| 2042 picture_buffer_id, input_buffer_id), | 2064 picture_buffer_id, |
| 2043 base::TimeDelta::FromMilliseconds( | 2065 input_buffer_id)); |
| 2044 kFlushDecoderSurfaceTimeoutMs)); | |
| 2045 } | 2066 } |
| 2046 | 2067 |
| 2047 void DXVAVideoDecodeAccelerator::FlushDecoder( | 2068 void DXVAVideoDecodeAccelerator::FlushDecoder( |
| 2048 int iterations, | 2069 int iterations, |
| 2049 IDirect3DSurface9* src_surface, | 2070 IDirect3DSurface9* src_surface, |
| 2050 IDirect3DSurface9* dest_surface, | 2071 IDirect3DSurface9* dest_surface, |
| 2051 int picture_buffer_id, | 2072 int picture_buffer_id, |
| 2052 int input_buffer_id) { | 2073 int input_buffer_id) { |
| 2053 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); | 2074 DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
| 2054 | 2075 |
| 2055 // The DXVA decoder has its own device which it uses for decoding. ANGLE | 2076 // 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. | 2077 // has its own device which we don't have access to. |
| 2057 // The above code attempts to copy the decoded picture into a surface | 2078 // 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 | 2079 // which is owned by ANGLE. As there are multiple devices involved in |
| 2059 // this, the StretchRect call above is not synchronous. | 2080 // this, the StretchRect call above is not synchronous. |
| 2060 // We attempt to flush the batched operations to ensure that the picture is | 2081 // We attempt to flush the batched operations to ensure that the picture is |
| 2061 // copied to the surface owned by ANGLE. | 2082 // copied to the surface owned by ANGLE. |
| 2062 // We need to do this in a loop and call flush multiple times. | 2083 // 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 | 2084 // We have seen the GetData call for flushing the command buffer fail to |
| 2064 // return success occassionally on multi core machines, leading to an | 2085 // return success occassionally on multi core machines, leading to an |
| 2065 // infinite loop. | 2086 // infinite loop. |
| 2066 // Workaround is to have an upper limit of 4 on the number of iterations to | 2087 // Workaround is to have an upper limit of 4 on the number of iterations to |
| 2067 // wait for the Flush to finish. | 2088 // wait for the Flush to finish. |
| 2089 DCHECK(!use_dx11_); | |
| 2090 | |
| 2068 HRESULT hr = E_FAIL; | 2091 HRESULT hr = E_FAIL; |
| 2069 | 2092 |
| 2070 if (use_dx11_) { | 2093 hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH); |
| 2071 BOOL query_data = 0; | 2094 |
| 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)) { | 2095 if ((hr == S_FALSE) && (++iterations < kMaxIterationsForD3DFlush)) { |
| 2085 decoder_thread_task_runner_->PostDelayedTask( | 2096 decoder_thread_task_runner_->PostDelayedTask( |
| 2086 FROM_HERE, | 2097 FROM_HERE, |
| 2087 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, | 2098 base::Bind(&DXVAVideoDecodeAccelerator::FlushDecoder, |
| 2088 base::Unretained(this), iterations, src_surface, | 2099 base::Unretained(this), iterations, src_surface, |
| 2089 dest_surface, picture_buffer_id, input_buffer_id), | 2100 dest_surface, picture_buffer_id, input_buffer_id), |
| 2090 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); | 2101 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); |
| 2091 return; | 2102 return; |
| 2092 } | 2103 } |
| 2093 | 2104 |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2265 D3DSURFACE_DESC surface_desc; | 2276 D3DSURFACE_DESC surface_desc; |
| 2266 hr = surface->GetDesc(&surface_desc); | 2277 hr = surface->GetDesc(&surface_desc); |
| 2267 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); | 2278 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); |
| 2268 *width = surface_desc.Width; | 2279 *width = surface_desc.Width; |
| 2269 *height = surface_desc.Height; | 2280 *height = surface_desc.Height; |
| 2270 } | 2281 } |
| 2271 return true; | 2282 return true; |
| 2272 } | 2283 } |
| 2273 | 2284 |
| 2274 } // namespace content | 2285 } // namespace content |
| OLD | NEW |