| 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 |