Chromium Code Reviews| Index: gpu/ipc/service/direct_composition_surface_win.cc |
| diff --git a/gpu/ipc/service/direct_composition_surface_win.cc b/gpu/ipc/service/direct_composition_surface_win.cc |
| index 1698f220a69675590d9498f6fe5ceef79e5d723c..222cf5d169528c9622426436ef703dfceb0190f4 100644 |
| --- a/gpu/ipc/service/direct_composition_surface_win.cc |
| +++ b/gpu/ipc/service/direct_composition_surface_win.cc |
| @@ -7,6 +7,8 @@ |
| #include <d3d11_1.h> |
| #include <dcomptypes.h> |
| +#include <deque> |
| + |
| #include "base/feature_list.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/metrics/histogram_macros.h" |
| @@ -71,6 +73,37 @@ bool SizeContains(const gfx::Size& a, const gfx::Size& b) { |
| return gfx::Rect(a).Contains(gfx::Rect(b)); |
| } |
| +// This keeps track of whether the previous 30 frames used Overlays or GPU |
| +// composition to present. |
| +class PresentationHistory { |
| + public: |
| + static const int kPresentsToStore = 30; |
| + |
| + PresentationHistory() {} |
| + |
| + void AddSample(DXGI_FRAME_PRESENTATION_MODE mode) { |
| + if (mode == DXGI_FRAME_PRESENTATION_MODE_COMPOSED) |
| + composed_count_++; |
| + |
| + presents_.push_back(mode); |
| + if (presents_.size() > kPresentsToStore) { |
| + DXGI_FRAME_PRESENTATION_MODE first_mode = presents_.front(); |
| + if (first_mode == DXGI_FRAME_PRESENTATION_MODE_COMPOSED) |
| + composed_count_--; |
| + presents_.pop_front(); |
| + } |
| + } |
| + |
| + bool valid() const { return presents_.size() >= kPresentsToStore; } |
| + int composed_count() const { return composed_count_; } |
| + |
| + private: |
| + std::deque<DXGI_FRAME_PRESENTATION_MODE> presents_; |
| + int composed_count_ = 0; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(PresentationHistory); |
| +}; |
| + |
| // Only one DirectComposition surface can be rendered into at a time. Track |
| // here which IDCompositionSurface is being rendered into. If another context |
| // is made current, then this surface will be suspended. |
| @@ -178,7 +211,8 @@ class DCLayerTree::SwapChainPresenter { |
| // Returns true if the video processor changed. |
| bool InitializeVideoProcessor(const gfx::Size& in_size, |
| const gfx::Size& out_size); |
| - void ReallocateSwapChain(); |
| + void ReallocateSwapChain(bool yuy2); |
| + bool ShouldBeYUY2(); |
| DCLayerTree* surface_; |
| PFN_DCOMPOSITION_CREATE_SURFACE_HANDLE create_surface_handle_function_; |
| @@ -193,6 +227,10 @@ class DCLayerTree::SwapChainPresenter { |
| float swap_chain_scale_x_ = 0.0f; |
| float swap_chain_scale_y_ = 0.0f; |
| + PresentationHistory history_; |
|
sunnyps
2017/04/11 23:19:29
nit: presentation_history_
|
| + bool failed_to_create_yuy2_swapchain_ = false; |
| + int frames_since_color_space_change_ = 0; |
| + |
| // This is the GLImage that was presented in the last frame. |
| scoped_refptr<gl::GLImageDXGI> last_gl_image_; |
| @@ -287,6 +325,25 @@ DCLayerTree::SwapChainPresenter::SwapChainPresenter( |
| DCLayerTree::SwapChainPresenter::~SwapChainPresenter() {} |
| +bool DCLayerTree::SwapChainPresenter::ShouldBeYUY2() { |
| + // Start out as YUY2. |
| + if (!history_.valid()) |
| + return true; |
| + int composition_count = history_.composed_count(); |
| + |
| + // It's more efficient to use a BGRA backbuffer instead of YUY2 if overlays |
| + // aren't being used, as otherwise DWM will use the video processor a second |
| + // time to convert it to BGRA before displaying it on screen. |
| + |
| + if (is_yuy2_swapchain_) { |
| + // Switch to BGRA once 3/4 of presents are composed. |
| + return composition_count < (PresentationHistory::kPresentsToStore * 3 / 4); |
| + } else { |
| + // Switch to YUY2 once 3/4 are using overlays (or unknown). |
| + return composition_count < (PresentationHistory::kPresentsToStore / 4); |
| + } |
| +} |
| + |
| void DCLayerTree::SwapChainPresenter::PresentToSwapChain( |
| const ui::DCRendererLayerParams& params) { |
| gl::GLImageDXGI* image_dxgi = |
| @@ -309,12 +366,15 @@ void DCLayerTree::SwapChainPresenter::PresentToSwapChain( |
| InitializeVideoProcessor(ceiled_input_size, swap_chain_size); |
| + bool yuy2_swapchain = ShouldBeYUY2(); |
| bool first_present = false; |
| - if (!swap_chain_ || swap_chain_size_ != swap_chain_size) { |
| + if (!swap_chain_ || swap_chain_size_ != swap_chain_size || |
| + ((yuy2_swapchain != is_yuy2_swapchain_) && |
| + !failed_to_create_yuy2_swapchain_)) { |
| first_present = true; |
| swap_chain_size_ = swap_chain_size; |
| swap_chain_.Reset(); |
| - ReallocateSwapChain(); |
| + ReallocateSwapChain(yuy2_swapchain); |
| } else if (last_gl_image_ == image_dxgi) { |
| // The swap chain is presenting the same image as last swap, which means |
| // that the image was never returned to the video decoder and should have |
| @@ -413,12 +473,15 @@ void DCLayerTree::SwapChainPresenter::PresentToSwapChain( |
| swap_chain_->Present(first_present ? 0 : 1, 0); |
| + frames_since_color_space_change_++; |
| + |
| base::win::ScopedComPtr<IDXGISwapChainMedia> swap_chain_media; |
| if (SUCCEEDED(swap_chain_.QueryInterface(swap_chain_media.Receive()))) { |
| DXGI_FRAME_STATISTICS_MEDIA stats = {}; |
| if (SUCCEEDED(swap_chain_media->GetFrameStatisticsMedia(&stats))) { |
| UMA_HISTOGRAM_SPARSE_SLOWLY("GPU.DirectComposition.CompositionMode", |
| stats.CompositionMode); |
| + history_.AddSample(stats.CompositionMode); |
| } |
| } |
| } |
| @@ -441,7 +504,7 @@ bool DCLayerTree::SwapChainPresenter::InitializeVideoProcessor( |
| return true; |
| } |
| -void DCLayerTree::SwapChainPresenter::ReallocateSwapChain() { |
| +void DCLayerTree::SwapChainPresenter::ReallocateSwapChain(bool yuy2) { |
| TRACE_EVENT0("gpu", "DCLayerTree::SwapChainPresenter::ReallocateSwapChain"); |
| DCHECK(!swap_chain_); |
| @@ -473,12 +536,24 @@ void DCLayerTree::SwapChainPresenter::ReallocateSwapChain() { |
| &handle); |
| swap_chain_handle_.Set(handle); |
| + if (is_yuy2_swapchain_ != yuy2) { |
| + UMA_HISTOGRAM_COUNTS_1000( |
| + "GPU.DirectComposition.FramesSinceColorSpaceChange", |
| + frames_since_color_space_change_); |
| + } |
| + |
| + frames_since_color_space_change_ = 0; |
| + |
| is_yuy2_swapchain_ = true; |
| // The composition surface handle isn't actually used, but |
| // CreateSwapChainForComposition can't create YUY2 swapchains. |
| - HRESULT hr = media_factory->CreateSwapChainForCompositionSurfaceHandle( |
| - d3d11_device_.get(), swap_chain_handle_.Get(), &desc, nullptr, |
| - swap_chain_.Receive()); |
| + HRESULT hr = E_FAIL; |
|
sunnyps
2017/04/11 23:19:30
nit: can you rewrite to something like this:
is_y
|
| + if (yuy2) { |
| + hr = media_factory->CreateSwapChainForCompositionSurfaceHandle( |
| + d3d11_device_.get(), swap_chain_handle_.Get(), &desc, nullptr, |
| + swap_chain_.Receive()); |
| + failed_to_create_yuy2_swapchain_ = FAILED(hr); |
| + } |
| if (FAILED(hr)) { |
| // This should not be hit in production but is a simple fallback for |
|
sunnyps
2017/04/11 23:19:30
nit: This comment needs to be updated.
|