diff options
author | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-07 20:01:49 +0000 |
---|---|---|
committer | apatrick@chromium.org <apatrick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-07 20:01:49 +0000 |
commit | 38f4e2efd1e3105160f41669606580d17a85121f (patch) | |
tree | 76a470d99ea438ec0a5c2d28f3485f8d92b9e9f6 /ui/gfx/surface | |
parent | a648ea759bee8e7adf2d2560c6a414b16cd05fd1 (diff) | |
download | chromium_src-38f4e2efd1e3105160f41669606580d17a85121f.zip chromium_src-38f4e2efd1e3105160f41669606580d17a85121f.tar.gz chromium_src-38f4e2efd1e3105160f41669606580d17a85121f.tar.bz2 |
Windows: Limit D3D devices to one per Present Thread (4 max).
Instead of one D3D device per unsuspended tab, there is one D3D device per Present Thread plus one additional swap chain per unsuspended tab. Also, the swap chains are completely destroyed when a tab is suspended, rather than resizing the device swap chain to 1 x 1.
Specified flag on D3D device creation to tell it not to create worker threads to evaluate vertex shaders because we aren't using vertex shaders here but the devices appeared to create some (actually lots) anyway.
Sent Suspend notification directly from browser IO thread to present thread rather than via UI thread so tehy don't get unnecessarily held up if the UI thread is busy.
BUG=116175,115707
Review URL: https://chromiumcodereview.appspot.com/9565043
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@125439 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/gfx/surface')
-rw-r--r-- | ui/gfx/surface/accelerated_surface_win.cc | 504 | ||||
-rw-r--r-- | ui/gfx/surface/accelerated_surface_win.h | 55 |
2 files changed, 264 insertions, 295 deletions
diff --git a/ui/gfx/surface/accelerated_surface_win.cc b/ui/gfx/surface/accelerated_surface_win.cc index 45fdf48..4edc1ee 100644 --- a/ui/gfx/surface/accelerated_surface_win.cc +++ b/ui/gfx/surface/accelerated_surface_win.cc @@ -4,11 +4,8 @@ #include "ui/gfx/surface/accelerated_surface_win.h" -#include <d3d9.h> #include <windows.h> -#include <list> - #include "base/bind.h" #include "base/bind_helpers.h" #include "base/callback.h" @@ -16,18 +13,13 @@ #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/synchronization/waitable_event.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" #include "ui/gfx/gl/gl_switches.h" @@ -39,53 +31,6 @@ typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT sdk_version, const wchar_t kD3D9ModuleName[] = L"d3d9.dll"; const char kCreate3D9DeviceExName[] = "Direct3DCreate9Ex"; -class PresentThreadPool { - public: - static const int kNumPresentThreads = 4; - - PresentThreadPool(); - - int NextThread(); - - void PostTask(int thread, - const tracked_objects::Location& from_here, - const base::Closure& task); - - private: - int next_thread_; - scoped_ptr<base::Thread> present_threads_[kNumPresentThreads]; - - DISALLOW_COPY_AND_ASSIGN(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( - base::StringPrintf("PresentThread #%d", i).c_str())); - present_threads_[i]->Start(); - } -} - -int PresentThreadPool::NextThread() { - next_thread_ = (next_thread_ + 1) % kNumPresentThreads; - return next_thread_; -} - -void PresentThreadPool::PostTask(int thread, - const tracked_objects::Location& from_here, - const base::Closure& task) { - DCHECK_GE(thread, 0); - DCHECK_LT(thread, kNumPresentThreads); - - present_threads_[thread]->message_loop()->PostTask(from_here, task); -} - UINT GetPresentationInterval() { if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync)) return D3DPRESENT_INTERVAL_IMMEDIATE; @@ -95,54 +40,24 @@ UINT GetPresentationInterval() { } // namespace anonymous -class AcceleratedPresenter { +// 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 { public: - AcceleratedPresenter(); - ~AcceleratedPresenter(); + PresentThread(const char* name); + ~PresentThread(); - void AsyncPresentAndAcknowledge(gfx::NativeWindow window, - const gfx::Size& size, - int64 surface_id, - const base::Closure& completion_task); + IDirect3DDevice9* device() { return device_.get(); } + IDirect3DQuery9* query() { return query_.get(); } - bool Present(gfx::NativeWindow window); + void ResetDevice(); - void Suspend(); + protected: + virtual void Init(); + virtual void CleanUp(); 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_; - - // Whether the presenter is suspended and therefore unable to represent. Only - // accessed on the UI thread so the lock is unnecessary. - bool suspended_; - - // 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 @@ -150,141 +65,42 @@ class AcceleratedPresenter { // texture again. base::win::ScopedComPtr<IDirect3DQuery9> query_; - DISALLOW_COPY_AND_ASSIGN(AcceleratedPresenter); + DISALLOW_COPY_AND_ASSIGN(PresentThread); }; -AcceleratedPresenter::AcceleratedPresenter() - : thread_affinity_(g_present_thread_pool.Pointer()->NextThread()), - suspended_(true), - num_pending_resizes_(0) { - g_present_thread_pool.Pointer()->PostTask( - thread_affinity_, - FROM_HERE, - base::Bind(&AcceleratedPresenter::DoInitialize, base::Unretained(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 AcceleratedPresenter::AsyncPresentAndAcknowledge( - gfx::NativeWindow window, - const gfx::Size& size, - int64 surface_id, - const base::Closure& completion_task) { - const int kRound = 64; - gfx::Size quantized_size( - std::max(1, (size.width() + kRound - 1) / kRound * kRound), - std::max(1, (size.height() + kRound - 1) / kRound * kRound)); - - if (pending_size_ != quantized_size) { - pending_size_ = quantized_size; - base::AtomicRefCountInc(&num_pending_resizes_); - - g_present_thread_pool.Pointer()->PostTask( - thread_affinity_, - FROM_HERE, - base::Bind(&AcceleratedPresenter::DoResize, - base::Unretained(this), - quantized_size)); - } - - g_present_thread_pool.Pointer()->PostTask( - thread_affinity_, - FROM_HERE, - base::Bind(&AcceleratedPresenter::DoPresentAndAcknowledge, - base::Unretained(this), - window, - size, - surface_id, - completion_task)); - - suspended_ = false; -} - -bool AcceleratedPresenter::Present(gfx::NativeWindow window) { - TRACE_EVENT0("surface", "Present"); - - HRESULT hr; - - if (suspended_) - return false; - - base::AutoLock locked(lock_); - - if (!device_) - return true; - - RECT rect; - if (!GetClientRect(window, &rect)) - return true; - - { - TRACE_EVENT0("surface", "PresentEx"); - hr = device_->PresentEx(&rect, - &rect, - window, - 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(&AcceleratedPresenter::DoReset, base::Unretained(this))); - - // A device hang destroys the contents of the back buffer so no point in - // scheduling a present. - } +// There is a fixed sized pool of PresentThreads and therefore the maximum +// number of Direct3D devices owned by those threads is bounded. +class PresentThreadPool { + public: + static const int kNumPresentThreads = 4; - if (FAILED(hr)) - return false; - } + PresentThreadPool(); + PresentThread* NextThread(); - hr = query_->Issue(D3DISSUE_END); - if (FAILED(hr)) - return true; + private: + int next_thread_; + scoped_ptr<PresentThread> present_threads_[kNumPresentThreads]; - { - TRACE_EVENT0("surface", "spin"); - do { - hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH); + DISALLOW_COPY_AND_ASSIGN(PresentThreadPool); +}; - if (hr == S_FALSE) - Sleep(0); - } while (hr == S_FALSE); - } +base::LazyInstance<PresentThreadPool> + g_present_thread_pool = LAZY_INSTANCE_INITIALIZER; - return true; +PresentThread::PresentThread(const char* name) : base::Thread(name) { } -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))); - - suspended_ = true; +PresentThread::~PresentThread() { + Stop(); } -void AcceleratedPresenter::DoInitialize() { - TRACE_EVENT0("surface", "DoInitialize"); +void PresentThread::ResetDevice() { + TRACE_EVENT0("surface", "PresentThread::ResetDevice"); - HRESULT hr; - - d3d_module_.Reset(base::LoadNativeLibrary(FilePath(kD3D9ModuleName), NULL)); + // This will crash some Intel drivers but we can't render anything without + // reseting the device, which would be disappointing. + query_ = NULL; + device_ = NULL; Direct3DCreate9ExFunc create_func = reinterpret_cast<Direct3DCreate9ExFunc>( d3d_module_.GetFunctionPointer(kCreate3D9DeviceExName)); @@ -292,7 +108,7 @@ void AcceleratedPresenter::DoInitialize() { return; base::win::ScopedComPtr<IDirect3D9Ex> d3d; - hr = create_func(D3D_SDK_VERSION, d3d.Receive()); + HRESULT hr = create_func(D3D_SDK_VERSION, d3d.Receive()); if (FAILED(hr)) return; @@ -316,7 +132,7 @@ void AcceleratedPresenter::DoInitialize() { D3DDEVTYPE_HAL, window, D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING | - D3DCREATE_MULTITHREADED, + D3DCREATE_DISABLE_PSGP_THREADING | D3DCREATE_MULTITHREADED, ¶meters, NULL, device_.Receive()); @@ -326,48 +142,118 @@ void AcceleratedPresenter::DoInitialize() { hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); if (FAILED(hr)) { device_ = NULL; - return; } +} + +void PresentThread::Init() { + TRACE_EVENT0("surface", "PresentThread::Init"); + d3d_module_.Reset(base::LoadNativeLibrary(FilePath(kD3D9ModuleName), NULL)); + ResetDevice(); +} + +void PresentThread::CleanUp() { + // The D3D device and query are leaked because destroying the associated D3D + // query crashes some Intel drivers. + device_.Detach(); + query_.Detach(); +} - return; +PresentThreadPool::PresentThreadPool() : next_thread_(0) { } -void AcceleratedPresenter::DoResize(const gfx::Size& size) { - TRACE_EVENT0("surface", "DoResize"); - size_ = size; - DoReset(); +PresentThread* PresentThreadPool::NextThread() { + next_thread_ = (next_thread_ + 1) % kNumPresentThreads; + if (!present_threads_[next_thread_].get()) { + present_threads_[next_thread_].reset(new PresentThread( + base::StringPrintf("PresentThread #%d", next_thread_).c_str())); + present_threads_[next_thread_]->Start(); + } + return present_threads_[next_thread_].get(); } -void AcceleratedPresenter::DoReset() { - TRACE_EVENT0("surface", "DoReset"); +AcceleratedPresenter::AcceleratedPresenter() + : present_thread_(g_present_thread_pool.Pointer()->NextThread()) { +} - HRESULT hr; +void AcceleratedPresenter::AsyncPresentAndAcknowledge( + gfx::NativeWindow window, + const gfx::Size& size, + int64 surface_id, + const base::Closure& completion_task) { + present_thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&AcceleratedPresenter::DoPresentAndAcknowledge, + this, + window, + size, + surface_id, + completion_task)); +} + +bool AcceleratedPresenter::Present(gfx::NativeWindow window) { + TRACE_EVENT0("surface", "Present"); - base::AtomicRefCountDec(&num_pending_resizes_); + HRESULT hr; base::AutoLock locked(lock_); - if (!device_) - return; + // Signal the caller to recomposite if the presenter has been suspended. + if (!swap_chain_) + return false; - gfx::NativeWindow window = GetShellWindow(); + RECT rect = { + 0, 0, + size_.width(), size_.height() + }; - D3DPRESENT_PARAMETERS parameters = { 0 }; - parameters.BackBufferWidth = size_.width(); - parameters.BackBufferHeight = size_.height(); - parameters.BackBufferCount = 1; - parameters.BackBufferFormat = D3DFMT_A8R8G8B8; - parameters.hDeviceWindow = window; - parameters.Windowed = TRUE; - parameters.Flags = 0; - parameters.PresentationInterval = GetPresentationInterval(); - parameters.SwapEffect = D3DSWAPEFFECT_COPY; + { + TRACE_EVENT0("surface", "PresentEx"); + hr = swap_chain_->Present(&rect, + &rect, + window, + NULL, + D3DPRESENT_INTERVAL_IMMEDIATE); + if (FAILED(hr)) + return false; + } - hr = device_->ResetEx(¶meters, NULL); - if (FAILED(hr)) - return; + // Wait for the Present to complete before returning. + { + TRACE_EVENT0("surface", "spin"); + hr = present_thread_->query()->Issue(D3DISSUE_END); + if (FAILED(hr)) + return false; + + do { + hr = present_thread_->query()->GetData(NULL, 0, D3DGETDATA_FLUSH); + + if (hr == S_FALSE) + Sleep(0); + } while (hr == S_FALSE); + } + + return true; +} + +void AcceleratedPresenter::Suspend() { + present_thread_->message_loop()->PostTask( + FROM_HERE, + base::Bind(&AcceleratedPresenter::DoSuspend, + this)); +} - device_->Clear(0, NULL, D3DCLEAR_TARGET, 0xFFFFFFFF, 0, 0); +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(); +} + +AcceleratedPresenter::~AcceleratedPresenter() { + // The presenter should have been suspended on the PresentThread prior to + // destruction. + DCHECK(!swap_chain_.get()); } void AcceleratedPresenter::DoPresentAndAcknowledge( @@ -384,8 +270,37 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( // Ensure the task is always run and while the lock is taken. base::ScopedClosureRunner scoped_completion_runner(completion_task); - if (!device_) - 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; + gfx::Size quantized_size( + std::max(1, (size.width() + kRound - 1) / kRound * kRound), + std::max(1, (size.height() + kRound - 1) / kRound * kRound)); + + // Ensure the swap chain exists and is the same size (rounded up) as the + // surface to be presented. + if (!swap_chain_ || size_ != quantized_size) { + TRACE_EVENT0("surface", "CreateAdditionalSwapChain"); + size_ = quantized_size; + + D3DPRESENT_PARAMETERS parameters = { 0 }; + parameters.BackBufferWidth = quantized_size.width(); + parameters.BackBufferHeight = quantized_size.height(); + parameters.BackBufferCount = 1; + parameters.BackBufferFormat = D3DFMT_A8R8G8B8; + parameters.hDeviceWindow = GetShellWindow(); + parameters.Windowed = TRUE; + parameters.Flags = 0; + parameters.PresentationInterval = GetPresentationInterval(); + parameters.SwapEffect = D3DSWAPEFFECT_COPY; + + swap_chain_ = NULL; + HRESULT hr = present_thread_->device()->CreateAdditionalSwapChain( + ¶meters, + swap_chain_.Receive()); + if (FAILED(hr)) + return; + } HANDLE handle = reinterpret_cast<HANDLE>(surface_id); if (!handle) @@ -394,14 +309,14 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( base::win::ScopedComPtr<IDirect3DTexture9> source_texture; { TRACE_EVENT0("surface", "CreateTexture"); - hr = device_->CreateTexture(size.width(), - size.height(), - 1, - D3DUSAGE_RENDERTARGET, - D3DFMT_A8R8G8B8, - D3DPOOL_DEFAULT, - source_texture.Receive(), - &handle); + hr = present_thread_->device()->CreateTexture(size.width(), + size.height(), + 1, + D3DUSAGE_RENDERTARGET, + D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, + source_texture.Receive(), + &handle); if (FAILED(hr)) return; } @@ -412,7 +327,9 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( return; base::win::ScopedComPtr<IDirect3DSurface9> dest_surface; - hr = device_->GetRenderTarget(0, dest_surface.Receive()); + hr = swap_chain_->GetBackBuffer(0, + D3DBACKBUFFER_TYPE_MONO, + dest_surface.Receive()); if (FAILED(hr)) return; @@ -423,22 +340,22 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( { TRACE_EVENT0("surface", "StretchRect"); - hr = device_->StretchRect(source_surface, - &rect, - dest_surface, - &rect, - D3DTEXF_NONE); + hr = present_thread_->device()->StretchRect(source_surface, + &rect, + dest_surface, + &rect, + D3DTEXF_NONE); if (FAILED(hr)) return; } - hr = query_->Issue(D3DISSUE_END); + hr = present_thread_->query()->Issue(D3DISSUE_END); if (FAILED(hr)) return; // Flush so the StretchRect can be processed by the GPU while the window is // being resized. - query_->GetData(NULL, 0, D3DGETDATA_FLUSH); + present_thread_->query()->GetData(NULL, 0, D3DGETDATA_FLUSH); ::SetWindowPos( window, @@ -454,7 +371,7 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( { TRACE_EVENT0("surface", "spin"); do { - hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH); + hr = present_thread_->query()->GetData(NULL, 0, D3DGETDATA_FLUSH); if (hr == S_FALSE) Sleep(0); @@ -467,34 +384,27 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( { TRACE_EVENT0("surface", "Present"); - 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) { - base::AtomicRefCountInc(&num_pending_resizes_); - g_present_thread_pool.Pointer()->PostTask( - thread_affinity_, - FROM_HERE, - base::Bind(&AcceleratedPresenter::DoReset, base::Unretained(this))); - - // A device hang destroys the contents of the back buffer so no point in - // scheduling a present. - } + hr = swap_chain_->Present(&rect, &rect, window, NULL, 0); + if (FAILED(hr)) + present_thread_->ResetDevice(); } } -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(); - } +void AcceleratedPresenter::DoSuspend() { + base::AutoLock locked(lock_); + swap_chain_ = NULL; +} + +AcceleratedSurface::AcceleratedSurface(){ } AcceleratedSurface::~AcceleratedSurface() { - presenter_->Suspend(); - g_unused_accelerated_presenters.Pointer()->push_back(presenter_); + if (presenter_) { + // Ensure that the swap chain is destroyed on the PresentThread in case + // there are still pending presents. + presenter_->Suspend(); + presenter_->WaitForPendingTasks(); + } } void AcceleratedSurface::AsyncPresentAndAcknowledge( @@ -502,6 +412,12 @@ void AcceleratedSurface::AsyncPresentAndAcknowledge( const gfx::Size& size, int64 surface_id, const base::Closure& completion_task) { + if (!surface_id) + return; + + if (!presenter_) + presenter_ = new AcceleratedPresenter; + presenter_->AsyncPresentAndAcknowledge(window, size, surface_id, @@ -509,10 +425,14 @@ void AcceleratedSurface::AsyncPresentAndAcknowledge( } bool AcceleratedSurface::Present(HWND window) { - return presenter_->Present(window); + if (presenter_) + return presenter_->Present(window); + else + return false; } void AcceleratedSurface::Suspend() { - presenter_->Suspend(); + if (presenter_) + presenter_->Suspend(); } diff --git a/ui/gfx/surface/accelerated_surface_win.h b/ui/gfx/surface/accelerated_surface_win.h index cf59178..5ed3078 100644 --- a/ui/gfx/surface/accelerated_surface_win.h +++ b/ui/gfx/surface/accelerated_surface_win.h @@ -6,13 +6,62 @@ #define UI_GFX_SURFACE_ACCELERATED_SURFACE_WIN_H_ #pragma once +#include <d3d9.h> + #include "base/callback_forward.h" -#include "base/memory/linked_ptr.h" +#include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" +#include "base/win/scoped_comptr.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/size.h" #include "ui/gfx/surface/surface_export.h" -class AcceleratedPresenter; +class PresentThread; + +class AcceleratedPresenter : public base::RefCounted<AcceleratedPresenter> { + public: + AcceleratedPresenter(); + + // The public member functions are called on the main thread. + void AsyncPresentAndAcknowledge(gfx::NativeWindow window, + const gfx::Size& size, + int64 surface_id, + const base::Closure& completion_task); + bool Present(gfx::NativeWindow window); + void Suspend(); + void WaitForPendingTasks(); + + private: + friend class base::RefCounted<AcceleratedPresenter>; + + ~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, + const base::Closure& completion_task); + void DoSuspend(); + + // The thread with which this presenter has affinity. + PresentThread* const present_thread_; + + // 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. + base::Lock lock_; + + // The current size of the swap chain. This is only accessed on the thread + // with which the surface has affinity. + gfx::Size size_; + + // The 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<IDirect3DSwapChain9> swap_chain_; + + DISALLOW_COPY_AND_ASSIGN(AcceleratedPresenter); +}; class SURFACE_EXPORT AcceleratedSurface { public: @@ -36,7 +85,7 @@ class SURFACE_EXPORT AcceleratedSurface { void Suspend(); private: - linked_ptr<AcceleratedPresenter> presenter_; + scoped_refptr<AcceleratedPresenter> presenter_; DISALLOW_COPY_AND_ASSIGN(AcceleratedSurface); }; |