diff options
author | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-20 22:51:48 +0000 |
---|---|---|
committer | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-20 22:51:48 +0000 |
commit | 85cd621132aca61852db935cf91baf7f53395084 (patch) | |
tree | c45e9529a8bd26a40600791c9a943f65f3e5930e /ui/gfx/surface | |
parent | 1ea8143aeeb5b9b464b67397ebe637e7731ea564 (diff) | |
download | chromium_src-85cd621132aca61852db935cf91baf7f53395084.zip chromium_src-85cd621132aca61852db935cf91baf7f53395084.tar.gz chromium_src-85cd621132aca61852db935cf91baf7f53395084.tar.bz2 |
Windows: Added AcceleratedPresenterMap.
This is a thread safe mapping from window handle to the associated AcceleratorPresenter that maintains the window's swap chain. The mapping was previously maintained by the GpuSurfaceTracker (via the surface ID). I changed it because I think is is possible the GpuSurfaceTracker's AcceleratedSurface pointer was going dangling.
I made PresentThread reference counted and made each AcceleratedPresenter ref count it's PresentThread so the PresentThread's message loop are always a valid place to post tasks.
Since other threads can post tasks to the AcceleratedPresenter at any time, I changed the shutdown of AcceleratedSurface to simply invalidate the presenter rather than waiting for its pending tasks to complete, which probably wasn't sufficient.
I renamed surface_id to surface_handle for consistency with the rest of the code.
BUG=117453
Review URL: https://chromiumcodereview.appspot.com/9704075
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@127821 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/gfx/surface')
-rw-r--r-- | ui/gfx/surface/accelerated_surface_win.cc | 182 | ||||
-rw-r--r-- | ui/gfx/surface/accelerated_surface_win.h | 49 |
2 files changed, 144 insertions, 87 deletions
diff --git a/ui/gfx/surface/accelerated_surface_win.cc b/ui/gfx/surface/accelerated_surface_win.cc index de749b36..f2a05bd 100644 --- a/ui/gfx/surface/accelerated_surface_win.cc +++ b/ui/gfx/surface/accelerated_surface_win.cc @@ -84,10 +84,10 @@ bool CreateTemporarySurface(IDirect3DDevice9* device, // A PresentThread is a thread that is dedicated to presenting surfaces to a // window. It owns a Direct3D device and a Direct3D query for this purpose. -class PresentThread : public base::Thread { +class PresentThread : public base::Thread, + public base::RefCountedThreadSafe<PresentThread> { public: - PresentThread(const char* name); - ~PresentThread(); + explicit PresentThread(const char* name); IDirect3DDevice9* device() { return device_.get(); } IDirect3DQuery9* query() { return query_.get(); } @@ -99,6 +99,10 @@ class PresentThread : public base::Thread { virtual void CleanUp(); private: + friend class base::RefCountedThreadSafe<PresentThread>; + + ~PresentThread(); + base::ScopedNativeLibrary d3d_module_; base::win::ScopedComPtr<IDirect3DDevice9Ex> device_; @@ -121,19 +125,33 @@ class PresentThreadPool { private: int next_thread_; - scoped_ptr<PresentThread> present_threads_[kNumPresentThreads]; + scoped_refptr<PresentThread> present_threads_[kNumPresentThreads]; DISALLOW_COPY_AND_ASSIGN(PresentThreadPool); }; +// A thread safe map of presenters by surface ID that returns presenters via +// a scoped_refptr to keep them alive while they are referenced. +class AcceleratedPresenterMap { + public: + AcceleratedPresenterMap(); + scoped_refptr<AcceleratedPresenter> CreatePresenter(gfx::NativeWindow window); + void RemovePresenter(const scoped_refptr<AcceleratedPresenter>& presenter); + scoped_refptr<AcceleratedPresenter> GetPresenter(gfx::NativeWindow window); + private: + base::Lock lock_; + typedef std::map<gfx::NativeWindow, AcceleratedPresenter*> PresenterMap; + PresenterMap presenters_; + DISALLOW_COPY_AND_ASSIGN(AcceleratedPresenterMap); +}; + base::LazyInstance<PresentThreadPool> g_present_thread_pool = LAZY_INSTANCE_INITIALIZER; -PresentThread::PresentThread(const char* name) : base::Thread(name) { -} +base::LazyInstance<AcceleratedPresenterMap> + g_accelerated_presenter_map = LAZY_INSTANCE_INITIALIZER; -PresentThread::~PresentThread() { - Stop(); +PresentThread::PresentThread(const char* name) : base::Thread(name) { } void PresentThread::InitDevice() { @@ -202,12 +220,16 @@ void PresentThread::CleanUp() { query_.Detach(); } +PresentThread::~PresentThread() { + Stop(); +} + PresentThreadPool::PresentThreadPool() : next_thread_(0) { // Do this in the constructor so present_threads_ is initialized before any // other thread sees it. See LazyInstance documentation. for (int i = 0; i < kNumPresentThreads; ++i) { - present_threads_[i].reset(new PresentThread( - base::StringPrintf("PresentThread #%d", i).c_str())); + present_threads_[i] = new PresentThread( + base::StringPrintf("PresentThread #%d", i).c_str()); present_threads_[i]->Start(); } } @@ -217,26 +239,75 @@ PresentThread* PresentThreadPool::NextThread() { return present_threads_[next_thread_].get(); } -AcceleratedPresenter::AcceleratedPresenter() - : present_thread_(g_present_thread_pool.Pointer()->NextThread()) { +AcceleratedPresenterMap::AcceleratedPresenterMap() { +} + +scoped_refptr<AcceleratedPresenter> AcceleratedPresenterMap::CreatePresenter( + gfx::NativeWindow window) { + scoped_refptr<AcceleratedPresenter> presenter( + new AcceleratedPresenter(window)); + + base::AutoLock locked(lock_); + DCHECK(presenters_.find(window) == presenters_.end()); + presenters_[window] = presenter.get(); + + return presenter; +} + +void AcceleratedPresenterMap::RemovePresenter( + const scoped_refptr<AcceleratedPresenter>& presenter) { + base::AutoLock locked(lock_); + for (PresenterMap::iterator it = presenters_.begin(); + it != presenters_.end(); + ++it) { + if (it->second == presenter.get()) { + presenters_.erase(it); + return; + } + } + + NOTREACHED(); +} + +scoped_refptr<AcceleratedPresenter> AcceleratedPresenterMap::GetPresenter( + gfx::NativeWindow window) { + base::AutoLock locked(lock_); + PresenterMap::iterator it = presenters_.find(window); + if (it == presenters_.end()) + return scoped_refptr<AcceleratedPresenter>(); + + return it->second; +} + +AcceleratedPresenter::AcceleratedPresenter(gfx::NativeWindow window) + : present_thread_(g_present_thread_pool.Pointer()->NextThread()), + window_(window) { +} + +scoped_refptr<AcceleratedPresenter> AcceleratedPresenter::GetForWindow( + gfx::NativeWindow window) { + return g_accelerated_presenter_map.Pointer()->GetPresenter(window); } void AcceleratedPresenter::AsyncPresentAndAcknowledge( - gfx::NativeWindow window, const gfx::Size& size, - int64 surface_id, + int64 surface_handle, const base::Callback<void(bool)>& completion_task) { + if (!surface_handle) { + completion_task.Run(true); + return; + } + present_thread_->message_loop()->PostTask( FROM_HERE, base::Bind(&AcceleratedPresenter::DoPresentAndAcknowledge, this, - window, size, - surface_id, + surface_handle, completion_task)); } -bool AcceleratedPresenter::Present(gfx::NativeWindow window) { +bool AcceleratedPresenter::Present() { TRACE_EVENT0("surface", "Present"); HRESULT hr; @@ -248,6 +319,10 @@ bool AcceleratedPresenter::Present(gfx::NativeWindow window) { if (!swap_chain_) return false; + // If invalidated, do nothing. The window is gone. + if (!window_) + return true; + RECT rect = { 0, 0, size_.width(), size_.height() @@ -257,7 +332,7 @@ bool AcceleratedPresenter::Present(gfx::NativeWindow window) { TRACE_EVENT0("surface", "PresentEx"); hr = swap_chain_->Present(&rect, &rect, - window, + window_, NULL, D3DPRESENT_INTERVAL_IMMEDIATE); if (FAILED(hr)) @@ -389,26 +464,24 @@ void AcceleratedPresenter::Suspend() { this)); } -void AcceleratedPresenter::WaitForPendingTasks() { - base::WaitableEvent event(true, false); - present_thread_->message_loop()->PostTask( - FROM_HERE, - base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event))); - event.Wait(); +void AcceleratedPresenter::Invalidate() { + // Make any pending or future presentation tasks do nothing. Once the last + // last pending task has been ignored, the reference count on the presenter + // will go to zero and the presenter, and potentially also the present thread + // it has a reference count on, will be destroyed. + base::AutoLock locked(lock_); + window_ = NULL; } AcceleratedPresenter::~AcceleratedPresenter() { - // The presenter should have been suspended on the PresentThread prior to - // destruction. - DCHECK(!swap_chain_.get()); } void AcceleratedPresenter::DoPresentAndAcknowledge( - gfx::NativeWindow window, const gfx::Size& size, - int64 surface_id, + int64 surface_handle, const base::Callback<void(bool)>& completion_task) { - TRACE_EVENT1("surface", "DoPresentAndAcknowledge", "surface_id", surface_id); + TRACE_EVENT1( + "surface", "DoPresentAndAcknowledge", "surface_handle", surface_handle); HRESULT hr; @@ -417,14 +490,6 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( // Initialize the device lazily since calling Direct3D can crash bots. present_thread_->InitDevice(); - // A surface with ID zero is presented even when shared surfaces are not in - // use for synchronization purposes. In that case, just acknowledge. - if (!surface_id) { - if (!completion_task.is_null()) - completion_task.Run(true); - return; - } - if (!present_thread_->device()) { if (!completion_task.is_null()) completion_task.Run(false); @@ -435,6 +500,10 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( base::ScopedClosureRunner scoped_completion_runner(base::Bind(completion_task, true)); + // If invalidated, do nothing, the window is gone. + if (!window_) + return; + // Round up size so the swap chain is not continuously resized with the // surface, which could lead to memory fragmentation. const int kRound = 64; @@ -470,7 +539,7 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( base::win::ScopedComPtr<IDirect3DTexture9> source_texture; { TRACE_EVENT0("surface", "CreateTexture"); - HANDLE handle = reinterpret_cast<HANDLE>(surface_id); + HANDLE handle = reinterpret_cast<HANDLE>(surface_handle); hr = present_thread_->device()->CreateTexture(size.width(), size.height(), 1, @@ -520,7 +589,7 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( present_thread_->query()->GetData(NULL, 0, D3DGETDATA_FLUSH); ::SetWindowPos( - window, + window_, NULL, 0, 0, size.width(), size.height(), @@ -546,7 +615,7 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( { TRACE_EVENT0("surface", "Present"); - hr = swap_chain_->Present(&rect, &rect, window, NULL, 0); + hr = swap_chain_->Present(&rect, &rect, window_, NULL, 0); if (FAILED(hr)) present_thread_->ResetDevice(); } @@ -557,35 +626,18 @@ void AcceleratedPresenter::DoSuspend() { swap_chain_ = NULL; } -AcceleratedSurface::AcceleratedSurface() - : presenter_(new AcceleratedPresenter) { +AcceleratedSurface::AcceleratedSurface(gfx::NativeWindow window) + : presenter_(g_accelerated_presenter_map.Pointer()->CreatePresenter( + window)) { } AcceleratedSurface::~AcceleratedSurface() { - // Ensure that the swap chain is destroyed on the PresentThread in case - // there are still pending presents. - presenter_->Suspend(); - presenter_->WaitForPendingTasks(); -} - -void AcceleratedSurface::AsyncPresentAndAcknowledge( - HWND window, - const gfx::Size& size, - int64 surface_id, - const base::Callback<void(bool)>& completion_task) { - if (!surface_id) { - completion_task.Run(true); - return; - } - - presenter_->AsyncPresentAndAcknowledge(window, - size, - surface_id, - completion_task); + g_accelerated_presenter_map.Pointer()->RemovePresenter(presenter_); + presenter_->Invalidate(); } -bool AcceleratedSurface::Present(HWND window) { - return presenter_->Present(window); +bool AcceleratedSurface::Present() { + return presenter_->Present(); } bool AcceleratedSurface::CopyTo(const gfx::Size& size, void* buf) { diff --git a/ui/gfx/surface/accelerated_surface_win.h b/ui/gfx/surface/accelerated_surface_win.h index 52208d3..e428c50 100644 --- a/ui/gfx/surface/accelerated_surface_win.h +++ b/ui/gfx/surface/accelerated_surface_win.h @@ -18,23 +18,36 @@ class PresentThread; -class AcceleratedPresenter +class SURFACE_EXPORT AcceleratedPresenter : public base::RefCountedThreadSafe<AcceleratedPresenter> { public: typedef base::Callback<void(bool)> CompletionTaskl; - AcceleratedPresenter(); + explicit AcceleratedPresenter(gfx::NativeWindow window); - // The public member functions are called on the main thread. + // Returns a thread safe reference to the presenter for the given window or + // null is no such presenter exists. The thread safe refptr ensures the + // presenter will not be destroyed. This can be called on any thread. + static scoped_refptr<AcceleratedPresenter> GetForWindow( + gfx::NativeWindow window); + + // 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. This can be + // called on any thread. void AsyncPresentAndAcknowledge( - gfx::NativeWindow window, const gfx::Size& size, - int64 surface_id, + int64 surface_handle, const base::Callback<void(bool)>& completion_task); - bool Present(gfx::NativeWindow window); - bool CopyTo(const gfx::Size& size, void* buf); + + // Schedule the presenter to free all its resources. This can be called on any + // thread. void Suspend(); - void WaitForPendingTasks(); + + // The public member functions are called on the main thread. + bool Present(); + bool CopyTo(const gfx::Size& size, void* buf); + void Invalidate(); private: friend class base::RefCountedThreadSafe<AcceleratedPresenter>; @@ -44,15 +57,17 @@ class AcceleratedPresenter // These member functions are called on the PresentThread with which the // presenter has affinity. void DoPresentAndAcknowledge( - gfx::NativeWindow window, const gfx::Size& size, - int64 surface_id, + int64 surface_handle, const base::Callback<void(bool)>& completion_task); void DoSuspend(); // The thread with which this presenter has affinity. PresentThread* const present_thread_; + // The window that is presented to. + gfx::NativeWindow window_; + // The lock is taken while any thread is calling the object, except those that // simply post from the main thread to the present thread via the immutable // present_thread_ member. @@ -71,20 +86,11 @@ class AcceleratedPresenter class SURFACE_EXPORT AcceleratedSurface { public: - AcceleratedSurface(); + AcceleratedSurface(gfx::NativeWindow window); ~AcceleratedSurface(); - // 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( - gfx::NativeWindow window, - const gfx::Size& size, - int64 surface_id, - const base::Callback<void(bool)>& completion_task); - // Synchronously present a frame with no acknowledgement. - bool Present(gfx::NativeWindow window); + bool Present(); // Copies the surface data to |buf|. The image data is transformed so that it // fits in |size|. @@ -98,7 +104,6 @@ class SURFACE_EXPORT AcceleratedSurface { void Suspend(); private: - // Immutable and accessible on any thread. const scoped_refptr<AcceleratedPresenter> presenter_; DISALLOW_COPY_AND_ASSIGN(AcceleratedSurface); }; |