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