Chromium Code Reviews| 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 |