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 // Initialize the device lazily since calling Direct3D can crash bots. | |
vangelis
2012/03/13 22:09:37
This comment probably makes more sense at the call
apatrick_chromium
2012/03/13 22:22:02
Done.
| |
99 if (device_) | |
100 return; | |
101 | |
102 TRACE_EVENT0("surface", "PresentThread::Init"); | |
103 d3d_module_.Reset(base::LoadNativeLibrary(FilePath(kD3D9ModuleName), NULL)); | |
104 ResetDevice(); | |
105 } | |
106 | |
97 void PresentThread::ResetDevice() { | 107 void PresentThread::ResetDevice() { |
98 TRACE_EVENT0("surface", "PresentThread::ResetDevice"); | 108 TRACE_EVENT0("surface", "PresentThread::ResetDevice"); |
99 | 109 |
100 // This will crash some Intel drivers but we can't render anything without | 110 // This will crash some Intel drivers but we can't render anything without |
101 // reseting the device, which would be disappointing. | 111 // reseting the device, which would be disappointing. |
102 query_ = NULL; | 112 query_ = NULL; |
103 device_ = NULL; | 113 device_ = NULL; |
104 | 114 |
105 Direct3DCreate9ExFunc create_func = reinterpret_cast<Direct3DCreate9ExFunc>( | 115 Direct3DCreate9ExFunc create_func = reinterpret_cast<Direct3DCreate9ExFunc>( |
106 d3d_module_.GetFunctionPointer(kCreate3D9DeviceExName)); | 116 d3d_module_.GetFunctionPointer(kCreate3D9DeviceExName)); |
(...skipping 30 matching lines...) Expand all Loading... | |
137 NULL, | 147 NULL, |
138 device_.Receive()); | 148 device_.Receive()); |
139 if (FAILED(hr)) | 149 if (FAILED(hr)) |
140 return; | 150 return; |
141 | 151 |
142 hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); | 152 hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); |
143 if (FAILED(hr)) | 153 if (FAILED(hr)) |
144 device_ = NULL; | 154 device_ = NULL; |
145 } | 155 } |
146 | 156 |
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() { | 157 void PresentThread::CleanUp() { |
154 // The D3D device and query are leaked because destroying the associated D3D | 158 // The D3D device and query are leaked because destroying the associated D3D |
155 // query crashes some Intel drivers. | 159 // query crashes some Intel drivers. |
156 device_.Detach(); | 160 device_.Detach(); |
157 query_.Detach(); | 161 query_.Detach(); |
158 } | 162 } |
159 | 163 |
160 PresentThreadPool::PresentThreadPool() : next_thread_(0) { | 164 PresentThreadPool::PresentThreadPool() : next_thread_(0) { |
165 // Do this in the constructor so present_threads_ is initialized before any | |
166 // other thread sees it. See LazyInstance documentation. | |
167 for (int i = 0; i < kNumPresentThreads; ++i) { | |
168 present_threads_[i].reset(new PresentThread( | |
169 base::StringPrintf("PresentThread #%d", i).c_str())); | |
170 present_threads_[i]->Start(); | |
171 } | |
161 } | 172 } |
162 | 173 |
163 PresentThread* PresentThreadPool::NextThread() { | 174 PresentThread* PresentThreadPool::NextThread() { |
164 next_thread_ = (next_thread_ + 1) % kNumPresentThreads; | 175 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(); | 176 return present_threads_[next_thread_].get(); |
171 } | 177 } |
172 | 178 |
173 AcceleratedPresenter::AcceleratedPresenter() | 179 AcceleratedPresenter::AcceleratedPresenter() |
174 : present_thread_(g_present_thread_pool.Pointer()->NextThread()) { | 180 : present_thread_(g_present_thread_pool.Pointer()->NextThread()) { |
175 } | 181 } |
176 | 182 |
177 void AcceleratedPresenter::AsyncPresentAndAcknowledge( | 183 void AcceleratedPresenter::AsyncPresentAndAcknowledge( |
178 gfx::NativeWindow window, | 184 gfx::NativeWindow window, |
179 const gfx::Size& size, | 185 const gfx::Size& size, |
180 int64 surface_id, | 186 int64 surface_id, |
181 const base::Callback<void(bool)>& completion_task) { | 187 const base::Callback<void(bool)>& completion_task) { |
182 present_thread_->message_loop()->PostTask( | 188 present_thread_->message_loop()->PostTask( |
183 FROM_HERE, | 189 FROM_HERE, |
184 base::Bind(&AcceleratedPresenter::DoPresentAndAcknowledge, | 190 base::Bind(&AcceleratedPresenter::DoPresentAndAcknowledge, |
185 this, | 191 this, |
186 window, | 192 window, |
187 size, | 193 size, |
188 surface_id, | 194 surface_id, |
189 completion_task)); | 195 completion_task)); |
190 } | 196 } |
191 | 197 |
192 bool AcceleratedPresenter::Present(gfx::NativeWindow window) { | 198 bool AcceleratedPresenter::Present(gfx::NativeWindow window) { |
193 TRACE_EVENT0("surface", "Present"); | 199 TRACE_EVENT0("surface", "Present"); |
194 | 200 |
195 HRESULT hr; | 201 HRESULT hr; |
196 | 202 |
197 base::AutoLock locked(lock_); | 203 base::AutoLock locked(lock_); |
198 | 204 |
199 // Signal the caller to recomposite if the presenter has been suspended. | 205 // Signal the caller to recomposite if the presenter has been suspended or no |
206 // surface has ever been presented. | |
200 if (!swap_chain_) | 207 if (!swap_chain_) |
201 return false; | 208 return false; |
202 | 209 |
203 RECT rect = { | 210 RECT rect = { |
204 0, 0, | 211 0, 0, |
205 size_.width(), size_.height() | 212 size_.width(), size_.height() |
206 }; | 213 }; |
207 | 214 |
208 { | 215 { |
209 TRACE_EVENT0("surface", "PresentEx"); | 216 TRACE_EVENT0("surface", "PresentEx"); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
259 gfx::NativeWindow window, | 266 gfx::NativeWindow window, |
260 const gfx::Size& size, | 267 const gfx::Size& size, |
261 int64 surface_id, | 268 int64 surface_id, |
262 const base::Callback<void(bool)>& completion_task) { | 269 const base::Callback<void(bool)>& completion_task) { |
263 TRACE_EVENT1("surface", "DoPresentAndAcknowledge", "surface_id", surface_id); | 270 TRACE_EVENT1("surface", "DoPresentAndAcknowledge", "surface_id", surface_id); |
264 | 271 |
265 HRESULT hr; | 272 HRESULT hr; |
266 | 273 |
267 base::AutoLock locked(lock_); | 274 base::AutoLock locked(lock_); |
268 | 275 |
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 |