summaryrefslogtreecommitdiffstats
path: root/ui/surface
diff options
context:
space:
mode:
authorapatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-04 01:43:56 +0000
committerapatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-04 01:43:56 +0000
commitd830fd4d83c1170ed2413308da48c0096bfd562e (patch)
treef88fc8c92aaadd5a084eaa8706620cb62180d48f /ui/surface
parent8d790d6a43fed99c3614634410f226f8497f30bc (diff)
downloadchromium_src-d830fd4d83c1170ed2413308da48c0096bfd562e.zip
chromium_src-d830fd4d83c1170ed2413308da48c0096bfd562e.tar.gz
chromium_src-d830fd4d83c1170ed2413308da48c0096bfd562e.tar.bz2
Windows: AcceleratedSurface presents with GDI while the window is being resized.
Presenting with Direct3D while the window resizes causes regions of the top level window that are rendered with GDI, like the title bar, to flicker visible / invisible. So use GDI across the board when resizing and switch back to Direct3D afterwards. BUG=120904 Review URL: https://chromiumcodereview.appspot.com/10990119 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@160042 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/surface')
-rw-r--r--ui/surface/accelerated_surface_win.cc196
-rw-r--r--ui/surface/accelerated_surface_win.h23
2 files changed, 135 insertions, 84 deletions
diff --git a/ui/surface/accelerated_surface_win.cc b/ui/surface/accelerated_surface_win.cc
index 78777b0..e3f1dca 100644
--- a/ui/surface/accelerated_surface_win.cc
+++ b/ui/surface/accelerated_surface_win.cc
@@ -234,6 +234,7 @@ class AcceleratedPresenterMap {
void RemovePresenter(const scoped_refptr<AcceleratedPresenter>& presenter);
scoped_refptr<AcceleratedPresenter> GetPresenter(
gfx::PluginWindowHandle window);
+
private:
base::Lock lock_;
typedef std::map<gfx::PluginWindowHandle, AcceleratedPresenter*> PresenterMap;
@@ -457,85 +458,20 @@ void AcceleratedPresenter::AsyncPresentAndAcknowledge(
completion_task));
}
-bool AcceleratedPresenter::Present(HDC dc) {
+void AcceleratedPresenter::Present(HDC dc) {
TRACE_EVENT0("gpu", "Present");
- bool result;
-
- present_thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&AcceleratedPresenter::DoPresent,
- this,
- dc,
- &result));
- // http://crbug.com/125391
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
- event_.Wait();
- return result;
-}
-
-void AcceleratedPresenter::DoPresent(HDC dc, bool* result)
-{
- *result = DoRealPresent(dc);
- event_.Signal();
-}
-
-bool AcceleratedPresenter::DoRealPresent(HDC dc)
-{
- TRACE_EVENT0("gpu", "DoRealPresent");
- HRESULT hr;
-
base::AutoLock locked(lock_);
// If invalidated, do nothing. The window is gone.
if (!window_)
- return true;
-
-
- RECT window_rect;
- GetClientRect(window_, &window_rect);
- if (window_rect.right != present_size_.width() ||
- window_rect.bottom != present_size_.height()) {
- // If the window is a different size than the swap chain that was previously
- // presented and it is becoming visible then signal the caller to
- // recomposite at the new size.
- if (hidden_)
- return false;
-
- HBRUSH brush = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
- RECT fill_rect = window_rect;
- fill_rect.top = present_size_.height();
- FillRect(dc, &fill_rect, brush);
- fill_rect = window_rect;
- fill_rect.left = present_size_.width();
- fill_rect.bottom = present_size_.height();
- FillRect(dc, &fill_rect, brush);
- }
+ return;
- // Signal the caller to recomposite if the presenter has been suspended or no
- // surface has ever been presented.
+ // Suspended or nothing has ever been presented.
if (!swap_chain_)
- return false;
-
- RECT present_rect = {
- 0, 0,
- present_size_.width(), present_size_.height()
- };
-
- {
- TRACE_EVENT0("gpu", "PresentEx");
- hr = swap_chain_->Present(&present_rect,
- &present_rect,
- window_,
- NULL,
- D3DPRESENT_INTERVAL_IMMEDIATE);
- // For latency_tests.cc:
- UNSHIPPED_TRACE_EVENT_INSTANT0("test_gpu", "CompositorSwapBuffersComplete");
- if (FAILED(hr))
- return false;
- }
+ return;
- return true;
+ PresentWithGDI(dc);
}
bool AcceleratedPresenter::CopyTo(const gfx::Rect& src_subrect,
@@ -722,15 +658,13 @@ void AcceleratedPresenter::DoPresentAndAcknowledge(
#if !defined(USE_AURA)
// If the window is a different size than the swap chain that is being
// presented then drop the frame.
- RECT window_rect;
- GetClientRect(window_, &window_rect);
- if (hidden_ && (window_rect.right != size.width() ||
- window_rect.bottom != size.height())) {
+ gfx::Size window_size = GetWindowSize();
+ if (hidden_ && size != window_size) {
TRACE_EVENT2("gpu", "EarlyOut_WrongWindowSize",
"backwidth", size.width(), "backheight", size.height());
TRACE_EVENT2("gpu", "EarlyOut_WrongWindowSize2",
- "windowwidth", window_rect.right,
- "windowheight", window_rect.bottom);
+ "windowwidth", window_size.width(),
+ "windowheight", window_size.height());
return;
}
#endif
@@ -856,15 +790,24 @@ void AcceleratedPresenter::DoPresentAndAcknowledge(
if (swap_delay.ToInternalValue())
base::PlatformThread::Sleep(swap_delay);
- {
- TRACE_EVENT0("gpu", "Present");
+ // If it is expected that Direct3D cannot be used reliably because the window
+ // is resizing, fall back to presenting with GDI.
+ if (CheckDirect3DWillWork()) {
+ TRACE_EVENT0("gpu", "PresentD3D");
+
hr = swap_chain_->Present(&rect, &rect, window_, NULL, 0);
+
// For latency_tests.cc:
UNSHIPPED_TRACE_EVENT_INSTANT0("test_gpu", "CompositorSwapBuffersComplete");
+
if (FAILED(hr) &&
FAILED(present_thread_->device()->CheckDeviceState(window_))) {
present_thread_->ResetDevice();
}
+ } else {
+ HDC dc = GetDC(window_);
+ PresentWithGDI(dc);
+ ReleaseDC(window_, dc);
}
hidden_ = false;
@@ -928,6 +871,99 @@ void AcceleratedPresenter::DoReleaseSurface() {
source_texture_.Release();
}
+void AcceleratedPresenter::PresentWithGDI(HDC dc) {
+ TRACE_EVENT0("gpu", "PresentWithGDI");
+
+ base::win::ScopedComPtr<IDirect3DTexture9> system_texture;
+ {
+ TRACE_EVENT0("gpu", "CreateSystemTexture");
+ HRESULT hr = present_thread_->device()->CreateTexture(
+ quantized_size_.width(),
+ quantized_size_.height(),
+ 1,
+ 0,
+ D3DFMT_A8R8G8B8,
+ D3DPOOL_SYSTEMMEM,
+ system_texture.Receive(),
+ NULL);
+ if (FAILED(hr))
+ return;
+ }
+
+ base::win::ScopedComPtr<IDirect3DSurface9> system_surface;
+ HRESULT hr = system_texture->GetSurfaceLevel(0, system_surface.Receive());
+ DCHECK(SUCCEEDED(hr));
+
+ base::win::ScopedComPtr<IDirect3DSurface9> back_buffer;
+ hr = swap_chain_->GetBackBuffer(0,
+ D3DBACKBUFFER_TYPE_MONO,
+ back_buffer.Receive());
+ DCHECK(SUCCEEDED(hr));
+
+ {
+ TRACE_EVENT0("gpu", "GetRenderTargetData");
+ hr = present_thread_->device()->GetRenderTargetData(back_buffer,
+ system_surface);
+ DCHECK(SUCCEEDED(hr));
+ }
+
+ D3DLOCKED_RECT locked_surface;
+ hr = system_surface->LockRect(&locked_surface, NULL, D3DLOCK_READONLY);
+ DCHECK(SUCCEEDED(hr));
+
+ BITMAPINFO bitmap_info = {
+ {
+ sizeof(BITMAPINFOHEADER),
+ quantized_size_.width(),
+ -quantized_size_.height(),
+ 1, // planes
+ 32, // bitcount
+ BI_RGB
+ },
+ {
+ {0, 0, 0, 0}
+ }
+ };
+
+ {
+ TRACE_EVENT0("gpu", "StretchDIBits");
+ StretchDIBits(dc,
+ 0, 0,
+ present_size_.width(),
+ present_size_.height(),
+ 0, 0,
+ present_size_.width(),
+ present_size_.height(),
+ locked_surface.pBits,
+ &bitmap_info,
+ DIB_RGB_COLORS,
+ SRCCOPY);
+ }
+
+ system_surface->UnlockRect();
+
+ // For latency_tests.cc:
+ UNSHIPPED_TRACE_EVENT_INSTANT0("test_gpu", "CompositorSwapBuffersComplete");
+}
+
+gfx::Size AcceleratedPresenter::GetWindowSize() {
+ RECT rect;
+ GetClientRect(window_, &rect);
+ return gfx::Rect(rect).size();
+}
+
+bool AcceleratedPresenter::CheckDirect3DWillWork() {
+ gfx::Size window_size = GetWindowSize();
+ if (window_size != last_window_size_) {
+ last_window_size_ = window_size;
+ last_window_resize_time_ = base::Time::Now();
+ return false;
+ }
+
+ return base::Time::Now() - last_window_resize_time_ >
+ base::TimeDelta::FromMilliseconds(100);
+}
+
AcceleratedSurface::AcceleratedSurface(gfx::PluginWindowHandle window)
: presenter_(g_accelerated_presenter_map.Pointer()->CreatePresenter(
window)) {
@@ -938,8 +974,8 @@ AcceleratedSurface::~AcceleratedSurface() {
presenter_->Invalidate();
}
-bool AcceleratedSurface::Present(HDC dc) {
- return presenter_->Present(dc);
+void AcceleratedSurface::Present(HDC dc) {
+ presenter_->Present(dc);
}
bool AcceleratedSurface::CopyTo(const gfx::Rect& src_subrect,
diff --git a/ui/surface/accelerated_surface_win.h b/ui/surface/accelerated_surface_win.h
index 20c8f9e..5fc3de0 100644
--- a/ui/surface/accelerated_surface_win.h
+++ b/ui/surface/accelerated_surface_win.h
@@ -57,7 +57,7 @@ class SURFACE_EXPORT AcceleratedPresenter
void ReleaseSurface();
// The public member functions are called on the main thread.
- bool Present(HDC dc);
+ void Present(HDC dc);
bool CopyTo(const gfx::Rect& src_subrect,
const gfx::Size& dst_size,
void* buf);
@@ -81,10 +81,18 @@ class SURFACE_EXPORT AcceleratedPresenter
int64 surface_handle,
const CompletionTask& completion_task);
void DoSuspend();
- void DoPresent(HDC dc, bool* presented);
- bool DoRealPresent(HDC dc);
+ void DoPresent(const base::Closure& composite_task);
void DoReleaseSurface();
+ void PresentWithGDI(HDC dc);
+ gfx::Size GetWindowSize();
+
+ // This function tries to guess whether Direct3D will be able to reliably
+ // present to the window. When the window is resizing, presenting with
+ // Direct3D causes other regions of the window rendered with GDI to
+ // flicker transparent / non-transparent.
+ bool CheckDirect3DWillWork();
+
// The thread with which this presenter has affinity.
PresentThread* const present_thread_;
@@ -120,6 +128,13 @@ class SURFACE_EXPORT AcceleratedPresenter
// last hidden.
bool hidden_;
+ // These are used to detect when the window is resizing. For some reason,
+ // presenting with D3D while the window resizes causes those parts not
+ // drawn with D3D (e.g. with GDI) to flicker visible / invisible.
+ // http://crbug.com/120904
+ gfx::Size last_window_size_;
+ base::Time last_window_resize_time_;
+
DISALLOW_COPY_AND_ASSIGN(AcceleratedPresenter);
};
@@ -129,7 +144,7 @@ class SURFACE_EXPORT AcceleratedSurface {
~AcceleratedSurface();
// Synchronously present a frame with no acknowledgement.
- bool Present(HDC dc);
+ void Present(HDC dc);
// Copies the surface data to |buf|. The copied region is specified with
// |src_subrect| and the image data is transformed so that it fits in