Index: ui/gfx/surface/accelerated_surface_win.cc |
diff --git a/ui/gfx/surface/accelerated_surface_win.cc b/ui/gfx/surface/accelerated_surface_win.cc |
index 4edc1ee332eb367f6d45813fd488653e42889933..005d6749d156482fe4ca55e139a9858d1fc24a65 100644 |
--- a/ui/gfx/surface/accelerated_surface_win.cc |
+++ b/ui/gfx/surface/accelerated_surface_win.cc |
@@ -5,6 +5,7 @@ |
#include "ui/gfx/surface/accelerated_surface_win.h" |
#include <windows.h> |
+#include <algorithm> |
#include "base/bind.h" |
#include "base/bind_helpers.h" |
@@ -145,6 +146,82 @@ void PresentThread::ResetDevice() { |
} |
} |
+bool AcceleratedPresenter::CopyTo(const gfx::Size& size, |
+ std::vector<unsigned char>* buf) { |
+ base::AutoLock locked(lock_); |
+ |
+ base::win::ScopedComPtr<IDirect3DSurface9> temp_buffer[2]; |
+ HRESULT hr = swap_chain_->GetBackBuffer(0, |
apatrick_chromium
2012/03/08 20:15:47
swap_chain_ will be null if either no surface has
mazda
2012/03/10 07:51:37
Done.
|
+ D3DBACKBUFFER_TYPE_MONO, |
+ temp_buffer[0].Receive()); |
+ if (FAILED(hr)) |
+ return false; |
+ |
+ D3DSURFACE_DESC desc; |
+ hr = temp_buffer[0]->GetDesc(&desc); |
+ if (FAILED(hr) || (desc.Width == 0) || (desc.Height == 0)) |
+ return false; |
+ |
+ // Repeat downsampling the surface until its size becomes identical to |
+ // |size|. We keep the factor of each downsampling no more than two because |
+ // using a factor more than two can introduce aliasing. |
+ int buffer_width = desc.Width; |
+ int buffer_height = desc.Height; |
+ int read_buffer = 0; |
+ int write_buffer = 1; |
+ do { |
apatrick_chromium
2012/03/08 20:15:47
I believe it is possible to call GetRenderTargetDa
mazda
2012/03/10 07:51:37
Done.
|
+ buffer_width = std::max(buffer_width / 2, size.width()); |
+ buffer_height = std::max(buffer_height / 2, size.height()); |
+ temp_buffer[write_buffer].Release(); |
+ hr = present_thread_->device()->CreateRenderTarget( |
vangelis
2012/03/08 17:34:35
Can we avoid creating render targets for all inter
mazda
2012/03/10 07:51:37
Done.
|
+ buffer_width, |
+ buffer_height, |
+ D3DFMT_A8R8G8B8, |
+ D3DMULTISAMPLE_NONE, |
+ 0, |
+ TRUE, |
+ temp_buffer[write_buffer].Receive(), |
+ NULL); |
+ if (FAILED(hr)) |
+ return false; |
+ |
+ hr = present_thread_->device()->StretchRect(temp_buffer[read_buffer], |
+ NULL, |
+ temp_buffer[write_buffer], |
+ NULL, |
+ D3DTEXF_LINEAR); |
+ if (FAILED(hr)) |
+ return false; |
+ |
+ std::swap(read_buffer, write_buffer); |
+ } while (size != gfx::Size(buffer_width, buffer_height)); |
+ |
+ const size_t buf_size = static_cast<size_t>(4 * size.GetArea()); |
+ if (buf->size() < buf_size) { |
+ buf->resize(buf_size); |
+ } |
+ |
+ base::win::ScopedComPtr<IDirect3DSurface9> temp_surface; |
+ HANDLE handle = reinterpret_cast<HANDLE>(&(*buf)[0]); |
+ hr = present_thread_->device()->CreateOffscreenPlainSurface( |
+ size.width(), |
+ size.height(), |
+ D3DFMT_A8R8G8B8, |
+ D3DPOOL_SYSTEMMEM, |
+ temp_surface.Receive(), |
+ &handle); |
+ if (FAILED(hr)) |
+ return false; |
+ |
+ // Copy the data in the temporary buffer to the surface backed by |buf|. |
+ hr = present_thread_->device()->GetRenderTargetData( |
+ temp_buffer[read_buffer], temp_surface); |
+ if (FAILED(hr)) |
+ return false; |
+ |
+ return true; |
+} |
+ |
void PresentThread::Init() { |
TRACE_EVENT0("surface", "PresentThread::Init"); |
d3d_module_.Reset(base::LoadNativeLibrary(FilePath(kD3D9ModuleName), NULL)); |
@@ -431,8 +508,12 @@ bool AcceleratedSurface::Present(HWND window) { |
return false; |
} |
+bool AcceleratedSurface::CopyTo(const gfx::Size& size, |
+ std::vector<unsigned char>* buf) { |
+ return presenter_->CopyTo(size, buf); |
+} |
+ |
void AcceleratedSurface::Suspend() { |
if (presenter_) |
presenter_->Suspend(); |
} |
- |