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 #include <algorithm> | |
8 | 9 |
9 #include "base/bind.h" | 10 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
11 #include "base/callback.h" | 12 #include "base/callback.h" |
12 #include "base/command_line.h" | 13 #include "base/command_line.h" |
13 #include "base/debug/trace_event.h" | 14 #include "base/debug/trace_event.h" |
14 #include "base/file_path.h" | 15 #include "base/file_path.h" |
15 #include "base/lazy_instance.h" | 16 #include "base/lazy_instance.h" |
16 #include "base/memory/scoped_ptr.h" | 17 #include "base/memory/scoped_ptr.h" |
17 #include "base/scoped_native_library.h" | 18 #include "base/scoped_native_library.h" |
(...skipping 13 matching lines...) Expand all Loading... | |
31 const wchar_t kD3D9ModuleName[] = L"d3d9.dll"; | 32 const wchar_t kD3D9ModuleName[] = L"d3d9.dll"; |
32 const char kCreate3D9DeviceExName[] = "Direct3DCreate9Ex"; | 33 const char kCreate3D9DeviceExName[] = "Direct3DCreate9Ex"; |
33 | 34 |
34 UINT GetPresentationInterval() { | 35 UINT GetPresentationInterval() { |
35 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync)) | 36 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync)) |
36 return D3DPRESENT_INTERVAL_IMMEDIATE; | 37 return D3DPRESENT_INTERVAL_IMMEDIATE; |
37 else | 38 else |
38 return D3DPRESENT_INTERVAL_ONE; | 39 return D3DPRESENT_INTERVAL_ONE; |
39 } | 40 } |
40 | 41 |
42 // Calculate the number necessary to transform |source_size| into |dest_size| | |
43 // by repeating downsampling of the image of |source_size| by a factor no more | |
44 // than 2. | |
45 int GetResampleCount(const gfx::Size& source_size, const gfx::Size& dest_size) { | |
46 int width_count = 0; | |
47 int width = source_size.width(); | |
48 while (width > dest_size.width()) { | |
49 ++width_count; | |
50 width >>= 1; | |
51 } | |
52 int height_count = 0; | |
53 int height = source_size.height(); | |
54 while (height > dest_size.height()) { | |
55 ++height_count; | |
56 height >>= 1; | |
57 } | |
58 return std::max(width_count, height_count); | |
59 } | |
60 | |
61 // Returns half the size of |size| no smaller than |min_size|. | |
62 gfx::Size GetHalfSizeNoLessThan(const gfx::Size& size, | |
63 const gfx::Size& min_size) { | |
64 return gfx::Size(std::max(min_size.width(), size.width() / 2), | |
65 std::max(min_size.height(), size.height() / 2)); | |
66 } | |
67 | |
68 bool CreateTemporarySurface(IDirect3DDevice9* device, | |
69 const gfx::Size& size, | |
70 IDirect3DSurface9** surface) { | |
71 HRESULT hr = device->CreateRenderTarget( | |
72 size.width(), | |
73 size.height(), | |
74 D3DFMT_A8R8G8B8, | |
75 D3DMULTISAMPLE_NONE, | |
76 0, | |
77 TRUE, | |
78 surface, | |
79 NULL); | |
80 return SUCCEEDED(hr); | |
81 } | |
82 | |
41 } // namespace anonymous | 83 } // namespace anonymous |
42 | 84 |
43 // A PresentThread is a thread that is dedicated to presenting surfaces to a | 85 // 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. | 86 // window. It owns a Direct3D device and a Direct3D query for this purpose. |
45 class PresentThread : public base::Thread { | 87 class PresentThread : public base::Thread { |
46 public: | 88 public: |
47 PresentThread(const char* name); | 89 PresentThread(const char* name); |
48 ~PresentThread(); | 90 ~PresentThread(); |
49 | 91 |
50 IDirect3DDevice9* device() { return device_.get(); } | 92 IDirect3DDevice9* device() { return device_.get(); } |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
137 NULL, | 179 NULL, |
138 device_.Receive()); | 180 device_.Receive()); |
139 if (FAILED(hr)) | 181 if (FAILED(hr)) |
140 return; | 182 return; |
141 | 183 |
142 hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); | 184 hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); |
143 if (FAILED(hr)) | 185 if (FAILED(hr)) |
144 device_ = NULL; | 186 device_ = NULL; |
145 } | 187 } |
146 | 188 |
189 bool AcceleratedPresenter::CopyTo(const gfx::Size& size, | |
190 void* buf) { | |
191 base::AutoLock locked(lock_); | |
192 | |
193 if (!swap_chain_) | |
194 return false; | |
195 | |
196 base::win::ScopedComPtr<IDirect3DSurface9> back_buffer; | |
197 HRESULT hr = swap_chain_->GetBackBuffer(0, | |
198 D3DBACKBUFFER_TYPE_MONO, | |
199 back_buffer.Receive()); | |
200 if (FAILED(hr)) | |
201 return false; | |
202 | |
203 D3DSURFACE_DESC desc; | |
204 hr = back_buffer->GetDesc(&desc); | |
205 if (FAILED(hr)) | |
206 return false; | |
207 | |
208 const gfx::Size back_buffer_size(desc.Width, desc.Height); | |
209 if (back_buffer_size.IsEmpty()) | |
210 return false; | |
211 | |
212 // Set up intermediate buffers needed for downsampling. | |
213 const int resample_count = | |
214 GetResampleCount(gfx::Size(desc.Width, desc.Height), size); | |
215 base::win::ScopedComPtr<IDirect3DSurface9> final_surface; | |
216 base::win::ScopedComPtr<IDirect3DSurface9> temp_buffer[2]; | |
217 if (resample_count == 0) | |
218 final_surface = back_buffer; | |
219 if (resample_count > 0) { | |
220 if (!CreateTemporarySurface(present_thread_->device(), | |
221 size, | |
222 final_surface.Receive())) | |
223 return false; | |
224 } | |
225 const gfx::Size half_size = GetHalfSizeNoLessThan(back_buffer_size, size); | |
226 if (resample_count > 1) { | |
227 if (!CreateTemporarySurface(present_thread_->device(), | |
228 half_size, | |
229 temp_buffer[0].Receive())) | |
230 return false; | |
231 } | |
232 if (resample_count > 2) { | |
233 const gfx::Size quater_size = GetHalfSizeNoLessThan(half_size, size); | |
apatrick_chromium
2012/03/12 20:25:06
quater -> quarter
mazda
2012/03/12 23:20:42
Done.
| |
234 if (!CreateTemporarySurface(present_thread_->device(), | |
235 quater_size, | |
236 temp_buffer[1].Receive())) | |
237 return false; | |
238 } | |
239 | |
240 // Repeat downsampling the surface until its size becomes identical to | |
241 // |size|. We keep the factor of each downsampling no more than two because | |
242 // using a factor more than two can introduce aliasing. | |
243 gfx::Size read_size = back_buffer_size; | |
244 gfx::Size write_size = half_size; | |
245 int read_buffer_index = 1; | |
246 int write_buffer_index = 0; | |
247 for (int i = 0; i < resample_count; ++i) { | |
248 base::win::ScopedComPtr<IDirect3DSurface9> read_buffer = | |
249 (i == 0) ? back_buffer : temp_buffer[read_buffer_index]; | |
250 base::win::ScopedComPtr<IDirect3DSurface9> write_buffer = | |
251 (i == resample_count - 1) ? final_surface : | |
252 temp_buffer[write_buffer_index]; | |
253 RECT read_rect = {0, 0, read_size.width() - 1, read_size.height() - 1}; | |
apatrick_chromium
2012/03/12 20:25:06
The Windows convention is that right and bottom ar
mazda
2012/03/12 23:20:42
Fixed. Thanks.
| |
254 RECT write_rect = {0, 0, write_size.width() - 1, write_size.height() - 1}; | |
apatrick_chromium
2012/03/12 20:25:06
Ditto.
mazda
2012/03/12 23:20:42
Done.
| |
255 hr = present_thread_->device()->StretchRect(read_buffer, | |
256 &read_rect, | |
257 write_buffer, | |
258 &write_rect, | |
259 D3DTEXF_LINEAR); | |
260 if (FAILED(hr)) | |
261 return false; | |
262 read_size = write_size; | |
263 write_size = GetHalfSizeNoLessThan(write_size, size); | |
264 std::swap(read_buffer_index, write_buffer_index); | |
265 } | |
266 | |
267 DCHECK(size == read_size); | |
268 | |
269 base::win::ScopedComPtr<IDirect3DSurface9> temp_surface; | |
270 HANDLE handle = reinterpret_cast<HANDLE>(buf); | |
271 hr = present_thread_->device()->CreateOffscreenPlainSurface( | |
272 size.width(), | |
273 size.height(), | |
274 D3DFMT_A8R8G8B8, | |
275 D3DPOOL_SYSTEMMEM, | |
276 temp_surface.Receive(), | |
277 &handle); | |
278 if (FAILED(hr)) | |
279 return false; | |
280 | |
281 // Copy the data in the temporary buffer to the surface backed by |buf|. | |
282 hr = present_thread_->device()->GetRenderTargetData(final_surface, | |
283 temp_surface); | |
284 if (FAILED(hr)) | |
285 return false; | |
286 | |
287 return true; | |
288 } | |
289 | |
147 void PresentThread::Init() { | 290 void PresentThread::Init() { |
148 TRACE_EVENT0("surface", "PresentThread::Init"); | 291 TRACE_EVENT0("surface", "PresentThread::Init"); |
149 d3d_module_.Reset(base::LoadNativeLibrary(FilePath(kD3D9ModuleName), NULL)); | 292 d3d_module_.Reset(base::LoadNativeLibrary(FilePath(kD3D9ModuleName), NULL)); |
150 ResetDevice(); | 293 ResetDevice(); |
151 } | 294 } |
152 | 295 |
153 void PresentThread::CleanUp() { | 296 void PresentThread::CleanUp() { |
154 // The D3D device and query are leaked because destroying the associated D3D | 297 // The D3D device and query are leaked because destroying the associated D3D |
155 // query crashes some Intel drivers. | 298 // query crashes some Intel drivers. |
156 device_.Detach(); | 299 device_.Detach(); |
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
430 completion_task); | 573 completion_task); |
431 } | 574 } |
432 | 575 |
433 bool AcceleratedSurface::Present(HWND window) { | 576 bool AcceleratedSurface::Present(HWND window) { |
434 if (presenter_) | 577 if (presenter_) |
435 return presenter_->Present(window); | 578 return presenter_->Present(window); |
436 else | 579 else |
437 return false; | 580 return false; |
438 } | 581 } |
439 | 582 |
583 bool AcceleratedSurface::CopyTo(const gfx::Size& size, | |
584 void* buf) { | |
585 return presenter_->CopyTo(size, buf); | |
586 } | |
587 | |
440 void AcceleratedSurface::Suspend() { | 588 void AcceleratedSurface::Suspend() { |
441 if (presenter_) | 589 if (presenter_) |
442 presenter_->Suspend(); | 590 presenter_->Suspend(); |
443 } | 591 } |
444 | |
OLD | NEW |