summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorapatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-19 22:04:07 +0000
committerapatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-19 22:04:07 +0000
commit3d6306bce8a6081a322cb3b3161ecc468c7433e1 (patch)
tree923dcf738b752bdf1525c95343c4ec649f9ab8c3 /ui
parent5804cb5df6f3a5527be72ec8c89fef40e4621d03 (diff)
downloadchromium_src-3d6306bce8a6081a322cb3b3161ecc468c7433e1.zip
chromium_src-3d6306bce8a6081a322cb3b3161ecc468c7433e1.tar.gz
chromium_src-3d6306bce8a6081a322cb3b3161ecc468c7433e1.tar.bz2
Win accelerated surface recovers from a hung device.
It doesn't recover from a stopped device yet. That would require completely reinitializing D3D. Some cases also don't work yet. For example, if an async present fails, although it resets the device, it doesn't ask the renderer to produce a new frame. I'll hook that up to the completion callback or something. Review URL: http://codereview.chromium.org/8929020 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@115024 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r--ui/gfx/surface/accelerated_surface_win.cc59
-rw-r--r--ui/gfx/surface/accelerated_surface_win.h11
2 files changed, 46 insertions, 24 deletions
diff --git a/ui/gfx/surface/accelerated_surface_win.cc b/ui/gfx/surface/accelerated_surface_win.cc
index 2be4e80..50559aa 100644
--- a/ui/gfx/surface/accelerated_surface_win.cc
+++ b/ui/gfx/surface/accelerated_surface_win.cc
@@ -142,7 +142,7 @@ void AcceleratedSurface::AsyncPresentAndAcknowledge(
completion_task));
}
-void AcceleratedSurface::Present() {
+bool AcceleratedSurface::Present() {
TRACE_EVENT0("surface", "Present");
HRESULT hr;
@@ -150,11 +150,11 @@ void AcceleratedSurface::Present() {
base::AutoLock locked(lock_);
if (!device_)
- return;
+ return true;
RECT rect;
if (!GetClientRect(window_, &rect))
- return;
+ return true;
{
TRACE_EVENT0("surface", "PresentEx");
@@ -163,13 +163,26 @@ void AcceleratedSurface::Present() {
NULL,
NULL,
D3DPRESENT_INTERVAL_IMMEDIATE);
+
+ // If the device hung, force a resize to reset the device.
+ if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICEHUNG) {
+ base::AtomicRefCountInc(&num_pending_resizes_);
+ g_present_thread_pool.Pointer()->PostTask(
+ thread_affinity_,
+ FROM_HERE,
+ base::Bind(&AcceleratedSurface::DoReset, this));
+
+ // A device hang destroys the contents of the back buffer so no point in
+ // scheduling a present.
+ }
+
if (FAILED(hr))
- return;
+ return false;
}
hr = query_->Issue(D3DISSUE_END);
if (FAILED(hr))
- return;
+ return true;
{
TRACE_EVENT0("surface", "spin");
@@ -180,6 +193,8 @@ void AcceleratedSurface::Present() {
Sleep(0);
} while (hr == S_FALSE);
}
+
+ return true;
}
void AcceleratedSurface::DoInitialize() {
@@ -231,14 +246,6 @@ void AcceleratedSurface::DoInitialize() {
return;
}
-void AcceleratedSurface::QueriesDestroyed() {
- g_present_thread_pool.Pointer()->PostTask(
- thread_affinity_,
- FROM_HERE,
- base::Bind(&AcceleratedSurface::DoDestroy,
- this));
-}
-
void AcceleratedSurface::DoDestroy() {
TRACE_EVENT0("surface", "DoDestroy");
@@ -250,6 +257,12 @@ void AcceleratedSurface::DoDestroy() {
void AcceleratedSurface::DoResize(const gfx::Size& size) {
TRACE_EVENT0("surface", "DoResize");
+ size_ = size;
+ DoReset();
+}
+
+void AcceleratedSurface::DoReset() {
+ TRACE_EVENT0("surface", "DoReset");
HRESULT hr;
@@ -261,8 +274,8 @@ void AcceleratedSurface::DoResize(const gfx::Size& size) {
return;
D3DPRESENT_PARAMETERS parameters = { 0 };
- parameters.BackBufferWidth = size.width();
- parameters.BackBufferHeight = size.height();
+ parameters.BackBufferWidth = size_.width();
+ parameters.BackBufferHeight = size_.height();
parameters.BackBufferCount = 1;
parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
parameters.hDeviceWindow = window_;
@@ -275,8 +288,6 @@ void AcceleratedSurface::DoResize(const gfx::Size& size) {
if (FAILED(hr))
return;
- size_ = size;
-
device_->Clear(0, NULL, D3DCLEAR_TARGET, 0xFFFFFFFF, 0, 0);
}
@@ -380,7 +391,17 @@ void AcceleratedSurface::DoPresentAndAcknowledge(
{
TRACE_EVENT0("surface", "Present");
hr = device_->Present(&rect, &rect, NULL, NULL);
- if (FAILED(hr))
- return;
+
+ // If the device hung, force a resize to reset the device.
+ if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICEHUNG) {
+ base::AtomicRefCountInc(&num_pending_resizes_);
+ g_present_thread_pool.Pointer()->PostTask(
+ thread_affinity_,
+ FROM_HERE,
+ base::Bind(&AcceleratedSurface::DoReset, this));
+
+ // A device hang destroys the contents of the back buffer so no point in
+ // scheduling a present.
+ }
}
}
diff --git a/ui/gfx/surface/accelerated_surface_win.h b/ui/gfx/surface/accelerated_surface_win.h
index b526deb..593972b 100644
--- a/ui/gfx/surface/accelerated_surface_win.h
+++ b/ui/gfx/surface/accelerated_surface_win.h
@@ -35,13 +35,13 @@ class SURFACE_EXPORT AcceleratedSurface
const base::Closure& completion_task);
// Synchronously present a frame with no acknowledgement.
- void Present();
+ bool Present();
private:
void DoInitialize();
- void QueriesDestroyed();
void DoDestroy();
void DoResize(const gfx::Size& size);
+ void DoReset();
void DoPresentAndAcknowledge(const gfx::Size& size,
int64 surface_id,
const base::Closure& completion_task);
@@ -55,6 +55,10 @@ class SURFACE_EXPORT AcceleratedSurface
// Only accessed on the UI thread so the lock is unnecessary.
gfx::Size pending_size_;
+ // The current size of the swap chain. This is only accessed on the thread
+ // with which the surface has affinity.
+ gfx::Size size_;
+
// The number of pending resizes. This is accessed with atomic operations so
// the lock is not necessary.
base::AtomicRefCount num_pending_resizes_;
@@ -71,9 +75,6 @@ class SURFACE_EXPORT AcceleratedSurface
// texture again.
base::win::ScopedComPtr<IDirect3DQuery9> query_;
- // The current size of the swap chain.
- gfx::Size size_;
-
DISALLOW_COPY_AND_ASSIGN(AcceleratedSurface);
};