Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(388)

Unified Diff: ui/gfx/surface/accelerated_surface_win.cc

Issue 9582003: Support browser side thumbnailing for GPU composited pages on Windows. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/gfx/surface/accelerated_surface_win.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 adff364ca6d72257de6031caac998330811b0f00..bf24711fbfdda452774b25fbd62b9a3b2800a622 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"
@@ -38,6 +39,47 @@ UINT GetPresentationInterval() {
return D3DPRESENT_INTERVAL_ONE;
}
+// Calculate the number necessary to transform |source_size| into |dest_size|
+// by repeating downsampling of the image of |source_size| by a factor no more
+// than 2.
+int GetResampleCount(const gfx::Size& source_size, const gfx::Size& dest_size) {
+ int width_count = 0;
+ int width = source_size.width();
+ while (width > dest_size.width()) {
+ ++width_count;
+ width >>= 1;
+ }
+ int height_count = 0;
+ int height = source_size.height();
+ while (height > dest_size.height()) {
+ ++height_count;
+ height >>= 1;
+ }
+ return std::max(width_count, height_count);
+}
+
+// Returns half the size of |size| no smaller than |min_size|.
+gfx::Size GetHalfSizeNoLessThan(const gfx::Size& size,
+ const gfx::Size& min_size) {
+ return gfx::Size(std::max(min_size.width(), size.width() / 2),
+ std::max(min_size.height(), size.height() / 2));
+}
+
+bool CreateTemporarySurface(IDirect3DDevice9* device,
+ const gfx::Size& size,
+ IDirect3DSurface9** surface) {
+ HRESULT hr = device->CreateRenderTarget(
+ size.width(),
+ size.height(),
+ D3DFMT_A8R8G8B8,
+ D3DMULTISAMPLE_NONE,
+ 0,
+ TRUE,
+ surface,
+ NULL);
+ return SUCCEEDED(hr);
+}
+
} // namespace anonymous
// A PresentThread is a thread that is dedicated to presenting surfaces to a
@@ -240,6 +282,106 @@ bool AcceleratedPresenter::Present(gfx::NativeWindow window) {
return true;
}
+bool AcceleratedPresenter::CopyTo(const gfx::Size& size, void* buf) {
+ base::AutoLock locked(lock_);
+
+ if (!swap_chain_)
+ return false;
+
+ base::win::ScopedComPtr<IDirect3DSurface9> back_buffer;
+ HRESULT hr = swap_chain_->GetBackBuffer(0,
+ D3DBACKBUFFER_TYPE_MONO,
+ back_buffer.Receive());
+ if (FAILED(hr))
+ return false;
+
+ D3DSURFACE_DESC desc;
+ hr = back_buffer->GetDesc(&desc);
+ if (FAILED(hr))
+ return false;
+
+ const gfx::Size back_buffer_size(desc.Width, desc.Height);
+ if (back_buffer_size.IsEmpty())
+ return false;
+
+ // Set up intermediate buffers needed for downsampling.
+ const int resample_count =
+ GetResampleCount(gfx::Size(desc.Width, desc.Height), size);
+ base::win::ScopedComPtr<IDirect3DSurface9> final_surface;
+ base::win::ScopedComPtr<IDirect3DSurface9> temp_buffer[2];
+ if (resample_count == 0)
+ final_surface = back_buffer;
+ if (resample_count > 0) {
+ if (!CreateTemporarySurface(present_thread_->device(),
+ size,
+ final_surface.Receive()))
+ return false;
+ }
+ const gfx::Size half_size = GetHalfSizeNoLessThan(back_buffer_size, size);
+ if (resample_count > 1) {
+ if (!CreateTemporarySurface(present_thread_->device(),
+ half_size,
+ temp_buffer[0].Receive()))
+ return false;
+ }
+ if (resample_count > 2) {
+ const gfx::Size quarter_size = GetHalfSizeNoLessThan(half_size, size);
+ if (!CreateTemporarySurface(present_thread_->device(),
+ quarter_size,
+ temp_buffer[1].Receive()))
+ 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.
+ gfx::Size read_size = back_buffer_size;
+ gfx::Size write_size = half_size;
+ int read_buffer_index = 1;
+ int write_buffer_index = 0;
+ for (int i = 0; i < resample_count; ++i) {
+ base::win::ScopedComPtr<IDirect3DSurface9> read_buffer =
+ (i == 0) ? back_buffer : temp_buffer[read_buffer_index];
+ base::win::ScopedComPtr<IDirect3DSurface9> write_buffer =
+ (i == resample_count - 1) ? final_surface :
+ temp_buffer[write_buffer_index];
+ RECT read_rect = {0, 0, read_size.width(), read_size.height()};
+ RECT write_rect = {0, 0, write_size.width(), write_size.height()};
+ hr = present_thread_->device()->StretchRect(read_buffer,
+ &read_rect,
+ write_buffer,
+ &write_rect,
+ D3DTEXF_LINEAR);
+ if (FAILED(hr))
+ return false;
+ read_size = write_size;
+ write_size = GetHalfSizeNoLessThan(write_size, size);
+ std::swap(read_buffer_index, write_buffer_index);
+ }
+
+ DCHECK(size == read_size);
+
+ base::win::ScopedComPtr<IDirect3DSurface9> temp_surface;
+ HANDLE handle = reinterpret_cast<HANDLE>(buf);
+ 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(final_surface,
+ temp_surface);
+ if (FAILED(hr))
+ return false;
+
+ return true;
+}
+
void AcceleratedPresenter::Suspend() {
present_thread_->message_loop()->PostTask(
FROM_HERE,
@@ -444,7 +586,10 @@ bool AcceleratedSurface::Present(HWND window) {
return presenter_->Present(window);
}
+bool AcceleratedSurface::CopyTo(const gfx::Size& size, void* buf) {
+ return presenter_->CopyTo(size, buf);
+}
+
void AcceleratedSurface::Suspend() {
presenter_->Suspend();
}
-
« no previous file with comments | « ui/gfx/surface/accelerated_surface_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698