diff options
Diffstat (limited to 'ui/gfx/surface')
-rw-r--r-- | ui/gfx/surface/accelerated_surface_win.cc | 188 | ||||
-rw-r--r-- | ui/gfx/surface/accelerated_surface_win.h | 63 |
2 files changed, 152 insertions, 99 deletions
diff --git a/ui/gfx/surface/accelerated_surface_win.cc b/ui/gfx/surface/accelerated_surface_win.cc index 29f8993..9845f8f 100644 --- a/ui/gfx/surface/accelerated_surface_win.cc +++ b/ui/gfx/surface/accelerated_surface_win.cc @@ -4,6 +4,7 @@ #include "ui/gfx/surface/accelerated_surface_win.h" +#include <d3d9.h> #include <windows.h> #include <list> @@ -14,11 +15,16 @@ #include "base/debug/trace_event.h" #include "base/file_path.h" #include "base/lazy_instance.h" +#include "base/memory/linked_ptr.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" #include "base/memory/weak_ptr.h" +#include "base/scoped_native_library.h" #include "base/stringprintf.h" +#include "base/synchronization/lock.h" #include "base/threading/thread.h" #include "base/tracked_objects.h" +#include "base/win/scoped_comptr.h" #include "base/win/wrapped_window_proc.h" #include "ipc/ipc_message.h" #include "ui/base/win/hwnd_util.h" @@ -54,6 +60,9 @@ class PresentThreadPool { base::LazyInstance<PresentThreadPool> g_present_thread_pool = LAZY_INSTANCE_INITIALIZER; +base::LazyInstance<std::vector<linked_ptr<AcceleratedPresenter> > > + g_unused_accelerated_presenters; + PresentThreadPool::PresentThreadPool() : next_thread_(0) { for (int i = 0; i < kNumPresentThreads; ++i) { present_threads_[i].reset(new base::Thread( @@ -85,32 +94,78 @@ UINT GetPresentationInterval() { } // namespace anonymous -AcceleratedSurface::AcceleratedSurface(HWND parent) - : thread_affinity_(g_present_thread_pool.Pointer()->NextThread()), - window_(parent), - num_pending_resizes_(0) { -} +class AcceleratedPresenter { + public: + AcceleratedPresenter(); + ~AcceleratedPresenter(); -AcceleratedSurface::~AcceleratedSurface() { - // Destroy should have been called prior to the last reference going away. - DCHECK(!device_); -} + void AsyncPresentAndAcknowledge(gfx::NativeWindow window, + const gfx::Size& size, + int64 surface_id, + const base::Closure& completion_task); + + bool Present(gfx::NativeWindow window); + + void Suspend(); + + private: + void DoInitialize(); + void DoResize(const gfx::Size& size); + void DoReset(); + void DoPresentAndAcknowledge(gfx::NativeWindow window, + const gfx::Size& size, + int64 surface_id, + const base::Closure& completion_task); + + // Immutable and accessible from any thread without the lock. + const int thread_affinity_; + base::ScopedNativeLibrary d3d_module_; + + // The size of the swap chain once any pending resizes have been processed. + // 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_; + + // Take the lock before accessing any other state. + base::Lock lock_; + + // This device's swap chain is presented to the child window. Copy semantics + // are used so it is possible to represent it to quickly validate the window. + base::win::ScopedComPtr<IDirect3DDevice9Ex> device_; + + // This query is used to wait until a certain amount of progress has been + // made by the GPU and it is safe for the producer to modify its shared + // texture again. + base::win::ScopedComPtr<IDirect3DQuery9> query_; + + DISALLOW_COPY_AND_ASSIGN(AcceleratedPresenter); +}; -void AcceleratedSurface::Initialize() { +AcceleratedPresenter::AcceleratedPresenter() + : thread_affinity_(g_present_thread_pool.Pointer()->NextThread()), + num_pending_resizes_(0) { g_present_thread_pool.Pointer()->PostTask( thread_affinity_, FROM_HERE, - base::Bind(&AcceleratedSurface::DoInitialize, this)); + base::Bind(&AcceleratedPresenter::DoInitialize, base::Unretained(this))); } -void AcceleratedSurface::Destroy() { - g_present_thread_pool.Pointer()->PostTask( - thread_affinity_, - FROM_HERE, - base::Bind(&AcceleratedSurface::DoDestroy, this)); +AcceleratedPresenter::~AcceleratedPresenter() { + // The D3D device and query are leaked because destroying the associated D3D + // query crashes some Intel drivers. + device_.Detach(); + query_.Detach(); } -void AcceleratedSurface::AsyncPresentAndAcknowledge( +void AcceleratedPresenter::AsyncPresentAndAcknowledge( + gfx::NativeWindow window, const gfx::Size& size, int64 surface_id, const base::Closure& completion_task) { @@ -126,7 +181,9 @@ void AcceleratedSurface::AsyncPresentAndAcknowledge( g_present_thread_pool.Pointer()->PostTask( thread_affinity_, FROM_HERE, - base::Bind(&AcceleratedSurface::DoResize, this, quantized_size)); + base::Bind(&AcceleratedPresenter::DoResize, + base::Unretained(this), + quantized_size)); } // This might unnecessarily post to the thread with which the swap chain has @@ -135,14 +192,15 @@ void AcceleratedSurface::AsyncPresentAndAcknowledge( num_pending_resizes_ ? thread_affinity_ : g_present_thread_pool.Pointer()->NextThread(), FROM_HERE, - base::Bind(&AcceleratedSurface::DoPresentAndAcknowledge, - this, + base::Bind(&AcceleratedPresenter::DoPresentAndAcknowledge, + base::Unretained(this), + window, size, surface_id, completion_task)); } -bool AcceleratedSurface::Present() { +bool AcceleratedPresenter::Present(gfx::NativeWindow window) { TRACE_EVENT0("surface", "Present"); HRESULT hr; @@ -153,14 +211,14 @@ bool AcceleratedSurface::Present() { return true; RECT rect; - if (!GetClientRect(window_, &rect)) + if (!GetClientRect(window, &rect)) return true; { TRACE_EVENT0("surface", "PresentEx"); hr = device_->PresentEx(&rect, &rect, - NULL, + window, NULL, D3DPRESENT_INTERVAL_IMMEDIATE); @@ -170,7 +228,7 @@ bool AcceleratedSurface::Present() { g_present_thread_pool.Pointer()->PostTask( thread_affinity_, FROM_HERE, - base::Bind(&AcceleratedSurface::DoReset, this)); + base::Bind(&AcceleratedPresenter::DoReset, base::Unretained(this))); // A device hang destroys the contents of the back buffer so no point in // scheduling a present. @@ -197,7 +255,21 @@ bool AcceleratedSurface::Present() { return true; } -void AcceleratedSurface::DoInitialize() { +void AcceleratedPresenter::Suspend() { + // Resize the swap chain to 1 x 1 to save memory while the presenter is not + // in use. + pending_size_ = gfx::Size(1, 1); + base::AtomicRefCountInc(&num_pending_resizes_); + + g_present_thread_pool.Pointer()->PostTask( + thread_affinity_, + FROM_HERE, + base::Bind(&AcceleratedPresenter::DoResize, + base::Unretained(this), + gfx::Size(1, 1))); +} + +void AcceleratedPresenter::DoInitialize() { TRACE_EVENT0("surface", "DoInitialize"); HRESULT hr; @@ -214,12 +286,16 @@ void AcceleratedSurface::DoInitialize() { if (FAILED(hr)) return; + // Any old window will do to create the device. In practice the window to + // present to is an argument to IDirect3DDevice9::Present. + HWND window = GetShellWindow(); + D3DPRESENT_PARAMETERS parameters = { 0 }; parameters.BackBufferWidth = 1; parameters.BackBufferHeight = 1; parameters.BackBufferCount = 1; parameters.BackBufferFormat = D3DFMT_A8R8G8B8; - parameters.hDeviceWindow = window_; + parameters.hDeviceWindow = window; parameters.Windowed = TRUE; parameters.Flags = 0; parameters.PresentationInterval = GetPresentationInterval(); @@ -228,7 +304,7 @@ void AcceleratedSurface::DoInitialize() { hr = d3d->CreateDeviceEx( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, - window_, + window, D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED, ¶meters, @@ -246,22 +322,13 @@ void AcceleratedSurface::DoInitialize() { return; } -void AcceleratedSurface::DoDestroy() { - TRACE_EVENT0("surface", "DoDestroy"); - - base::AutoLock locked(lock_); - - query_ = NULL; - device_ = NULL; -} - -void AcceleratedSurface::DoResize(const gfx::Size& size) { +void AcceleratedPresenter::DoResize(const gfx::Size& size) { TRACE_EVENT0("surface", "DoResize"); size_ = size; DoReset(); } -void AcceleratedSurface::DoReset() { +void AcceleratedPresenter::DoReset() { TRACE_EVENT0("surface", "DoReset"); HRESULT hr; @@ -273,12 +340,14 @@ void AcceleratedSurface::DoReset() { if (!device_) return; + gfx::NativeWindow window = GetShellWindow(); + D3DPRESENT_PARAMETERS parameters = { 0 }; parameters.BackBufferWidth = size_.width(); parameters.BackBufferHeight = size_.height(); parameters.BackBufferCount = 1; parameters.BackBufferFormat = D3DFMT_A8R8G8B8; - parameters.hDeviceWindow = window_; + parameters.hDeviceWindow = window; parameters.Windowed = TRUE; parameters.Flags = 0; parameters.PresentationInterval = GetPresentationInterval(); @@ -291,7 +360,8 @@ void AcceleratedSurface::DoReset() { device_->Clear(0, NULL, D3DCLEAR_TARGET, 0xFFFFFFFF, 0, 0); } -void AcceleratedSurface::DoPresentAndAcknowledge( +void AcceleratedPresenter::DoPresentAndAcknowledge( + gfx::NativeWindow window, const gfx::Size& size, int64 surface_id, const base::Closure& completion_task) { @@ -307,9 +377,6 @@ void AcceleratedSurface::DoPresentAndAcknowledge( if (!device_) return; - if (!window_) - return; - HANDLE handle = reinterpret_cast<HANDLE>(surface_id); if (!handle) return; @@ -364,7 +431,7 @@ void AcceleratedSurface::DoPresentAndAcknowledge( query_->GetData(NULL, 0, D3DGETDATA_FLUSH); ::SetWindowPos( - window_, + window, NULL, 0, 0, size.width(), size.height(), @@ -390,7 +457,7 @@ void AcceleratedSurface::DoPresentAndAcknowledge( { TRACE_EVENT0("surface", "Present"); - hr = device_->Present(&rect, &rect, NULL, NULL); + hr = device_->Present(&rect, &rect, window, NULL); // If the device hung, force a resize to reset the device. if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICEHUNG) { @@ -398,10 +465,39 @@ void AcceleratedSurface::DoPresentAndAcknowledge( g_present_thread_pool.Pointer()->PostTask( thread_affinity_, FROM_HERE, - base::Bind(&AcceleratedSurface::DoReset, this)); + base::Bind(&AcceleratedPresenter::DoReset, base::Unretained(this))); // A device hang destroys the contents of the back buffer so no point in // scheduling a present. } } } + +AcceleratedSurface::AcceleratedSurface() { + if (g_unused_accelerated_presenters.Pointer()->empty()) { + presenter_.reset(new AcceleratedPresenter); + } else { + presenter_ = g_unused_accelerated_presenters.Pointer()->back(); + g_unused_accelerated_presenters.Pointer()->pop_back(); + } +} + +AcceleratedSurface::~AcceleratedSurface() { + presenter_->Suspend(); + g_unused_accelerated_presenters.Pointer()->push_back(presenter_); +} + +void AcceleratedSurface::AsyncPresentAndAcknowledge( + HWND window, + const gfx::Size& size, + int64 surface_id, + const base::Closure& completion_task) { + presenter_->AsyncPresentAndAcknowledge(window, + size, + surface_id, + completion_task); +} + +bool AcceleratedSurface::Present(HWND window) { + return presenter_->Present(window); +} diff --git a/ui/gfx/surface/accelerated_surface_win.h b/ui/gfx/surface/accelerated_surface_win.h index 593972b..a2b6c66 100644 --- a/ui/gfx/surface/accelerated_surface_win.h +++ b/ui/gfx/surface/accelerated_surface_win.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,75 +6,32 @@ #define UI_GFX_SURFACE_ACCELERATED_SURFACE_WIN_H_ #pragma once -#include <d3d9.h> - #include "base/callback_forward.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop_proxy.h" -#include "base/scoped_native_library.h" -#include "base/synchronization/lock.h" -#include "base/win/scoped_comptr.h" +#include "base/memory/linked_ptr.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/size.h" #include "ui/gfx/surface/surface_export.h" -class SURFACE_EXPORT AcceleratedSurface - : public base::RefCountedThreadSafe<AcceleratedSurface> { +class AcceleratedPresenter; + +class SURFACE_EXPORT AcceleratedSurface { public: - explicit AcceleratedSurface(gfx::NativeWindow parent); + AcceleratedSurface(); ~AcceleratedSurface(); - void Initialize(); - void Destroy(); - // Schedule a frame to be presented. The completion callback will be invoked // when it is safe to write to the surface on another thread. The lock for // this surface will be held while the completion callback runs. - void AsyncPresentAndAcknowledge(const gfx::Size& size, + void AsyncPresentAndAcknowledge(HWND window, + const gfx::Size& size, int64 surface_id, const base::Closure& completion_task); // Synchronously present a frame with no acknowledgement. - bool Present(); + bool Present(HWND window); private: - void DoInitialize(); - void DoDestroy(); - void DoResize(const gfx::Size& size); - void DoReset(); - void DoPresentAndAcknowledge(const gfx::Size& size, - int64 surface_id, - const base::Closure& completion_task); - - // Immutable and accessible from any thread without the lock. - const int thread_affinity_; - const gfx::NativeWindow window_; - base::ScopedNativeLibrary d3d_module_; - - // The size of the swap chain once any pending resizes have been processed. - // 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_; - - // Take the lock before accessing any other state. - base::Lock lock_; - - // This device's swap chain is presented to the child window. Copy semantics - // are used so it is possible to represent it to quickly validate the window. - base::win::ScopedComPtr<IDirect3DDevice9Ex> device_; - - // This query is used to wait until a certain amount of progress has been - // made by the GPU and it is safe for the producer to modify its shared - // texture again. - base::win::ScopedComPtr<IDirect3DQuery9> query_; - + linked_ptr<AcceleratedPresenter> presenter_; DISALLOW_COPY_AND_ASSIGN(AcceleratedSurface); }; |