Commit 5d511a16 authored by apatrick@chromium.org's avatar apatrick@chromium.org

Ensure that PresentThreadPool is initialized on the UI thread.

It was being initialized lazily on the IO thread when the first AsyncPresentAndAcknowledge came in.

Also, the AcceleratedSurface::presenter_ variable was mutable, initialized on the IO thread and used on the IO and UI thread with no lock. I think this allowed the UI thread to attempt to use a partially initialized AcceleratedPresenter. I made presenter_ immutable and ensured that the AcceleratedPresenter is instead always created on the UI thread and not visible in partially constructed form on the IO thread.

I had to change the timing of the Direct3D device initialization so that it is not created if it is not needed because that can crash windows bots.

BUG=117453

Review URL: http://codereview.chromium.org/9694015

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@126741 0039d316-1c4b-4281-b951-d872f2087c98
parent dceb4cc8
...@@ -50,10 +50,10 @@ class PresentThread : public base::Thread { ...@@ -50,10 +50,10 @@ class PresentThread : public base::Thread {
IDirect3DDevice9* device() { return device_.get(); } IDirect3DDevice9* device() { return device_.get(); }
IDirect3DQuery9* query() { return query_.get(); } IDirect3DQuery9* query() { return query_.get(); }
void InitDevice();
void ResetDevice(); void ResetDevice();
protected: protected:
virtual void Init();
virtual void CleanUp(); virtual void CleanUp();
private: private:
...@@ -94,6 +94,15 @@ PresentThread::~PresentThread() { ...@@ -94,6 +94,15 @@ PresentThread::~PresentThread() {
Stop(); Stop();
} }
void PresentThread::InitDevice() {
if (device_)
return;
TRACE_EVENT0("surface", "PresentThread::Init");
d3d_module_.Reset(base::LoadNativeLibrary(FilePath(kD3D9ModuleName), NULL));
ResetDevice();
}
void PresentThread::ResetDevice() { void PresentThread::ResetDevice() {
TRACE_EVENT0("surface", "PresentThread::ResetDevice"); TRACE_EVENT0("surface", "PresentThread::ResetDevice");
...@@ -144,12 +153,6 @@ void PresentThread::ResetDevice() { ...@@ -144,12 +153,6 @@ void PresentThread::ResetDevice() {
device_ = NULL; device_ = NULL;
} }
void PresentThread::Init() {
TRACE_EVENT0("surface", "PresentThread::Init");
d3d_module_.Reset(base::LoadNativeLibrary(FilePath(kD3D9ModuleName), NULL));
ResetDevice();
}
void PresentThread::CleanUp() { void PresentThread::CleanUp() {
// The D3D device and query are leaked because destroying the associated D3D // The D3D device and query are leaked because destroying the associated D3D
// query crashes some Intel drivers. // query crashes some Intel drivers.
...@@ -158,15 +161,17 @@ void PresentThread::CleanUp() { ...@@ -158,15 +161,17 @@ void PresentThread::CleanUp() {
} }
PresentThreadPool::PresentThreadPool() : next_thread_(0) { 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]->Start();
}
} }
PresentThread* PresentThreadPool::NextThread() { PresentThread* PresentThreadPool::NextThread() {
next_thread_ = (next_thread_ + 1) % kNumPresentThreads; 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(); return present_threads_[next_thread_].get();
} }
...@@ -196,7 +201,8 @@ bool AcceleratedPresenter::Present(gfx::NativeWindow window) { ...@@ -196,7 +201,8 @@ bool AcceleratedPresenter::Present(gfx::NativeWindow window) {
base::AutoLock locked(lock_); base::AutoLock locked(lock_);
// Signal the caller to recomposite if the presenter has been suspended. // Signal the caller to recomposite if the presenter has been suspended or no
// surface has ever been presented.
if (!swap_chain_) if (!swap_chain_)
return false; return false;
...@@ -266,6 +272,17 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( ...@@ -266,6 +272,17 @@ void AcceleratedPresenter::DoPresentAndAcknowledge(
base::AutoLock locked(lock_); base::AutoLock locked(lock_);
// 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 (!present_thread_->device()) {
if (!completion_task.is_null()) if (!completion_task.is_null())
completion_task.Run(false); completion_task.Run(false);
...@@ -308,13 +325,10 @@ void AcceleratedPresenter::DoPresentAndAcknowledge( ...@@ -308,13 +325,10 @@ void AcceleratedPresenter::DoPresentAndAcknowledge(
return; return;
} }
HANDLE handle = reinterpret_cast<HANDLE>(surface_id);
if (!handle)
return;
base::win::ScopedComPtr<IDirect3DTexture9> source_texture; base::win::ScopedComPtr<IDirect3DTexture9> source_texture;
{ {
TRACE_EVENT0("surface", "CreateTexture"); TRACE_EVENT0("surface", "CreateTexture");
HANDLE handle = reinterpret_cast<HANDLE>(surface_id);
hr = present_thread_->device()->CreateTexture(size.width(), hr = present_thread_->device()->CreateTexture(size.width(),
size.height(), size.height(),
1, 1,
...@@ -401,16 +415,15 @@ void AcceleratedPresenter::DoSuspend() { ...@@ -401,16 +415,15 @@ void AcceleratedPresenter::DoSuspend() {
swap_chain_ = NULL; swap_chain_ = NULL;
} }
AcceleratedSurface::AcceleratedSurface(){ AcceleratedSurface::AcceleratedSurface()
: presenter_(new AcceleratedPresenter) {
} }
AcceleratedSurface::~AcceleratedSurface() { AcceleratedSurface::~AcceleratedSurface() {
if (presenter_) { // Ensure that the swap chain is destroyed on the PresentThread in case
// Ensure that the swap chain is destroyed on the PresentThread in case // there are still pending presents.
// there are still pending presents. presenter_->Suspend();
presenter_->Suspend(); presenter_->WaitForPendingTasks();
presenter_->WaitForPendingTasks();
}
} }
void AcceleratedSurface::AsyncPresentAndAcknowledge( void AcceleratedSurface::AsyncPresentAndAcknowledge(
...@@ -421,9 +434,6 @@ void AcceleratedSurface::AsyncPresentAndAcknowledge( ...@@ -421,9 +434,6 @@ void AcceleratedSurface::AsyncPresentAndAcknowledge(
if (!surface_id) if (!surface_id)
return; return;
if (!presenter_)
presenter_ = new AcceleratedPresenter;
presenter_->AsyncPresentAndAcknowledge(window, presenter_->AsyncPresentAndAcknowledge(window,
size, size,
surface_id, surface_id,
...@@ -431,14 +441,10 @@ void AcceleratedSurface::AsyncPresentAndAcknowledge( ...@@ -431,14 +441,10 @@ void AcceleratedSurface::AsyncPresentAndAcknowledge(
} }
bool AcceleratedSurface::Present(HWND window) { bool AcceleratedSurface::Present(HWND window) {
if (presenter_) return presenter_->Present(window);
return presenter_->Present(window);
else
return false;
} }
void AcceleratedSurface::Suspend() { void AcceleratedSurface::Suspend() {
if (presenter_) presenter_->Suspend();
presenter_->Suspend();
} }
...@@ -91,7 +91,8 @@ class SURFACE_EXPORT AcceleratedSurface { ...@@ -91,7 +91,8 @@ class SURFACE_EXPORT AcceleratedSurface {
void Suspend(); void Suspend();
private: private:
scoped_refptr<AcceleratedPresenter> presenter_; // Immutable and accessible on any thread.
const scoped_refptr<AcceleratedPresenter> presenter_;
DISALLOW_COPY_AND_ASSIGN(AcceleratedSurface); DISALLOW_COPY_AND_ASSIGN(AcceleratedSurface);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment