Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: gpu/ipc/service/direct_composition_surface_win.cc

Issue 2809473003: Switch DirectComposition layers to BGRA if overlay allocation fails. (Closed)
Patch Set: post-review changes Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 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 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 "gpu/ipc/service/direct_composition_surface_win.h" 5 #include "gpu/ipc/service/direct_composition_surface_win.h"
6 6
7 #include <d3d11_1.h> 7 #include <d3d11_1.h>
8 #include <dcomptypes.h> 8 #include <dcomptypes.h>
9 9
10 #include <deque>
11
10 #include "base/feature_list.h" 12 #include "base/feature_list.h"
11 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
12 #include "base/metrics/histogram_macros.h" 14 #include "base/metrics/histogram_macros.h"
13 #include "base/optional.h" 15 #include "base/optional.h"
14 #include "base/synchronization/waitable_event.h" 16 #include "base/synchronization/waitable_event.h"
15 #include "base/trace_event/trace_event.h" 17 #include "base/trace_event/trace_event.h"
16 #include "base/win/scoped_handle.h" 18 #include "base/win/scoped_handle.h"
17 #include "base/win/windows_version.h" 19 #include "base/win/windows_version.h"
18 #include "gpu/ipc/service/gpu_channel_manager.h" 20 #include "gpu/ipc/service/gpu_channel_manager.h"
19 #include "gpu/ipc/service/gpu_channel_manager_delegate.h" 21 #include "gpu/ipc/service/gpu_channel_manager_delegate.h"
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 } 66 }
65 67
66 private: 68 private:
67 base::Optional<ui::ScopedMakeCurrent> make_current_; 69 base::Optional<ui::ScopedMakeCurrent> make_current_;
68 }; 70 };
69 71
70 bool SizeContains(const gfx::Size& a, const gfx::Size& b) { 72 bool SizeContains(const gfx::Size& a, const gfx::Size& b) {
71 return gfx::Rect(a).Contains(gfx::Rect(b)); 73 return gfx::Rect(a).Contains(gfx::Rect(b));
72 } 74 }
73 75
76 // This keeps track of whether the previous 30 frames used Overlays or GPU
77 // composition to present.
78 class PresentationHistory {
79 public:
80 static const int kPresentsToStore = 30;
81
82 PresentationHistory() {}
83
84 void AddSample(DXGI_FRAME_PRESENTATION_MODE mode) {
85 if (mode == DXGI_FRAME_PRESENTATION_MODE_COMPOSED)
86 composed_count_++;
87
88 presents_.push_back(mode);
89 if (presents_.size() > kPresentsToStore) {
90 DXGI_FRAME_PRESENTATION_MODE first_mode = presents_.front();
91 if (first_mode == DXGI_FRAME_PRESENTATION_MODE_COMPOSED)
92 composed_count_--;
93 presents_.pop_front();
94 }
95 }
96
97 bool valid() const { return presents_.size() >= kPresentsToStore; }
98 int composed_count() const { return composed_count_; }
99
100 private:
101 std::deque<DXGI_FRAME_PRESENTATION_MODE> presents_;
102 int composed_count_ = 0;
103
104 DISALLOW_COPY_AND_ASSIGN(PresentationHistory);
105 };
106
74 // Only one DirectComposition surface can be rendered into at a time. Track 107 // Only one DirectComposition surface can be rendered into at a time. Track
75 // here which IDCompositionSurface is being rendered into. If another context 108 // here which IDCompositionSurface is being rendered into. If another context
76 // is made current, then this surface will be suspended. 109 // is made current, then this surface will be suspended.
77 IDCompositionSurface* g_current_surface; 110 IDCompositionSurface* g_current_surface;
78 111
79 } // namespace 112 } // namespace
80 113
81 class DCLayerTree { 114 class DCLayerTree {
82 public: 115 public:
83 DCLayerTree(DirectCompositionSurfaceWin* surface, 116 DCLayerTree(DirectCompositionSurfaceWin* surface,
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
171 return swap_chain_; 204 return swap_chain_;
172 } 205 }
173 206
174 private: 207 private:
175 using PFN_DCOMPOSITION_CREATE_SURFACE_HANDLE = 208 using PFN_DCOMPOSITION_CREATE_SURFACE_HANDLE =
176 HRESULT(WINAPI*)(DWORD, SECURITY_ATTRIBUTES*, HANDLE*); 209 HRESULT(WINAPI*)(DWORD, SECURITY_ATTRIBUTES*, HANDLE*);
177 210
178 // Returns true if the video processor changed. 211 // Returns true if the video processor changed.
179 bool InitializeVideoProcessor(const gfx::Size& in_size, 212 bool InitializeVideoProcessor(const gfx::Size& in_size,
180 const gfx::Size& out_size); 213 const gfx::Size& out_size);
181 void ReallocateSwapChain(); 214 void ReallocateSwapChain(bool yuy2);
215 bool ShouldBeYUY2();
182 216
183 DCLayerTree* surface_; 217 DCLayerTree* surface_;
184 PFN_DCOMPOSITION_CREATE_SURFACE_HANDLE create_surface_handle_function_; 218 PFN_DCOMPOSITION_CREATE_SURFACE_HANDLE create_surface_handle_function_;
185 219
186 gfx::Size swap_chain_size_; 220 gfx::Size swap_chain_size_;
187 gfx::Size processor_input_size_; 221 gfx::Size processor_input_size_;
188 gfx::Size processor_output_size_; 222 gfx::Size processor_output_size_;
189 bool is_yuy2_swapchain_ = false; 223 bool is_yuy2_swapchain_ = false;
190 224
191 // This is the scale from the swapchain size to the size of the contents 225 // This is the scale from the swapchain size to the size of the contents
192 // onscreen. 226 // onscreen.
193 float swap_chain_scale_x_ = 0.0f; 227 float swap_chain_scale_x_ = 0.0f;
194 float swap_chain_scale_y_ = 0.0f; 228 float swap_chain_scale_y_ = 0.0f;
195 229
230 PresentationHistory presentation_history_;
231 bool failed_to_create_yuy2_swapchain_ = false;
232 int frames_since_color_space_change_ = 0;
233
196 // This is the GLImage that was presented in the last frame. 234 // This is the GLImage that was presented in the last frame.
197 scoped_refptr<gl::GLImageDXGI> last_gl_image_; 235 scoped_refptr<gl::GLImageDXGI> last_gl_image_;
198 236
199 base::win::ScopedComPtr<ID3D11Device> d3d11_device_; 237 base::win::ScopedComPtr<ID3D11Device> d3d11_device_;
200 base::win::ScopedComPtr<IDXGISwapChain1> swap_chain_; 238 base::win::ScopedComPtr<IDXGISwapChain1> swap_chain_;
201 base::win::ScopedComPtr<ID3D11VideoProcessorOutputView> out_view_; 239 base::win::ScopedComPtr<ID3D11VideoProcessorOutputView> out_view_;
202 base::win::ScopedComPtr<ID3D11VideoProcessor> video_processor_; 240 base::win::ScopedComPtr<ID3D11VideoProcessor> video_processor_;
203 base::win::ScopedComPtr<ID3D11VideoProcessorEnumerator> 241 base::win::ScopedComPtr<ID3D11VideoProcessorEnumerator>
204 video_processor_enumerator_; 242 video_processor_enumerator_;
205 base::win::ScopedComPtr<ID3D11VideoDevice> video_device_; 243 base::win::ScopedComPtr<ID3D11VideoDevice> video_device_;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
280 HMODULE dcomp = ::GetModuleHandleA("dcomp.dll"); 318 HMODULE dcomp = ::GetModuleHandleA("dcomp.dll");
281 CHECK(dcomp); 319 CHECK(dcomp);
282 create_surface_handle_function_ = 320 create_surface_handle_function_ =
283 reinterpret_cast<PFN_DCOMPOSITION_CREATE_SURFACE_HANDLE>( 321 reinterpret_cast<PFN_DCOMPOSITION_CREATE_SURFACE_HANDLE>(
284 GetProcAddress(dcomp, "DCompositionCreateSurfaceHandle")); 322 GetProcAddress(dcomp, "DCompositionCreateSurfaceHandle"));
285 CHECK(create_surface_handle_function_); 323 CHECK(create_surface_handle_function_);
286 } 324 }
287 325
288 DCLayerTree::SwapChainPresenter::~SwapChainPresenter() {} 326 DCLayerTree::SwapChainPresenter::~SwapChainPresenter() {}
289 327
328 bool DCLayerTree::SwapChainPresenter::ShouldBeYUY2() {
329 // Start out as YUY2.
330 if (!presentation_history_.valid())
331 return true;
332 int composition_count = presentation_history_.composed_count();
333
334 // It's more efficient to use a BGRA backbuffer instead of YUY2 if overlays
335 // aren't being used, as otherwise DWM will use the video processor a second
336 // time to convert it to BGRA before displaying it on screen.
337
338 if (is_yuy2_swapchain_) {
339 // Switch to BGRA once 3/4 of presents are composed.
340 return composition_count < (PresentationHistory::kPresentsToStore * 3 / 4);
341 } else {
342 // Switch to YUY2 once 3/4 are using overlays (or unknown).
343 return composition_count < (PresentationHistory::kPresentsToStore / 4);
344 }
345 }
346
290 void DCLayerTree::SwapChainPresenter::PresentToSwapChain( 347 void DCLayerTree::SwapChainPresenter::PresentToSwapChain(
291 const ui::DCRendererLayerParams& params) { 348 const ui::DCRendererLayerParams& params) {
292 gl::GLImageDXGI* image_dxgi = 349 gl::GLImageDXGI* image_dxgi =
293 gl::GLImageDXGI::FromGLImage(params.image.get()); 350 gl::GLImageDXGI::FromGLImage(params.image.get());
294 DCHECK(image_dxgi); 351 DCHECK(image_dxgi);
295 352
296 // Swap chain size is the minimum of the on-screen size and the source 353 // Swap chain size is the minimum of the on-screen size and the source
297 // size so the video processor can do the minimal amount of work and 354 // size so the video processor can do the minimal amount of work and
298 // the overlay has to read the minimal amount of data. 355 // the overlay has to read the minimal amount of data.
299 // DWM is also less likely to promote a surface to an overlay if it's 356 // DWM is also less likely to promote a surface to an overlay if it's
300 // much larger than its area on-screen. 357 // much larger than its area on-screen.
301 gfx::Rect bounds_rect = params.rect; 358 gfx::Rect bounds_rect = params.rect;
302 gfx::Size ceiled_input_size = gfx::ToCeiledSize(params.contents_rect.size()); 359 gfx::Size ceiled_input_size = gfx::ToCeiledSize(params.contents_rect.size());
303 gfx::Size swap_chain_size = bounds_rect.size(); 360 gfx::Size swap_chain_size = bounds_rect.size();
304 swap_chain_size.SetToMin(ceiled_input_size); 361 swap_chain_size.SetToMin(ceiled_input_size);
305 362
306 // YUY2 surfaces must have an even width. 363 // YUY2 surfaces must have an even width.
307 if (swap_chain_size.width() % 2 == 1) 364 if (swap_chain_size.width() % 2 == 1)
308 swap_chain_size.set_width(swap_chain_size.width() + 1); 365 swap_chain_size.set_width(swap_chain_size.width() + 1);
309 366
310 InitializeVideoProcessor(ceiled_input_size, swap_chain_size); 367 InitializeVideoProcessor(ceiled_input_size, swap_chain_size);
311 368
369 bool yuy2_swapchain = ShouldBeYUY2();
312 bool first_present = false; 370 bool first_present = false;
313 if (!swap_chain_ || swap_chain_size_ != swap_chain_size) { 371 if (!swap_chain_ || swap_chain_size_ != swap_chain_size ||
372 ((yuy2_swapchain != is_yuy2_swapchain_) &&
373 !failed_to_create_yuy2_swapchain_)) {
314 first_present = true; 374 first_present = true;
315 swap_chain_size_ = swap_chain_size; 375 swap_chain_size_ = swap_chain_size;
316 swap_chain_.Reset(); 376 swap_chain_.Reset();
317 ReallocateSwapChain(); 377 ReallocateSwapChain(yuy2_swapchain);
318 } else if (last_gl_image_ == image_dxgi) { 378 } else if (last_gl_image_ == image_dxgi) {
319 // The swap chain is presenting the same image as last swap, which means 379 // The swap chain is presenting the same image as last swap, which means
320 // that the image was never returned to the video decoder and should have 380 // that the image was never returned to the video decoder and should have
321 // the same contents as last time. It shouldn't need to be redrawn. 381 // the same contents as last time. It shouldn't need to be redrawn.
322 return; 382 return;
323 } 383 }
324 384
325 last_gl_image_ = image_dxgi; 385 last_gl_image_ = image_dxgi;
326 386
327 if (!out_view_) { 387 if (!out_view_) {
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 hr = video_context_->VideoProcessorBlt(video_processor_.get(), 468 hr = video_context_->VideoProcessorBlt(video_processor_.get(),
409 out_view_.get(), 0, 1, &stream); 469 out_view_.get(), 0, 1, &stream);
410 CHECK(SUCCEEDED(hr)); 470 CHECK(SUCCEEDED(hr));
411 } 471 }
412 472
413 swap_chain_scale_x_ = bounds_rect.width() * 1.0f / swap_chain_size.width(); 473 swap_chain_scale_x_ = bounds_rect.width() * 1.0f / swap_chain_size.width();
414 swap_chain_scale_y_ = bounds_rect.height() * 1.0f / swap_chain_size.height(); 474 swap_chain_scale_y_ = bounds_rect.height() * 1.0f / swap_chain_size.height();
415 475
416 swap_chain_->Present(first_present ? 0 : 1, 0); 476 swap_chain_->Present(first_present ? 0 : 1, 0);
417 477
478 frames_since_color_space_change_++;
479
418 base::win::ScopedComPtr<IDXGISwapChainMedia> swap_chain_media; 480 base::win::ScopedComPtr<IDXGISwapChainMedia> swap_chain_media;
419 if (SUCCEEDED(swap_chain_.QueryInterface(swap_chain_media.Receive()))) { 481 if (SUCCEEDED(swap_chain_.QueryInterface(swap_chain_media.Receive()))) {
420 DXGI_FRAME_STATISTICS_MEDIA stats = {}; 482 DXGI_FRAME_STATISTICS_MEDIA stats = {};
421 if (SUCCEEDED(swap_chain_media->GetFrameStatisticsMedia(&stats))) { 483 if (SUCCEEDED(swap_chain_media->GetFrameStatisticsMedia(&stats))) {
422 UMA_HISTOGRAM_SPARSE_SLOWLY("GPU.DirectComposition.CompositionMode", 484 UMA_HISTOGRAM_SPARSE_SLOWLY("GPU.DirectComposition.CompositionMode",
423 stats.CompositionMode); 485 stats.CompositionMode);
486 presentation_history_.AddSample(stats.CompositionMode);
424 } 487 }
425 } 488 }
426 } 489 }
427 490
428 bool DCLayerTree::SwapChainPresenter::InitializeVideoProcessor( 491 bool DCLayerTree::SwapChainPresenter::InitializeVideoProcessor(
429 const gfx::Size& in_size, 492 const gfx::Size& in_size,
430 const gfx::Size& out_size) { 493 const gfx::Size& out_size) {
431 if (video_processor_ && SizeContains(processor_input_size_, in_size) && 494 if (video_processor_ && SizeContains(processor_input_size_, in_size) &&
432 SizeContains(processor_output_size_, out_size)) 495 SizeContains(processor_output_size_, out_size))
433 return false; 496 return false;
434 processor_input_size_ = in_size; 497 processor_input_size_ = in_size;
435 processor_output_size_ = out_size; 498 processor_output_size_ = out_size;
436 surface_->InitializeVideoProcessor(in_size, out_size); 499 surface_->InitializeVideoProcessor(in_size, out_size);
437 500
438 video_processor_enumerator_ = surface_->video_processor_enumerator(); 501 video_processor_enumerator_ = surface_->video_processor_enumerator();
439 video_processor_ = surface_->video_processor(); 502 video_processor_ = surface_->video_processor();
440 // out_view_ depends on video_processor_enumerator_, so ensure it's 503 // out_view_ depends on video_processor_enumerator_, so ensure it's
441 // recreated if the enumerator is. 504 // recreated if the enumerator is.
442 out_view_.Reset(); 505 out_view_.Reset();
443 return true; 506 return true;
444 } 507 }
445 508
446 void DCLayerTree::SwapChainPresenter::ReallocateSwapChain() { 509 void DCLayerTree::SwapChainPresenter::ReallocateSwapChain(bool yuy2) {
447 TRACE_EVENT0("gpu", "DCLayerTree::SwapChainPresenter::ReallocateSwapChain"); 510 TRACE_EVENT0("gpu", "DCLayerTree::SwapChainPresenter::ReallocateSwapChain");
448 DCHECK(!swap_chain_); 511 DCHECK(!swap_chain_);
449 512
450 base::win::ScopedComPtr<IDXGIDevice> dxgi_device; 513 base::win::ScopedComPtr<IDXGIDevice> dxgi_device;
451 d3d11_device_.QueryInterface(dxgi_device.Receive()); 514 d3d11_device_.QueryInterface(dxgi_device.Receive());
452 base::win::ScopedComPtr<IDXGIAdapter> dxgi_adapter; 515 base::win::ScopedComPtr<IDXGIAdapter> dxgi_adapter;
453 dxgi_device->GetAdapter(dxgi_adapter.Receive()); 516 dxgi_device->GetAdapter(dxgi_adapter.Receive());
454 base::win::ScopedComPtr<IDXGIFactory2> dxgi_factory; 517 base::win::ScopedComPtr<IDXGIFactory2> dxgi_factory;
455 dxgi_adapter->GetParent(IID_PPV_ARGS(dxgi_factory.Receive())); 518 dxgi_adapter->GetParent(IID_PPV_ARGS(dxgi_factory.Receive()));
456 519
(...skipping 11 matching lines...) Expand all
468 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; 531 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
469 desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; 532 desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
470 desc.Flags = 533 desc.Flags =
471 DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO | DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO; 534 DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO | DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO;
472 535
473 HANDLE handle; 536 HANDLE handle;
474 create_surface_handle_function_(COMPOSITIONOBJECT_ALL_ACCESS, nullptr, 537 create_surface_handle_function_(COMPOSITIONOBJECT_ALL_ACCESS, nullptr,
475 &handle); 538 &handle);
476 swap_chain_handle_.Set(handle); 539 swap_chain_handle_.Set(handle);
477 540
478 is_yuy2_swapchain_ = true; 541 if (is_yuy2_swapchain_ != yuy2) {
542 UMA_HISTOGRAM_COUNTS_1000(
543 "GPU.DirectComposition.FramesSinceColorSpaceChange",
544 frames_since_color_space_change_);
545 }
546
547 frames_since_color_space_change_ = 0;
548
549 is_yuy2_swapchain_ = false;
479 // The composition surface handle isn't actually used, but 550 // The composition surface handle isn't actually used, but
480 // CreateSwapChainForComposition can't create YUY2 swapchains. 551 // CreateSwapChainForComposition can't create YUY2 swapchains.
481 HRESULT hr = media_factory->CreateSwapChainForCompositionSurfaceHandle( 552 HRESULT hr = E_FAIL;
482 d3d11_device_.get(), swap_chain_handle_.Get(), &desc, nullptr, 553 if (yuy2) {
483 swap_chain_.Receive()); 554 hr = media_factory->CreateSwapChainForCompositionSurfaceHandle(
555 d3d11_device_.get(), swap_chain_handle_.Get(), &desc, nullptr,
556 swap_chain_.Receive());
557 is_yuy2_swapchain_ = SUCCEEDED(hr);
558 failed_to_create_yuy2_swapchain_ = !is_yuy2_swapchain_;
559 }
484 560
485 if (FAILED(hr)) { 561 if (!is_yuy2_swapchain_) {
486 // This should not be hit in production but is a simple fallback for 562 if (yuy2) {
487 // testing on systems without YUY2 swapchain support. 563 DLOG(ERROR) << "YUY2 creation failed with " << std::hex << hr
488 DLOG(ERROR) << "YUY2 creation failed with " << std::hex << hr 564 << ". Falling back to BGRA";
489 << ". Falling back to BGRA"; 565 }
490 is_yuy2_swapchain_ = false;
491 desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; 566 desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
492 desc.Flags = 0; 567 desc.Flags = 0;
493 hr = media_factory->CreateSwapChainForCompositionSurfaceHandle( 568 hr = media_factory->CreateSwapChainForCompositionSurfaceHandle(
494 d3d11_device_.get(), swap_chain_handle_.Get(), &desc, nullptr, 569 d3d11_device_.get(), swap_chain_handle_.Get(), &desc, nullptr,
495 swap_chain_.Receive()); 570 swap_chain_.Receive());
496 CHECK(SUCCEEDED(hr)); 571 CHECK(SUCCEEDED(hr));
497 } 572 }
498 UMA_HISTOGRAM_BOOLEAN("GPU.DirectComposition.SwapchainFormat", 573 UMA_HISTOGRAM_BOOLEAN("GPU.DirectComposition.SwapchainFormat",
499 is_yuy2_swapchain_); 574 is_yuy2_swapchain_);
500 out_view_.Reset(); 575 out_view_.Reset();
(...skipping 560 matching lines...) Expand 10 before | Expand all | Expand 10 after
1061 DirectCompositionSurfaceWin::GetWindowTaskRunnerForTesting() { 1136 DirectCompositionSurfaceWin::GetWindowTaskRunnerForTesting() {
1062 return child_window_.GetTaskRunnerForTesting(); 1137 return child_window_.GetTaskRunnerForTesting();
1063 } 1138 }
1064 1139
1065 base::win::ScopedComPtr<IDXGISwapChain1> 1140 base::win::ScopedComPtr<IDXGISwapChain1>
1066 DirectCompositionSurfaceWin::GetLayerSwapChainForTesting(size_t index) const { 1141 DirectCompositionSurfaceWin::GetLayerSwapChainForTesting(size_t index) const {
1067 return layer_tree_->GetLayerSwapChainForTesting(index); 1142 return layer_tree_->GetLayerSwapChainForTesting(index);
1068 } 1143 }
1069 1144
1070 } // namespace gpu 1145 } // namespace gpu
OLDNEW
« no previous file with comments | « no previous file | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698