OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |