OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "ui/surface/accelerated_surface_win.h" | 5 #include "ui/surface/accelerated_surface_win.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 #include <algorithm> | 8 #include <algorithm> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
12 #include "base/callback.h" | 12 #include "base/callback.h" |
13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
14 #include "base/debug/trace_event.h" | 14 #include "base/debug/trace_event.h" |
15 #include "base/file_path.h" | 15 #include "base/file_path.h" |
16 #include "base/lazy_instance.h" | 16 #include "base/lazy_instance.h" |
17 #include "base/memory/scoped_ptr.h" | 17 #include "base/memory/scoped_ptr.h" |
18 #include "base/scoped_native_library.h" | 18 #include "base/scoped_native_library.h" |
19 #include "base/string_number_conversions.h" | 19 #include "base/string_number_conversions.h" |
20 #include "base/stringprintf.h" | 20 #include "base/stringprintf.h" |
21 #include "base/synchronization/waitable_event.h" | 21 #include "base/synchronization/waitable_event.h" |
22 #include "base/threading/thread.h" | 22 #include "base/threading/thread.h" |
23 #include "base/threading/thread_restrictions.h" | 23 #include "base/threading/thread_restrictions.h" |
24 #include "base/time.h" | 24 #include "base/time.h" |
25 #include "base/tracked_objects.h" | 25 #include "base/tracked_objects.h" |
26 #include "base/win/wrapped_window_proc.h" | 26 #include "base/win/wrapped_window_proc.h" |
27 #include "ui/base/win/hwnd_util.h" | 27 #include "ui/base/win/hwnd_util.h" |
| 28 #include "ui/gfx/rect.h" |
28 #include "ui/gl/gl_switches.h" | 29 #include "ui/gl/gl_switches.h" |
29 | 30 |
30 namespace { | 31 namespace { |
31 | 32 |
32 typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT sdk_version, | 33 typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT sdk_version, |
33 IDirect3D9Ex **d3d); | 34 IDirect3D9Ex **d3d); |
34 | 35 |
35 const wchar_t kD3D9ModuleName[] = L"d3d9.dll"; | 36 const wchar_t kD3D9ModuleName[] = L"d3d9.dll"; |
36 const char kCreate3D9DeviceExName[] = "Direct3DCreate9Ex"; | 37 const char kCreate3D9DeviceExName[] = "Direct3DCreate9Ex"; |
37 | 38 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 D3DDECL_END() | 111 D3DDECL_END() |
111 }; | 112 }; |
112 | 113 |
113 UINT GetPresentationInterval() { | 114 UINT GetPresentationInterval() { |
114 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync)) | 115 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync)) |
115 return D3DPRESENT_INTERVAL_IMMEDIATE; | 116 return D3DPRESENT_INTERVAL_IMMEDIATE; |
116 else | 117 else |
117 return D3DPRESENT_INTERVAL_ONE; | 118 return D3DPRESENT_INTERVAL_ONE; |
118 } | 119 } |
119 | 120 |
120 // Calculate the number necessary to transform |source_size| into |dest_size| | 121 // Calculate the number necessary to transform |src_subrect| into |dst_size| |
121 // by repeating downsampling of the image of |source_size| by a factor no more | 122 // by repeating downsampling of the image of |src_subrect| by a factor no more |
122 // than 2. | 123 // than 2. |
123 int GetResampleCount(const gfx::Size& source_size, const gfx::Size& dest_size) { | 124 int GetResampleCount(const gfx::Rect& src_subrect, |
| 125 const gfx::Size& dst_size, |
| 126 const gfx::Size& back_buffer_size) { |
| 127 if (src_subrect.size() == dst_size) { |
| 128 // Even when the size of |src_subrect| is equal to |dst_size|, it is |
| 129 // necessary to resample pixels at least once unless |src_subrect| exactly |
| 130 // covers the back buffer. |
| 131 return (src_subrect == gfx::Rect(back_buffer_size)) ? 0 : 1; |
| 132 } |
124 int width_count = 0; | 133 int width_count = 0; |
125 int width = source_size.width(); | 134 int width = src_subrect.width(); |
126 while (width > dest_size.width()) { | 135 while (width > dst_size.width()) { |
127 ++width_count; | 136 ++width_count; |
128 width >>= 1; | 137 width >>= 1; |
129 } | 138 } |
130 int height_count = 0; | 139 int height_count = 0; |
131 int height = source_size.height(); | 140 int height = src_subrect.height(); |
132 while (height > dest_size.height()) { | 141 while (height > dst_size.height()) { |
133 ++height_count; | 142 ++height_count; |
134 height >>= 1; | 143 height >>= 1; |
135 } | 144 } |
136 return std::max(width_count, height_count); | 145 return std::max(width_count, height_count); |
137 } | 146 } |
138 | 147 |
139 // Returns half the size of |size| no smaller than |min_size|. | 148 // Returns half the size of |size| no smaller than |min_size|. |
140 gfx::Size GetHalfSizeNoLessThan(const gfx::Size& size, | 149 gfx::Size GetHalfSizeNoLessThan(const gfx::Size& size, |
141 const gfx::Size& min_size) { | 150 const gfx::Size& min_size) { |
142 return gfx::Size(std::max(min_size.width(), size.width() / 2), | 151 return gfx::Size(std::max(min_size.width(), size.width() / 2), |
(...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
499 D3DPRESENT_INTERVAL_IMMEDIATE); | 508 D3DPRESENT_INTERVAL_IMMEDIATE); |
500 // For latency_tests.cc: | 509 // For latency_tests.cc: |
501 UNSHIPPED_TRACE_EVENT_INSTANT0("test_gpu", "CompositorSwapBuffersComplete"); | 510 UNSHIPPED_TRACE_EVENT_INSTANT0("test_gpu", "CompositorSwapBuffersComplete"); |
502 if (FAILED(hr)) | 511 if (FAILED(hr)) |
503 return false; | 512 return false; |
504 } | 513 } |
505 | 514 |
506 return true; | 515 return true; |
507 } | 516 } |
508 | 517 |
509 bool AcceleratedPresenter::CopyTo(const gfx::Size& size, void* buf) { | 518 bool AcceleratedPresenter::CopyTo(const gfx::Rect& src_subrect, |
| 519 const gfx::Size& dst_size, |
| 520 void* buf) { |
510 base::AutoLock locked(lock_); | 521 base::AutoLock locked(lock_); |
511 | 522 |
512 if (!swap_chain_) | 523 if (!swap_chain_) |
513 return false; | 524 return false; |
514 | 525 |
515 base::win::ScopedComPtr<IDirect3DSurface9> back_buffer; | 526 base::win::ScopedComPtr<IDirect3DSurface9> back_buffer; |
516 HRESULT hr = swap_chain_->GetBackBuffer(0, | 527 HRESULT hr = swap_chain_->GetBackBuffer(0, |
517 D3DBACKBUFFER_TYPE_MONO, | 528 D3DBACKBUFFER_TYPE_MONO, |
518 back_buffer.Receive()); | 529 back_buffer.Receive()); |
519 if (FAILED(hr)) | 530 if (FAILED(hr)) |
520 return false; | 531 return false; |
521 | 532 |
522 D3DSURFACE_DESC desc; | 533 D3DSURFACE_DESC desc; |
523 hr = back_buffer->GetDesc(&desc); | 534 hr = back_buffer->GetDesc(&desc); |
524 if (FAILED(hr)) | 535 if (FAILED(hr)) |
525 return false; | 536 return false; |
526 | 537 |
527 const gfx::Size back_buffer_size(desc.Width, desc.Height); | 538 const gfx::Size back_buffer_size(desc.Width, desc.Height); |
528 if (back_buffer_size.IsEmpty()) | 539 if (back_buffer_size.IsEmpty()) |
529 return false; | 540 return false; |
530 | 541 |
531 // Set up intermediate buffers needed for downsampling. | 542 // Set up intermediate buffers needed for downsampling. |
532 const int resample_count = | 543 const int resample_count = |
533 GetResampleCount(gfx::Size(desc.Width, desc.Height), size); | 544 GetResampleCount(src_subrect, dst_size, back_buffer_size); |
534 base::win::ScopedComPtr<IDirect3DSurface9> final_surface; | 545 base::win::ScopedComPtr<IDirect3DSurface9> final_surface; |
535 base::win::ScopedComPtr<IDirect3DSurface9> temp_buffer[2]; | 546 base::win::ScopedComPtr<IDirect3DSurface9> temp_buffer[2]; |
536 if (resample_count == 0) | 547 if (resample_count == 0) |
537 final_surface = back_buffer; | 548 final_surface = back_buffer; |
538 if (resample_count > 0) { | 549 if (resample_count > 0) { |
539 if (!CreateTemporarySurface(present_thread_->device(), | 550 if (!CreateTemporarySurface(present_thread_->device(), |
540 size, | 551 dst_size, |
541 final_surface.Receive())) | 552 final_surface.Receive())) |
542 return false; | 553 return false; |
543 } | 554 } |
544 const gfx::Size half_size = GetHalfSizeNoLessThan(back_buffer_size, size); | 555 const gfx::Size half_size = |
| 556 GetHalfSizeNoLessThan(src_subrect.size(), dst_size); |
545 if (resample_count > 1) { | 557 if (resample_count > 1) { |
546 if (!CreateTemporarySurface(present_thread_->device(), | 558 if (!CreateTemporarySurface(present_thread_->device(), |
547 half_size, | 559 half_size, |
548 temp_buffer[0].Receive())) | 560 temp_buffer[0].Receive())) |
549 return false; | 561 return false; |
550 } | 562 } |
551 if (resample_count > 2) { | 563 if (resample_count > 2) { |
552 const gfx::Size quarter_size = GetHalfSizeNoLessThan(half_size, size); | 564 const gfx::Size quarter_size = GetHalfSizeNoLessThan(half_size, dst_size); |
553 if (!CreateTemporarySurface(present_thread_->device(), | 565 if (!CreateTemporarySurface(present_thread_->device(), |
554 quarter_size, | 566 quarter_size, |
555 temp_buffer[1].Receive())) | 567 temp_buffer[1].Receive())) |
556 return false; | 568 return false; |
557 } | 569 } |
558 | 570 |
| 571 |
559 // Repeat downsampling the surface until its size becomes identical to | 572 // Repeat downsampling the surface until its size becomes identical to |
560 // |size|. We keep the factor of each downsampling no more than two because | 573 // |dst_size|. We keep the factor of each downsampling no more than two |
561 // using a factor more than two can introduce aliasing. | 574 // because using a factor more than two can introduce aliasing. |
562 gfx::Size read_size = back_buffer_size; | 575 RECT read_rect = src_subrect.ToRECT(); |
563 gfx::Size write_size = half_size; | 576 gfx::Size write_size = half_size; |
564 int read_buffer_index = 1; | 577 int read_buffer_index = 1; |
565 int write_buffer_index = 0; | 578 int write_buffer_index = 0; |
566 for (int i = 0; i < resample_count; ++i) { | 579 for (int i = 0; i < resample_count; ++i) { |
567 base::win::ScopedComPtr<IDirect3DSurface9> read_buffer = | 580 base::win::ScopedComPtr<IDirect3DSurface9> read_buffer = |
568 (i == 0) ? back_buffer : temp_buffer[read_buffer_index]; | 581 (i == 0) ? back_buffer : temp_buffer[read_buffer_index]; |
569 base::win::ScopedComPtr<IDirect3DSurface9> write_buffer = | 582 base::win::ScopedComPtr<IDirect3DSurface9> write_buffer = |
570 (i == resample_count - 1) ? final_surface : | 583 (i == resample_count - 1) ? final_surface : |
571 temp_buffer[write_buffer_index]; | 584 temp_buffer[write_buffer_index]; |
572 RECT read_rect = {0, 0, read_size.width(), read_size.height()}; | 585 RECT write_rect = gfx::Rect(write_size).ToRECT(); |
573 RECT write_rect = {0, 0, write_size.width(), write_size.height()}; | |
574 hr = present_thread_->device()->StretchRect(read_buffer, | 586 hr = present_thread_->device()->StretchRect(read_buffer, |
575 &read_rect, | 587 &read_rect, |
576 write_buffer, | 588 write_buffer, |
577 &write_rect, | 589 &write_rect, |
578 D3DTEXF_LINEAR); | 590 D3DTEXF_LINEAR); |
579 if (FAILED(hr)) | 591 if (FAILED(hr)) |
580 return false; | 592 return false; |
581 read_size = write_size; | 593 read_rect = write_rect; |
582 write_size = GetHalfSizeNoLessThan(write_size, size); | 594 write_size = GetHalfSizeNoLessThan(write_size, dst_size); |
583 std::swap(read_buffer_index, write_buffer_index); | 595 std::swap(read_buffer_index, write_buffer_index); |
584 } | 596 } |
585 | 597 |
586 DCHECK(size == read_size); | |
587 | |
588 base::win::ScopedComPtr<IDirect3DSurface9> temp_surface; | 598 base::win::ScopedComPtr<IDirect3DSurface9> temp_surface; |
589 HANDLE handle = reinterpret_cast<HANDLE>(buf); | 599 HANDLE handle = reinterpret_cast<HANDLE>(buf); |
590 hr = present_thread_->device()->CreateOffscreenPlainSurface( | 600 hr = present_thread_->device()->CreateOffscreenPlainSurface( |
591 size.width(), | 601 dst_size.width(), |
592 size.height(), | 602 dst_size.height(), |
593 D3DFMT_A8R8G8B8, | 603 D3DFMT_A8R8G8B8, |
594 D3DPOOL_SYSTEMMEM, | 604 D3DPOOL_SYSTEMMEM, |
595 temp_surface.Receive(), | 605 temp_surface.Receive(), |
596 &handle); | 606 &handle); |
597 if (FAILED(hr)) | 607 if (FAILED(hr)) |
598 return false; | 608 return false; |
599 | 609 |
600 // Copy the data in the temporary buffer to the surface backed by |buf|. | 610 // Copy the data in the temporary buffer to the surface backed by |buf|. |
601 hr = present_thread_->device()->GetRenderTargetData(final_surface, | 611 hr = present_thread_->device()->GetRenderTargetData(final_surface, |
602 temp_surface); | 612 temp_surface); |
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
840 | 850 |
841 AcceleratedSurface::~AcceleratedSurface() { | 851 AcceleratedSurface::~AcceleratedSurface() { |
842 g_accelerated_presenter_map.Pointer()->RemovePresenter(presenter_); | 852 g_accelerated_presenter_map.Pointer()->RemovePresenter(presenter_); |
843 presenter_->Invalidate(); | 853 presenter_->Invalidate(); |
844 } | 854 } |
845 | 855 |
846 bool AcceleratedSurface::Present(HDC dc) { | 856 bool AcceleratedSurface::Present(HDC dc) { |
847 return presenter_->Present(dc); | 857 return presenter_->Present(dc); |
848 } | 858 } |
849 | 859 |
850 bool AcceleratedSurface::CopyTo(const gfx::Size& size, void* buf) { | 860 bool AcceleratedSurface::CopyTo(const gfx::Rect& src_subrect, |
851 return presenter_->CopyTo(size, buf); | 861 const gfx::Size& dst_size, |
| 862 void* buf) { |
| 863 return presenter_->CopyTo(src_subrect, dst_size, buf); |
852 } | 864 } |
853 | 865 |
854 void AcceleratedSurface::Suspend() { | 866 void AcceleratedSurface::Suspend() { |
855 presenter_->Suspend(); | 867 presenter_->Suspend(); |
856 } | 868 } |
857 | 869 |
858 void AcceleratedSurface::WasHidden() { | 870 void AcceleratedSurface::WasHidden() { |
859 presenter_->WasHidden(); | 871 presenter_->WasHidden(); |
860 } | 872 } |
OLD | NEW |