Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(159)

Side by Side Diff: ui/gfx/surface/accelerated_surface_win.cc

Issue 8395012: Implemented AcceleratedSurface for Windows. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/gfx/surface/accelerated_surface_win.h ('k') | ui/gfx/surface/surface.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/gfx/surface/accelerated_surface_win.h"
6
7 #include <windows.h>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/debug/trace_event.h"
12 #include "base/lazy_instance.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/stringprintf.h"
15 #include "base/threading/thread.h"
16 #include "base/tracked_objects.h"
17 #include "base/win/wrapped_window_proc.h"
18 #include "ipc/ipc_message.h"
19 #include "ui/base/win/hwnd_util.h"
20
21 #pragma comment(lib, "d3d9.lib")
22
23 namespace {
24
25 class PresentThreadPool {
26 public:
27 static const int kNumPresentThreads = 4;
28
29 PresentThreadPool();
30
31 int NextThread();
32
33 void PostTask(int thread,
34 const tracked_objects::Location& from_here,
35 base::Closure task);
36 private:
37 int next_thread_;
38 scoped_ptr<base::Thread> present_threads_[kNumPresentThreads];
39
40 DISALLOW_COPY_AND_ASSIGN(PresentThreadPool);
41 };
42
43 base::LazyInstance<PresentThreadPool>
44 g_present_thread_pool(base::LINKER_INITIALIZED);
45
46 PresentThreadPool::PresentThreadPool() : next_thread_(0) {
47 for (int i = 0; i < kNumPresentThreads; ++i) {
48 present_threads_[i].reset(new base::Thread(
49 base::StringPrintf("PresentThread #%d", i).c_str()));
50 present_threads_[i]->Start();
51 }
52 }
53
54 int PresentThreadPool::NextThread() {
55 next_thread_ = (next_thread_ + 1) % kNumPresentThreads;
56 return next_thread_;
57 }
58
59 void PresentThreadPool::PostTask(int thread,
60 const tracked_objects::Location& from_here,
61 base::Closure task) {
62 DCHECK_GE(thread, 0);
63 DCHECK_LT(thread, kNumPresentThreads);
64
65 present_threads_[thread]->message_loop()->PostTask(from_here, task);
66 }
67
68 } // namespace anonymous
69
70 AcceleratedSurface::AcceleratedSurface(HWND parent)
71 : thread_affinity_(g_present_thread_pool.Pointer()->NextThread()),
72 window_(parent),
73 num_pending_resizes_(0) {
74 }
75
76 AcceleratedSurface::~AcceleratedSurface() {
77 // Destroy should have been called prior to the last reference going away.
78 DCHECK(!device_);
79 }
80
81 void AcceleratedSurface::Initialize() {
82 g_present_thread_pool.Pointer()->PostTask(
83 thread_affinity_,
84 FROM_HERE,
85 base::Bind(&AcceleratedSurface::DoInitialize, this));
86 }
87
88 void AcceleratedSurface::Destroy() {
89 g_present_thread_pool.Pointer()->PostTask(
90 thread_affinity_,
91 FROM_HERE,
92 base::Bind(&AcceleratedSurface::DoDestroy,
93 this,
94 MessageLoop::current()->message_loop_proxy()));
95 }
96
97 void AcceleratedSurface::AsyncPresentAndAcknowledge(
98 const gfx::Size& size,
99 int64 surface_id,
100 base::Closure completion_task) {
101 const int kRound = 64;
102 gfx::Size quantized_size(
103 std::max(1, (size.width() + kRound - 1) / kRound * kRound),
104 std::max(1, (size.height() + kRound - 1) / kRound * kRound));
105
106 if (pending_size_ != quantized_size) {
107 pending_size_ = quantized_size;
108 base::AtomicRefCountInc(&num_pending_resizes_);
109
110 g_present_thread_pool.Pointer()->PostTask(
111 thread_affinity_,
112 FROM_HERE,
113 base::Bind(&AcceleratedSurface::DoResize, this, quantized_size));
114 }
115
116 // This might unnecessarily post to the thread with which the swap chain has
117 // affinity. This will only result in potentially delaying the present.
118 g_present_thread_pool.Pointer()->PostTask(
119 num_pending_resizes_ ?
120 thread_affinity_ : g_present_thread_pool.Pointer()->NextThread(),
121 FROM_HERE,
122 base::Bind(&AcceleratedSurface::DoPresentAndAcknowledge,
123 this,
124 size,
125 surface_id,
126 completion_task));
127 }
128
129 void AcceleratedSurface::Present() {
130 TRACE_EVENT0("surface", "Present");
131
132 HRESULT hr;
133
134 base::AutoLock locked(lock_);
135
136 if (!device_)
137 return;
138
139 RECT rect;
140 if (!GetClientRect(window_, &rect))
141 return;
142
143 {
144 TRACE_EVENT0("surface", "PresentEx");
145 hr = device_->PresentEx(&rect,
146 &rect,
147 NULL,
148 NULL,
149 D3DPRESENT_INTERVAL_IMMEDIATE);
150 if (FAILED(hr))
151 return;
152 }
153
154 hr = query_->Issue(D3DISSUE_END);
155 if (FAILED(hr))
156 return;
157
158 {
159 TRACE_EVENT0("surface", "spin");
160 do {
161 hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH);
162
163 if (hr == S_FALSE)
164 Sleep(0);
165 } while (hr == S_FALSE);
166 }
167 }
168
169 void AcceleratedSurface::DoInitialize() {
170 TRACE_EVENT0("surface", "DoInitialize");
171
172 HRESULT hr;
173
174 base::win::ScopedComPtr<IDirect3D9Ex> d3d;
175 hr = Direct3DCreate9Ex(D3D_SDK_VERSION, d3d.Receive());
176 if (FAILED(hr))
177 return;
178
179 D3DPRESENT_PARAMETERS parameters = { 0 };
180 parameters.BackBufferWidth = 1;
181 parameters.BackBufferHeight = 1;
182 parameters.BackBufferCount = 1;
183 parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
184 parameters.hDeviceWindow = window_;
185 parameters.Windowed = TRUE;
186 parameters.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
jbauman 2011/10/27 01:26:35 Is this necessary? Also, what presentation interva
apatrick_chromium 2011/10/27 17:44:32 I was messing with using LockRect on the back buff
187 parameters.SwapEffect = D3DSWAPEFFECT_COPY;
188
189 hr = d3d->CreateDeviceEx(
190 D3DADAPTER_DEFAULT,
191 D3DDEVTYPE_HAL,
192 window_,
193 D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING |
194 D3DCREATE_MULTITHREADED,
195 &parameters,
196 NULL,
197 device_.Receive());
198 if (FAILED(hr))
199 return;
200
201 hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive());
202 if (FAILED(hr)) {
203 device_ = NULL;
204 return;
205 }
206
207 return;
208 }
209
210 void AcceleratedSurface::DoDestroy(
211 const scoped_refptr<base::MessageLoopProxy>& ui_message_loop) {
212 TRACE_EVENT0("surface", "DoDestroy");
213
214 base::AutoLock locked(lock_);
215
216 device_ = NULL;
217 query_ = NULL;
218 }
219
220 void AcceleratedSurface::DoResize(const gfx::Size& size) {
221 TRACE_EVENT0("surface", "DoResize");
222
223 HRESULT hr;
224
225 base::AtomicRefCountDec(&num_pending_resizes_);
226
227 D3DPRESENT_PARAMETERS parameters = { 0 };
228 parameters.BackBufferWidth = size.width();
229 parameters.BackBufferHeight = size.height();
230 parameters.BackBufferCount = 1;
231 parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
232 parameters.hDeviceWindow = window_;
233 parameters.Windowed = TRUE;
234 parameters.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
235 parameters.SwapEffect = D3DSWAPEFFECT_COPY;
236
237 hr = device_->ResetEx(&parameters, NULL);
238 if (FAILED(hr))
239 return;
240
241 size_ = size;
242
243 device_->Clear(0, NULL, D3DCLEAR_TARGET, 0xFFFFFFFF, 0, 0);
244 }
245
246 void AcceleratedSurface::DoPresentAndAcknowledge(
247 const gfx::Size& size,
248 int64 surface_id,
249 base::Closure completion_task) {
250 TRACE_EVENT1("surface", "DoPresentAndAcknowledge", "surface_id", surface_id);
251
252 HRESULT hr;
253
254 base::AutoLock locked(lock_);
255
256 // Ensure the task is always run and while the lock is taken.
257 base::ScopedClosureRunner scoped_completion_runner(completion_task);
258
259 if (!window_)
260 return;
261
262 HANDLE handle = reinterpret_cast<HANDLE>(surface_id);
263 if (!handle)
264 return;
265
266 base::win::ScopedComPtr<IDirect3DTexture9> source_texture;
267 {
268 TRACE_EVENT0("surface", "CreateTexture");
269 hr = device_->CreateTexture(size.width(),
270 size.height(),
271 1,
272 D3DUSAGE_RENDERTARGET,
273 D3DFMT_A8R8G8B8,
274 D3DPOOL_DEFAULT,
275 source_texture.Receive(),
276 &handle);
277 if (FAILED(hr))
278 return;
279 }
280
281 base::win::ScopedComPtr<IDirect3DSurface9> source_surface;
282 hr = source_texture->GetSurfaceLevel(0, source_surface.Receive());
283 if (FAILED(hr))
284 return;
285
286 base::win::ScopedComPtr<IDirect3DSurface9> dest_surface;
287 hr = device_->GetRenderTarget(0, dest_surface.Receive());
288 if (FAILED(hr))
289 return;
290
291 RECT rect = {
292 0, 0,
293 size.width(), size.height()
294 };
295
296 {
297 TRACE_EVENT0("surface", "StretchRect");
298 hr = device_->StretchRect(source_surface,
299 &rect,
300 dest_surface,
301 &rect,
302 D3DTEXF_NONE);
303 if (FAILED(hr))
304 return;
305 }
306
307 hr = query_->Issue(D3DISSUE_END);
308 if (FAILED(hr))
309 return;
310
311 // Flush so the StretchRect can be processed by the GPU while the window is
312 // being resized.
313 query_->GetData(NULL, 0, D3DGETDATA_FLUSH);
314
315 ::SetWindowPos(
316 window_,
317 NULL,
318 0, 0,
319 size.width(), size.height(),
320 SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE |SWP_NOOWNERZORDER |
321 SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_NOSENDCHANGING |
322 SWP_ASYNCWINDOWPOS);
323
324 // Wait for the StretchRect to complete before notifying the GPU process
325 // that it is safe to write to its backing store again.
326 {
327 TRACE_EVENT0("surface", "spin");
328 do {
329 hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH);
330
331 if (hr == S_FALSE)
332 Sleep(0);
333 } while (hr == S_FALSE);
jbauman 2011/10/27 01:26:35 I'm a bit worried about all the extra latency we'r
apatrick_chromium 2011/10/27 17:44:32 Good idea. I'll try it.
334 }
335
336 scoped_completion_runner.Release();
337 if (!completion_task.is_null())
338 completion_task.Run();
339
340 {
341 TRACE_EVENT0("surface", "Present");
342 hr = device_->Present(&rect, &rect, NULL, NULL);
343 if (FAILED(hr))
344 return;
345 }
346 }
OLDNEW
« no previous file with comments | « ui/gfx/surface/accelerated_surface_win.h ('k') | ui/gfx/surface/surface.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698