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

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: improve 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 history_;
sunnyps 2017/04/11 23:19:29 nit: 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 (!history_.valid())
331 return true;
332 int composition_count = 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 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 hr = video_context_->VideoProcessorBlt(video_processor_.get(), 466 hr = video_context_->VideoProcessorBlt(video_processor_.get(),
407 out_view_.get(), 0, 1, &stream); 467 out_view_.get(), 0, 1, &stream);
408 CHECK(SUCCEEDED(hr)); 468 CHECK(SUCCEEDED(hr));
409 } 469 }
410 470
411 swap_chain_scale_x_ = bounds_rect.width() * 1.0f / swap_chain_size.width(); 471 swap_chain_scale_x_ = bounds_rect.width() * 1.0f / swap_chain_size.width();
412 swap_chain_scale_y_ = bounds_rect.height() * 1.0f / swap_chain_size.height(); 472 swap_chain_scale_y_ = bounds_rect.height() * 1.0f / swap_chain_size.height();
413 473
414 swap_chain_->Present(first_present ? 0 : 1, 0); 474 swap_chain_->Present(first_present ? 0 : 1, 0);
415 475
476 frames_since_color_space_change_++;
477
416 base::win::ScopedComPtr<IDXGISwapChainMedia> swap_chain_media; 478 base::win::ScopedComPtr<IDXGISwapChainMedia> swap_chain_media;
417 if (SUCCEEDED(swap_chain_.QueryInterface(swap_chain_media.Receive()))) { 479 if (SUCCEEDED(swap_chain_.QueryInterface(swap_chain_media.Receive()))) {
418 DXGI_FRAME_STATISTICS_MEDIA stats = {}; 480 DXGI_FRAME_STATISTICS_MEDIA stats = {};
419 if (SUCCEEDED(swap_chain_media->GetFrameStatisticsMedia(&stats))) { 481 if (SUCCEEDED(swap_chain_media->GetFrameStatisticsMedia(&stats))) {
420 UMA_HISTOGRAM_SPARSE_SLOWLY("GPU.DirectComposition.CompositionMode", 482 UMA_HISTOGRAM_SPARSE_SLOWLY("GPU.DirectComposition.CompositionMode",
421 stats.CompositionMode); 483 stats.CompositionMode);
484 history_.AddSample(stats.CompositionMode);
422 } 485 }
423 } 486 }
424 } 487 }
425 488
426 bool DCLayerTree::SwapChainPresenter::InitializeVideoProcessor( 489 bool DCLayerTree::SwapChainPresenter::InitializeVideoProcessor(
427 const gfx::Size& in_size, 490 const gfx::Size& in_size,
428 const gfx::Size& out_size) { 491 const gfx::Size& out_size) {
429 if (video_processor_ && SizeContains(processor_input_size_, in_size) && 492 if (video_processor_ && SizeContains(processor_input_size_, in_size) &&
430 SizeContains(processor_output_size_, out_size)) 493 SizeContains(processor_output_size_, out_size))
431 return false; 494 return false;
432 processor_input_size_ = in_size; 495 processor_input_size_ = in_size;
433 processor_output_size_ = out_size; 496 processor_output_size_ = out_size;
434 surface_->InitializeVideoProcessor(in_size, out_size); 497 surface_->InitializeVideoProcessor(in_size, out_size);
435 498
436 video_processor_enumerator_ = surface_->video_processor_enumerator(); 499 video_processor_enumerator_ = surface_->video_processor_enumerator();
437 video_processor_ = surface_->video_processor(); 500 video_processor_ = surface_->video_processor();
438 // out_view_ depends on video_processor_enumerator_, so ensure it's 501 // out_view_ depends on video_processor_enumerator_, so ensure it's
439 // recreated if the enumerator is. 502 // recreated if the enumerator is.
440 out_view_.Reset(); 503 out_view_.Reset();
441 return true; 504 return true;
442 } 505 }
443 506
444 void DCLayerTree::SwapChainPresenter::ReallocateSwapChain() { 507 void DCLayerTree::SwapChainPresenter::ReallocateSwapChain(bool yuy2) {
445 TRACE_EVENT0("gpu", "DCLayerTree::SwapChainPresenter::ReallocateSwapChain"); 508 TRACE_EVENT0("gpu", "DCLayerTree::SwapChainPresenter::ReallocateSwapChain");
446 DCHECK(!swap_chain_); 509 DCHECK(!swap_chain_);
447 510
448 base::win::ScopedComPtr<IDXGIDevice> dxgi_device; 511 base::win::ScopedComPtr<IDXGIDevice> dxgi_device;
449 d3d11_device_.QueryInterface(dxgi_device.Receive()); 512 d3d11_device_.QueryInterface(dxgi_device.Receive());
450 base::win::ScopedComPtr<IDXGIAdapter> dxgi_adapter; 513 base::win::ScopedComPtr<IDXGIAdapter> dxgi_adapter;
451 dxgi_device->GetAdapter(dxgi_adapter.Receive()); 514 dxgi_device->GetAdapter(dxgi_adapter.Receive());
452 base::win::ScopedComPtr<IDXGIFactory2> dxgi_factory; 515 base::win::ScopedComPtr<IDXGIFactory2> dxgi_factory;
453 dxgi_adapter->GetParent(IID_PPV_ARGS(dxgi_factory.Receive())); 516 dxgi_adapter->GetParent(IID_PPV_ARGS(dxgi_factory.Receive()));
454 517
(...skipping 11 matching lines...) Expand all
466 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; 529 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
467 desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; 530 desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
468 desc.Flags = 531 desc.Flags =
469 DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO | DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO; 532 DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO | DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO;
470 533
471 HANDLE handle; 534 HANDLE handle;
472 create_surface_handle_function_(COMPOSITIONOBJECT_ALL_ACCESS, nullptr, 535 create_surface_handle_function_(COMPOSITIONOBJECT_ALL_ACCESS, nullptr,
473 &handle); 536 &handle);
474 swap_chain_handle_.Set(handle); 537 swap_chain_handle_.Set(handle);
475 538
539 if (is_yuy2_swapchain_ != yuy2) {
540 UMA_HISTOGRAM_COUNTS_1000(
541 "GPU.DirectComposition.FramesSinceColorSpaceChange",
542 frames_since_color_space_change_);
543 }
544
545 frames_since_color_space_change_ = 0;
546
476 is_yuy2_swapchain_ = true; 547 is_yuy2_swapchain_ = true;
477 // The composition surface handle isn't actually used, but 548 // The composition surface handle isn't actually used, but
478 // CreateSwapChainForComposition can't create YUY2 swapchains. 549 // CreateSwapChainForComposition can't create YUY2 swapchains.
479 HRESULT hr = media_factory->CreateSwapChainForCompositionSurfaceHandle( 550 HRESULT hr = E_FAIL;
sunnyps 2017/04/11 23:19:30 nit: can you rewrite to something like this: is_y
480 d3d11_device_.get(), swap_chain_handle_.Get(), &desc, nullptr, 551 if (yuy2) {
481 swap_chain_.Receive()); 552 hr = media_factory->CreateSwapChainForCompositionSurfaceHandle(
553 d3d11_device_.get(), swap_chain_handle_.Get(), &desc, nullptr,
554 swap_chain_.Receive());
555 failed_to_create_yuy2_swapchain_ = FAILED(hr);
556 }
482 557
483 if (FAILED(hr)) { 558 if (FAILED(hr)) {
484 // This should not be hit in production but is a simple fallback for 559 // 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.
485 // testing on systems without YUY2 swapchain support. 560 // testing on systems without YUY2 swapchain support.
486 DLOG(ERROR) << "YUY2 creation failed with " << std::hex << hr 561 DLOG(ERROR) << "YUY2 creation failed with " << std::hex << hr
487 << ". Falling back to BGRA"; 562 << ". Falling back to BGRA";
488 is_yuy2_swapchain_ = false; 563 is_yuy2_swapchain_ = false;
489 desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; 564 desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
490 desc.Flags = 0; 565 desc.Flags = 0;
491 hr = media_factory->CreateSwapChainForCompositionSurfaceHandle( 566 hr = media_factory->CreateSwapChainForCompositionSurfaceHandle(
492 d3d11_device_.get(), swap_chain_handle_.Get(), &desc, nullptr, 567 d3d11_device_.get(), swap_chain_handle_.Get(), &desc, nullptr,
493 swap_chain_.Receive()); 568 swap_chain_.Receive());
494 CHECK(SUCCEEDED(hr)); 569 CHECK(SUCCEEDED(hr));
(...skipping 567 matching lines...) Expand 10 before | Expand all | Expand 10 after
1062 DirectCompositionSurfaceWin::GetWindowTaskRunnerForTesting() { 1137 DirectCompositionSurfaceWin::GetWindowTaskRunnerForTesting() {
1063 return child_window_.GetTaskRunnerForTesting(); 1138 return child_window_.GetTaskRunnerForTesting();
1064 } 1139 }
1065 1140
1066 base::win::ScopedComPtr<IDXGISwapChain1> 1141 base::win::ScopedComPtr<IDXGISwapChain1>
1067 DirectCompositionSurfaceWin::GetLayerSwapChainForTesting(size_t index) const { 1142 DirectCompositionSurfaceWin::GetLayerSwapChainForTesting(size_t index) const {
1068 return layer_tree_->GetLayerSwapChainForTesting(index); 1143 return layer_tree_->GetLayerSwapChainForTesting(index);
1069 } 1144 }
1070 1145
1071 } // namespace gpu 1146 } // 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