| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gfx/surface/accelerated_surface_win.h" | 5 #include "ui/gfx/surface/accelerated_surface_win.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 // A PresentThread is a thread that is dedicated to presenting surfaces to a | 43 // A PresentThread is a thread that is dedicated to presenting surfaces to a |
| 44 // window. It owns a Direct3D device and a Direct3D query for this purpose. | 44 // window. It owns a Direct3D device and a Direct3D query for this purpose. |
| 45 class PresentThread : public base::Thread { | 45 class PresentThread : public base::Thread { |
| 46 public: | 46 public: |
| 47 PresentThread(const char* name); | 47 PresentThread(const char* name); |
| 48 ~PresentThread(); | 48 ~PresentThread(); |
| 49 | 49 |
| 50 IDirect3DDevice9* device() { return device_.get(); } | 50 IDirect3DDevice9* device() { return device_.get(); } |
| 51 IDirect3DQuery9* query() { return query_.get(); } | 51 IDirect3DQuery9* query() { return query_.get(); } |
| 52 | 52 |
| 53 void InitDevice(); |
| 53 void ResetDevice(); | 54 void ResetDevice(); |
| 54 | 55 |
| 55 protected: | 56 protected: |
| 56 virtual void Init(); | |
| 57 virtual void CleanUp(); | 57 virtual void CleanUp(); |
| 58 | 58 |
| 59 private: | 59 private: |
| 60 base::ScopedNativeLibrary d3d_module_; | 60 base::ScopedNativeLibrary d3d_module_; |
| 61 base::win::ScopedComPtr<IDirect3DDevice9Ex> device_; | 61 base::win::ScopedComPtr<IDirect3DDevice9Ex> device_; |
| 62 | 62 |
| 63 // This query is used to wait until a certain amount of progress has been | 63 // This query is used to wait until a certain amount of progress has been |
| 64 // made by the GPU and it is safe for the producer to modify its shared | 64 // made by the GPU and it is safe for the producer to modify its shared |
| 65 // texture again. | 65 // texture again. |
| 66 base::win::ScopedComPtr<IDirect3DQuery9> query_; | 66 base::win::ScopedComPtr<IDirect3DQuery9> query_; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 87 base::LazyInstance<PresentThreadPool> | 87 base::LazyInstance<PresentThreadPool> |
| 88 g_present_thread_pool = LAZY_INSTANCE_INITIALIZER; | 88 g_present_thread_pool = LAZY_INSTANCE_INITIALIZER; |
| 89 | 89 |
| 90 PresentThread::PresentThread(const char* name) : base::Thread(name) { | 90 PresentThread::PresentThread(const char* name) : base::Thread(name) { |
| 91 } | 91 } |
| 92 | 92 |
| 93 PresentThread::~PresentThread() { | 93 PresentThread::~PresentThread() { |
| 94 Stop(); | 94 Stop(); |
| 95 } | 95 } |
| 96 | 96 |
| 97 void PresentThread::InitDevice() { |
| 98 if (device_) |
| 99 return; |
| 100 |
| 101 TRACE_EVENT0("surface", "PresentThread::Init"); |
| 102 d3d_module_.Reset(base::LoadNativeLibrary(FilePath(kD3D9ModuleName), NULL)); |
| 103 ResetDevice(); |
| 104 } |
| 105 |
| 97 void PresentThread::ResetDevice() { | 106 void PresentThread::ResetDevice() { |
| 98 TRACE_EVENT0("surface", "PresentThread::ResetDevice"); | 107 TRACE_EVENT0("surface", "PresentThread::ResetDevice"); |
| 99 | 108 |
| 100 // This will crash some Intel drivers but we can't render anything without | 109 // This will crash some Intel drivers but we can't render anything without |
| 101 // reseting the device, which would be disappointing. | 110 // reseting the device, which would be disappointing. |
| 102 query_ = NULL; | 111 query_ = NULL; |
| 103 device_ = NULL; | 112 device_ = NULL; |
| 104 | 113 |
| 105 Direct3DCreate9ExFunc create_func = reinterpret_cast<Direct3DCreate9ExFunc>( | 114 Direct3DCreate9ExFunc create_func = reinterpret_cast<Direct3DCreate9ExFunc>( |
| 106 d3d_module_.GetFunctionPointer(kCreate3D9DeviceExName)); | 115 d3d_module_.GetFunctionPointer(kCreate3D9DeviceExName)); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 137 NULL, | 146 NULL, |
| 138 device_.Receive()); | 147 device_.Receive()); |
| 139 if (FAILED(hr)) | 148 if (FAILED(hr)) |
| 140 return; | 149 return; |
| 141 | 150 |
| 142 hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); | 151 hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); |
| 143 if (FAILED(hr)) | 152 if (FAILED(hr)) |
| 144 device_ = NULL; | 153 device_ = NULL; |
| 145 } | 154 } |
| 146 | 155 |
| 147 void PresentThread::Init() { | |
| 148 TRACE_EVENT0("surface", "PresentThread::Init"); | |
| 149 d3d_module_.Reset(base::LoadNativeLibrary(FilePath(kD3D9ModuleName), NULL)); | |
| 150 ResetDevice(); | |
| 151 } | |
| 152 | |
| 153 void PresentThread::CleanUp() { | 156 void PresentThread::CleanUp() { |
| 154 // The D3D device and query are leaked because destroying the associated D3D | 157 // The D3D device and query are leaked because destroying the associated D3D |
| 155 // query crashes some Intel drivers. | 158 // query crashes some Intel drivers. |
| 156 device_.Detach(); | 159 device_.Detach(); |
| 157 query_.Detach(); | 160 query_.Detach(); |
| 158 } | 161 } |
| 159 | 162 |
| 160 PresentThreadPool::PresentThreadPool() : next_thread_(0) { | 163 PresentThreadPool::PresentThreadPool() : next_thread_(0) { |
| 164 // Do this in the constructor so present_threads_ is initialized before any |
| 165 // other thread sees it. See LazyInstance documentation. |
| 166 for (int i = 0; i < kNumPresentThreads; ++i) { |
| 167 present_threads_[i].reset(new PresentThread( |
| 168 base::StringPrintf("PresentThread #%d", i).c_str())); |
| 169 present_threads_[i]->Start(); |
| 170 } |
| 161 } | 171 } |
| 162 | 172 |
| 163 PresentThread* PresentThreadPool::NextThread() { | 173 PresentThread* PresentThreadPool::NextThread() { |
| 164 next_thread_ = (next_thread_ + 1) % kNumPresentThreads; | 174 next_thread_ = (next_thread_ + 1) % kNumPresentThreads; |
| 165 if (!present_threads_[next_thread_].get()) { | |
| 166 present_threads_[next_thread_].reset(new PresentThread( | |
| 167 base::StringPrintf("PresentThread #%d", next_thread_).c_str())); | |
| 168 present_threads_[next_thread_]->Start(); | |
| 169 } | |
| 170 return present_threads_[next_thread_].get(); | 175 return present_threads_[next_thread_].get(); |
| 171 } | 176 } |
| 172 | 177 |
| 173 AcceleratedPresenter::AcceleratedPresenter() | 178 AcceleratedPresenter::AcceleratedPresenter() |
| 174 : present_thread_(g_present_thread_pool.Pointer()->NextThread()) { | 179 : present_thread_(g_present_thread_pool.Pointer()->NextThread()) { |
| 175 } | 180 } |
| 176 | 181 |
| 177 void AcceleratedPresenter::AsyncPresentAndAcknowledge( | 182 void AcceleratedPresenter::AsyncPresentAndAcknowledge( |
| 178 gfx::NativeWindow window, | 183 gfx::NativeWindow window, |
| 179 const gfx::Size& size, | 184 const gfx::Size& size, |
| 180 int64 surface_id, | 185 int64 surface_id, |
| 181 const base::Callback<void(bool)>& completion_task) { | 186 const base::Callback<void(bool)>& completion_task) { |
| 182 present_thread_->message_loop()->PostTask( | 187 present_thread_->message_loop()->PostTask( |
| 183 FROM_HERE, | 188 FROM_HERE, |
| 184 base::Bind(&AcceleratedPresenter::DoPresentAndAcknowledge, | 189 base::Bind(&AcceleratedPresenter::DoPresentAndAcknowledge, |
| 185 this, | 190 this, |
| 186 window, | 191 window, |
| 187 size, | 192 size, |
| 188 surface_id, | 193 surface_id, |
| 189 completion_task)); | 194 completion_task)); |
| 190 } | 195 } |
| 191 | 196 |
| 192 bool AcceleratedPresenter::Present(gfx::NativeWindow window) { | 197 bool AcceleratedPresenter::Present(gfx::NativeWindow window) { |
| 193 TRACE_EVENT0("surface", "Present"); | 198 TRACE_EVENT0("surface", "Present"); |
| 194 | 199 |
| 195 HRESULT hr; | 200 HRESULT hr; |
| 196 | 201 |
| 197 base::AutoLock locked(lock_); | 202 base::AutoLock locked(lock_); |
| 198 | 203 |
| 199 // Signal the caller to recomposite if the presenter has been suspended. | 204 // Signal the caller to recomposite if the presenter has been suspended or no |
| 205 // surface has ever been presented. |
| 200 if (!swap_chain_) | 206 if (!swap_chain_) |
| 201 return false; | 207 return false; |
| 202 | 208 |
| 203 RECT rect = { | 209 RECT rect = { |
| 204 0, 0, | 210 0, 0, |
| 205 size_.width(), size_.height() | 211 size_.width(), size_.height() |
| 206 }; | 212 }; |
| 207 | 213 |
| 208 { | 214 { |
| 209 TRACE_EVENT0("surface", "PresentEx"); | 215 TRACE_EVENT0("surface", "PresentEx"); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 259 gfx::NativeWindow window, | 265 gfx::NativeWindow window, |
| 260 const gfx::Size& size, | 266 const gfx::Size& size, |
| 261 int64 surface_id, | 267 int64 surface_id, |
| 262 const base::Callback<void(bool)>& completion_task) { | 268 const base::Callback<void(bool)>& completion_task) { |
| 263 TRACE_EVENT1("surface", "DoPresentAndAcknowledge", "surface_id", surface_id); | 269 TRACE_EVENT1("surface", "DoPresentAndAcknowledge", "surface_id", surface_id); |
| 264 | 270 |
| 265 HRESULT hr; | 271 HRESULT hr; |
| 266 | 272 |
| 267 base::AutoLock locked(lock_); | 273 base::AutoLock locked(lock_); |
| 268 | 274 |
| 275 // Initialize the device lazily since calling Direct3D can crash bots. |
| 276 present_thread_->InitDevice(); |
| 277 |
| 278 // A surface with ID zero is presented even when shared surfaces are not in |
| 279 // use for synchronization purposes. In that case, just acknowledge. |
| 280 if (!surface_id) { |
| 281 if (!completion_task.is_null()) |
| 282 completion_task.Run(true); |
| 283 return; |
| 284 } |
| 285 |
| 269 if (!present_thread_->device()) { | 286 if (!present_thread_->device()) { |
| 270 if (!completion_task.is_null()) | 287 if (!completion_task.is_null()) |
| 271 completion_task.Run(false); | 288 completion_task.Run(false); |
| 272 return; | 289 return; |
| 273 } | 290 } |
| 274 | 291 |
| 275 // Ensure the task is always run and while the lock is taken. | 292 // Ensure the task is always run and while the lock is taken. |
| 276 base::ScopedClosureRunner scoped_completion_runner(base::Bind(completion_task, | 293 base::ScopedClosureRunner scoped_completion_runner(base::Bind(completion_task, |
| 277 true)); | 294 true)); |
| 278 | 295 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 301 parameters.SwapEffect = D3DSWAPEFFECT_COPY; | 318 parameters.SwapEffect = D3DSWAPEFFECT_COPY; |
| 302 | 319 |
| 303 swap_chain_ = NULL; | 320 swap_chain_ = NULL; |
| 304 HRESULT hr = present_thread_->device()->CreateAdditionalSwapChain( | 321 HRESULT hr = present_thread_->device()->CreateAdditionalSwapChain( |
| 305 ¶meters, | 322 ¶meters, |
| 306 swap_chain_.Receive()); | 323 swap_chain_.Receive()); |
| 307 if (FAILED(hr)) | 324 if (FAILED(hr)) |
| 308 return; | 325 return; |
| 309 } | 326 } |
| 310 | 327 |
| 311 HANDLE handle = reinterpret_cast<HANDLE>(surface_id); | |
| 312 if (!handle) | |
| 313 return; | |
| 314 | |
| 315 base::win::ScopedComPtr<IDirect3DTexture9> source_texture; | 328 base::win::ScopedComPtr<IDirect3DTexture9> source_texture; |
| 316 { | 329 { |
| 317 TRACE_EVENT0("surface", "CreateTexture"); | 330 TRACE_EVENT0("surface", "CreateTexture"); |
| 331 HANDLE handle = reinterpret_cast<HANDLE>(surface_id); |
| 318 hr = present_thread_->device()->CreateTexture(size.width(), | 332 hr = present_thread_->device()->CreateTexture(size.width(), |
| 319 size.height(), | 333 size.height(), |
| 320 1, | 334 1, |
| 321 D3DUSAGE_RENDERTARGET, | 335 D3DUSAGE_RENDERTARGET, |
| 322 D3DFMT_A8R8G8B8, | 336 D3DFMT_A8R8G8B8, |
| 323 D3DPOOL_DEFAULT, | 337 D3DPOOL_DEFAULT, |
| 324 source_texture.Receive(), | 338 source_texture.Receive(), |
| 325 &handle); | 339 &handle); |
| 326 if (FAILED(hr)) | 340 if (FAILED(hr)) |
| 327 return; | 341 return; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 if (FAILED(hr)) | 408 if (FAILED(hr)) |
| 395 present_thread_->ResetDevice(); | 409 present_thread_->ResetDevice(); |
| 396 } | 410 } |
| 397 } | 411 } |
| 398 | 412 |
| 399 void AcceleratedPresenter::DoSuspend() { | 413 void AcceleratedPresenter::DoSuspend() { |
| 400 base::AutoLock locked(lock_); | 414 base::AutoLock locked(lock_); |
| 401 swap_chain_ = NULL; | 415 swap_chain_ = NULL; |
| 402 } | 416 } |
| 403 | 417 |
| 404 AcceleratedSurface::AcceleratedSurface(){ | 418 AcceleratedSurface::AcceleratedSurface() |
| 419 : presenter_(new AcceleratedPresenter) { |
| 405 } | 420 } |
| 406 | 421 |
| 407 AcceleratedSurface::~AcceleratedSurface() { | 422 AcceleratedSurface::~AcceleratedSurface() { |
| 408 if (presenter_) { | 423 // Ensure that the swap chain is destroyed on the PresentThread in case |
| 409 // Ensure that the swap chain is destroyed on the PresentThread in case | 424 // there are still pending presents. |
| 410 // there are still pending presents. | 425 presenter_->Suspend(); |
| 411 presenter_->Suspend(); | 426 presenter_->WaitForPendingTasks(); |
| 412 presenter_->WaitForPendingTasks(); | |
| 413 } | |
| 414 } | 427 } |
| 415 | 428 |
| 416 void AcceleratedSurface::AsyncPresentAndAcknowledge( | 429 void AcceleratedSurface::AsyncPresentAndAcknowledge( |
| 417 HWND window, | 430 HWND window, |
| 418 const gfx::Size& size, | 431 const gfx::Size& size, |
| 419 int64 surface_id, | 432 int64 surface_id, |
| 420 const base::Callback<void(bool)>& completion_task) { | 433 const base::Callback<void(bool)>& completion_task) { |
| 421 if (!surface_id) | 434 if (!surface_id) |
| 422 return; | 435 return; |
| 423 | 436 |
| 424 if (!presenter_) | |
| 425 presenter_ = new AcceleratedPresenter; | |
| 426 | |
| 427 presenter_->AsyncPresentAndAcknowledge(window, | 437 presenter_->AsyncPresentAndAcknowledge(window, |
| 428 size, | 438 size, |
| 429 surface_id, | 439 surface_id, |
| 430 completion_task); | 440 completion_task); |
| 431 } | 441 } |
| 432 | 442 |
| 433 bool AcceleratedSurface::Present(HWND window) { | 443 bool AcceleratedSurface::Present(HWND window) { |
| 434 if (presenter_) | 444 return presenter_->Present(window); |
| 435 return presenter_->Present(window); | |
| 436 else | |
| 437 return false; | |
| 438 } | 445 } |
| 439 | 446 |
| 440 void AcceleratedSurface::Suspend() { | 447 void AcceleratedSurface::Suspend() { |
| 441 if (presenter_) | 448 presenter_->Suspend(); |
| 442 presenter_->Suspend(); | |
| 443 } | 449 } |
| 444 | 450 |
| OLD | NEW |