Commit 4f646165 authored by mazda@chromium.org's avatar mazda@chromium.org

Support copying a partial rectangle region from the compositing surface on Win.

BUG=118571
TEST=Manual


Review URL: https://chromiumcodereview.appspot.com/10829054

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@148889 0039d316-1c4b-4281-b951-d872f2087c98
parent 1d65f485
...@@ -503,14 +503,8 @@ void RenderWidgetHostImpl::CopyFromBackingStore( ...@@ -503,14 +503,8 @@ void RenderWidgetHostImpl::CopyFromBackingStore(
if (view_ && is_accelerated_compositing_active_) { if (view_ && is_accelerated_compositing_active_) {
TRACE_EVENT0("browser", TRACE_EVENT0("browser",
"RenderWidgetHostImpl::CopyFromBackingStore::FromCompositingSurface"); "RenderWidgetHostImpl::CopyFromBackingStore::FromCompositingSurface");
#if defined(USE_AURA) || defined(OS_LINUX) || defined(OS_MACOSX)
gfx::Rect copy_rect = src_subrect.IsEmpty() ? gfx::Rect copy_rect = src_subrect.IsEmpty() ?
gfx::Rect(view_->GetViewBounds().size()) : src_subrect; gfx::Rect(view_->GetViewBounds().size()) : src_subrect;
#else
// Just passes an empty rect to CopyFromCompositingSurface on non-Aura Win
// because copying a partial rectangle is not supported.
gfx::Rect copy_rect;
#endif
view_->CopyFromCompositingSurface(copy_rect, view_->CopyFromCompositingSurface(copy_rect,
accelerated_dst_size, accelerated_dst_size,
callback, callback,
......
...@@ -1199,13 +1199,6 @@ void RenderWidgetHostViewWin::CopyFromCompositingSurface( ...@@ -1199,13 +1199,6 @@ void RenderWidgetHostViewWin::CopyFromCompositingSurface(
const base::Callback<void(bool)>& callback, const base::Callback<void(bool)>& callback,
skia::PlatformCanvas* output) { skia::PlatformCanvas* output) {
base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false)); base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false));
// TODO(mazda): Support copying a partial rectangle from the compositing
// surface with |src_subrect| (http://crbug.com/118571).
if (!src_subrect.IsEmpty()) {
NOTIMPLEMENTED();
return;
}
if (!accelerated_surface_.get()) if (!accelerated_surface_.get())
return; return;
...@@ -1216,7 +1209,9 @@ void RenderWidgetHostViewWin::CopyFromCompositingSurface( ...@@ -1216,7 +1209,9 @@ void RenderWidgetHostViewWin::CopyFromCompositingSurface(
return; return;
const bool result = accelerated_surface_->CopyTo( const bool result = accelerated_surface_->CopyTo(
dst_size, output->getTopDevice()->accessBitmap(true).getPixels()); src_subrect,
dst_size,
output->getTopDevice()->accessBitmap(true).getPixels());
scoped_callback_runner.Release(); scoped_callback_runner.Release();
callback.Run(result); callback.Run(result);
} }
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "base/tracked_objects.h" #include "base/tracked_objects.h"
#include "base/win/wrapped_window_proc.h" #include "base/win/wrapped_window_proc.h"
#include "ui/base/win/hwnd_util.h" #include "ui/base/win/hwnd_util.h"
#include "ui/gfx/rect.h"
#include "ui/gl/gl_switches.h" #include "ui/gl/gl_switches.h"
namespace { namespace {
...@@ -117,19 +118,27 @@ UINT GetPresentationInterval() { ...@@ -117,19 +118,27 @@ UINT GetPresentationInterval() {
return D3DPRESENT_INTERVAL_ONE; return D3DPRESENT_INTERVAL_ONE;
} }
// Calculate the number necessary to transform |source_size| into |dest_size| // Calculate the number necessary to transform |src_subrect| into |dst_size|
// by repeating downsampling of the image of |source_size| by a factor no more // by repeating downsampling of the image of |src_subrect| by a factor no more
// than 2. // than 2.
int GetResampleCount(const gfx::Size& source_size, const gfx::Size& dest_size) { int GetResampleCount(const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
const gfx::Size& back_buffer_size) {
if (src_subrect.size() == dst_size) {
// Even when the size of |src_subrect| is equal to |dst_size|, it is
// necessary to resample pixels at least once unless |src_subrect| exactly
// covers the back buffer.
return (src_subrect == gfx::Rect(back_buffer_size)) ? 0 : 1;
}
int width_count = 0; int width_count = 0;
int width = source_size.width(); int width = src_subrect.width();
while (width > dest_size.width()) { while (width > dst_size.width()) {
++width_count; ++width_count;
width >>= 1; width >>= 1;
} }
int height_count = 0; int height_count = 0;
int height = source_size.height(); int height = src_subrect.height();
while (height > dest_size.height()) { while (height > dst_size.height()) {
++height_count; ++height_count;
height >>= 1; height >>= 1;
} }
...@@ -506,7 +515,9 @@ bool AcceleratedPresenter::DoRealPresent(HDC dc) ...@@ -506,7 +515,9 @@ bool AcceleratedPresenter::DoRealPresent(HDC dc)
return true; return true;
} }
bool AcceleratedPresenter::CopyTo(const gfx::Size& size, void* buf) { bool AcceleratedPresenter::CopyTo(const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
void* buf) {
base::AutoLock locked(lock_); base::AutoLock locked(lock_);
if (!swap_chain_) if (!swap_chain_)
...@@ -530,18 +541,19 @@ bool AcceleratedPresenter::CopyTo(const gfx::Size& size, void* buf) { ...@@ -530,18 +541,19 @@ bool AcceleratedPresenter::CopyTo(const gfx::Size& size, void* buf) {
// Set up intermediate buffers needed for downsampling. // Set up intermediate buffers needed for downsampling.
const int resample_count = const int resample_count =
GetResampleCount(gfx::Size(desc.Width, desc.Height), size); GetResampleCount(src_subrect, dst_size, back_buffer_size);
base::win::ScopedComPtr<IDirect3DSurface9> final_surface; base::win::ScopedComPtr<IDirect3DSurface9> final_surface;
base::win::ScopedComPtr<IDirect3DSurface9> temp_buffer[2]; base::win::ScopedComPtr<IDirect3DSurface9> temp_buffer[2];
if (resample_count == 0) if (resample_count == 0)
final_surface = back_buffer; final_surface = back_buffer;
if (resample_count > 0) { if (resample_count > 0) {
if (!CreateTemporarySurface(present_thread_->device(), if (!CreateTemporarySurface(present_thread_->device(),
size, dst_size,
final_surface.Receive())) final_surface.Receive()))
return false; return false;
} }
const gfx::Size half_size = GetHalfSizeNoLessThan(back_buffer_size, size); const gfx::Size half_size =
GetHalfSizeNoLessThan(src_subrect.size(), dst_size);
if (resample_count > 1) { if (resample_count > 1) {
if (!CreateTemporarySurface(present_thread_->device(), if (!CreateTemporarySurface(present_thread_->device(),
half_size, half_size,
...@@ -549,17 +561,18 @@ bool AcceleratedPresenter::CopyTo(const gfx::Size& size, void* buf) { ...@@ -549,17 +561,18 @@ bool AcceleratedPresenter::CopyTo(const gfx::Size& size, void* buf) {
return false; return false;
} }
if (resample_count > 2) { if (resample_count > 2) {
const gfx::Size quarter_size = GetHalfSizeNoLessThan(half_size, size); const gfx::Size quarter_size = GetHalfSizeNoLessThan(half_size, dst_size);
if (!CreateTemporarySurface(present_thread_->device(), if (!CreateTemporarySurface(present_thread_->device(),
quarter_size, quarter_size,
temp_buffer[1].Receive())) temp_buffer[1].Receive()))
return false; return false;
} }
// Repeat downsampling the surface until its size becomes identical to // Repeat downsampling the surface until its size becomes identical to
// |size|. We keep the factor of each downsampling no more than two because // |dst_size|. We keep the factor of each downsampling no more than two
// using a factor more than two can introduce aliasing. // because using a factor more than two can introduce aliasing.
gfx::Size read_size = back_buffer_size; RECT read_rect = src_subrect.ToRECT();
gfx::Size write_size = half_size; gfx::Size write_size = half_size;
int read_buffer_index = 1; int read_buffer_index = 1;
int write_buffer_index = 0; int write_buffer_index = 0;
...@@ -569,8 +582,7 @@ bool AcceleratedPresenter::CopyTo(const gfx::Size& size, void* buf) { ...@@ -569,8 +582,7 @@ bool AcceleratedPresenter::CopyTo(const gfx::Size& size, void* buf) {
base::win::ScopedComPtr<IDirect3DSurface9> write_buffer = base::win::ScopedComPtr<IDirect3DSurface9> write_buffer =
(i == resample_count - 1) ? final_surface : (i == resample_count - 1) ? final_surface :
temp_buffer[write_buffer_index]; temp_buffer[write_buffer_index];
RECT read_rect = {0, 0, read_size.width(), read_size.height()}; RECT write_rect = gfx::Rect(write_size).ToRECT();
RECT write_rect = {0, 0, write_size.width(), write_size.height()};
hr = present_thread_->device()->StretchRect(read_buffer, hr = present_thread_->device()->StretchRect(read_buffer,
&read_rect, &read_rect,
write_buffer, write_buffer,
...@@ -578,18 +590,16 @@ bool AcceleratedPresenter::CopyTo(const gfx::Size& size, void* buf) { ...@@ -578,18 +590,16 @@ bool AcceleratedPresenter::CopyTo(const gfx::Size& size, void* buf) {
D3DTEXF_LINEAR); D3DTEXF_LINEAR);
if (FAILED(hr)) if (FAILED(hr))
return false; return false;
read_size = write_size; read_rect = write_rect;
write_size = GetHalfSizeNoLessThan(write_size, size); write_size = GetHalfSizeNoLessThan(write_size, dst_size);
std::swap(read_buffer_index, write_buffer_index); std::swap(read_buffer_index, write_buffer_index);
} }
DCHECK(size == read_size);
base::win::ScopedComPtr<IDirect3DSurface9> temp_surface; base::win::ScopedComPtr<IDirect3DSurface9> temp_surface;
HANDLE handle = reinterpret_cast<HANDLE>(buf); HANDLE handle = reinterpret_cast<HANDLE>(buf);
hr = present_thread_->device()->CreateOffscreenPlainSurface( hr = present_thread_->device()->CreateOffscreenPlainSurface(
size.width(), dst_size.width(),
size.height(), dst_size.height(),
D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8,
D3DPOOL_SYSTEMMEM, D3DPOOL_SYSTEMMEM,
temp_surface.Receive(), temp_surface.Receive(),
...@@ -847,8 +857,10 @@ bool AcceleratedSurface::Present(HDC dc) { ...@@ -847,8 +857,10 @@ bool AcceleratedSurface::Present(HDC dc) {
return presenter_->Present(dc); return presenter_->Present(dc);
} }
bool AcceleratedSurface::CopyTo(const gfx::Size& size, void* buf) { bool AcceleratedSurface::CopyTo(const gfx::Rect& src_subrect,
return presenter_->CopyTo(size, buf); const gfx::Size& dst_size,
void* buf) {
return presenter_->CopyTo(src_subrect, dst_size, buf);
} }
void AcceleratedSurface::Suspend() { void AcceleratedSurface::Suspend() {
......
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
class PresentThread; class PresentThread;
namespace gfx {
class Rect;
}
class SURFACE_EXPORT AcceleratedPresenter class SURFACE_EXPORT AcceleratedPresenter
: public base::RefCountedThreadSafe<AcceleratedPresenter> { : public base::RefCountedThreadSafe<AcceleratedPresenter> {
public: public:
...@@ -52,7 +56,9 @@ class SURFACE_EXPORT AcceleratedPresenter ...@@ -52,7 +56,9 @@ class SURFACE_EXPORT AcceleratedPresenter
// The public member functions are called on the main thread. // The public member functions are called on the main thread.
bool Present(HDC dc); bool Present(HDC dc);
bool CopyTo(const gfx::Size& size, void* buf); bool CopyTo(const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
void* buf);
void Invalidate(); void Invalidate();
private: private:
...@@ -115,11 +121,14 @@ class SURFACE_EXPORT AcceleratedSurface { ...@@ -115,11 +121,14 @@ class SURFACE_EXPORT AcceleratedSurface {
// Synchronously present a frame with no acknowledgement. // Synchronously present a frame with no acknowledgement.
bool Present(HDC dc); bool Present(HDC dc);
// Copies the surface data to |buf|. The image data is transformed so that it // Copies the surface data to |buf|. The copied region is specified with
// fits in |size|. // |src_subrect| and the image data is transformed so that it fits in
// |dst_size|.
// Caller must ensure that |buf| is allocated with the size no less than // Caller must ensure that |buf| is allocated with the size no less than
// |4 * size.width() * size.height()| bytes. // |4 * dst_size.width() * dst_size.height()| bytes.
bool CopyTo(const gfx::Size& size, void* buf); bool CopyTo(const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
void* buf);
// Temporarily release resources until a new surface is asynchronously // Temporarily release resources until a new surface is asynchronously
// presented. Present will not be able to represent the last surface after // presented. Present will not be able to represent the last surface after
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment