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

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

Issue 8060045: Use shared D3D9 texture to transport the compositor's backing buffer to the browser... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 2 months 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
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/lazy_instance.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/stringprintf.h"
14 #include "base/threading/thread.h"
15 #include "base/tracked_objects.h"
16 #include "base/win/wrapped_window_proc.h"
17 #include "ipc/ipc_message.h"
18 #include "ui/base/win/hwnd_util.h"
19
20 #pragma comment(lib, "d3d9.lib")
21
22 namespace {
23
24 class PresentThreadPool {
25 public:
26 static const int kNumPresentThreads = 4;
27
28 PresentThreadPool();
29
30 int NextThread();
31
32 void PostTask(int thread,
33 const tracked_objects::Location& from_here,
34 base::Closure task);
35 private:
36 int next_thread_;
37 scoped_ptr<base::Thread> present_threads_[kNumPresentThreads];
38
39 DISALLOW_COPY_AND_ASSIGN(PresentThreadPool);
40 };
41
42 base::LazyInstance<PresentThreadPool>
43 g_present_thread_pool(base::LINKER_INITIALIZED);
44
45 PresentThreadPool::PresentThreadPool() : next_thread_(0) {
46 for (int i = 0; i < kNumPresentThreads; ++i) {
47 present_threads_[i].reset(new base::Thread(
48 base::StringPrintf("PresentThread #%d", i).c_str()));
49 present_threads_[i]->Start();
50 }
51 }
52
53 int PresentThreadPool::NextThread() {
54 next_thread_ = (next_thread_ + 1) % kNumPresentThreads;
55 return next_thread_;
56 }
57
58 void PresentThreadPool::PostTask(int thread,
59 const tracked_objects::Location& from_here,
60 base::Closure task) {
61 DCHECK_GE(thread, 0);
62 DCHECK_LT(thread, kNumPresentThreads);
63
64 present_threads_[thread]->message_loop()->PostTask(from_here, task);
65 }
66
67 } // namespace anonymous
68
69 AcceleratedSurface::AcceleratedSurface(HWND parent)
70 : thread_affinity_(g_present_thread_pool.Pointer()->NextThread()),
71 window_(parent),
72 num_pending_resizes_(0) {
73 }
74
75 AcceleratedSurface::~AcceleratedSurface() {
76 // Destroy should have been called prior to the last reference going away.
77 DCHECK(!device_);
78 }
79
80 void AcceleratedSurface::Initialize() {
81 g_present_thread_pool.Pointer()->PostTask(
82 thread_affinity_,
83 FROM_HERE,
84 base::Bind(&AcceleratedSurface::DoInitialize, this));
85 }
86
87 void AcceleratedSurface::Destroy() {
88 g_present_thread_pool.Pointer()->PostTask(
89 thread_affinity_,
90 FROM_HERE,
91 base::Bind(&AcceleratedSurface::DoDestroy,
92 this,
93 MessageLoop::current()->message_loop_proxy()));
94 }
95
96 void AcceleratedSurface::AsyncPresentAndAcknowledge(
97 const gfx::Size& size,
98 int64 surface_id,
99 base::Closure completion_task) {
100 const int kRound = 64;
101 gfx::Size quantized_size(
102 std::max(1, (size.width() + kRound - 1) / kRound * kRound),
103 std::max(1, (size.height() + kRound - 1) / kRound * kRound));
104
105 if (pending_size_ != quantized_size) {
106 pending_size_ = quantized_size;
107 base::AtomicRefCountInc(&num_pending_resizes_);
108
109 g_present_thread_pool.Pointer()->PostTask(
110 thread_affinity_,
111 FROM_HERE,
112 base::Bind(&AcceleratedSurface::DoResize, this, quantized_size));
113 }
114
115 // This might unnecessarily post to the thread with which the swap chain has
116 // affinity. This will only result in potentially delaying the present.
117 g_present_thread_pool.Pointer()->PostTask(
118 num_pending_resizes_ ?
119 thread_affinity_ : g_present_thread_pool.Pointer()->NextThread(),
120 FROM_HERE,
121 base::Bind(&AcceleratedSurface::DoPresentAndAcknowledge,
122 this,
123 size,
124 surface_id,
125 completion_task));
126 }
127
128 void AcceleratedSurface::Present() {
129 HRESULT hr;
130
131 base::AutoLock locked(lock_);
132
133 if (!device_)
134 return;
135
136 RECT rect;
137 if (!GetClientRect(window_, &rect))
138 return;
139
140 hr = device_->PresentEx(&rect,
141 &rect,
142 NULL,
143 NULL,
144 D3DPRESENT_INTERVAL_IMMEDIATE);
145 if (FAILED(hr))
146 return;
147
148 hr = query_->Issue(D3DISSUE_END);
149 if (FAILED(hr))
150 return;
151
152 do {
153 hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH);
154
155 if (hr == S_FALSE)
156 Sleep(0);
157 } while (hr == S_FALSE);
158 }
159
160 void AcceleratedSurface::DoInitialize() {
161 HRESULT hr;
162
163 base::win::ScopedComPtr<IDirect3D9Ex> d3d;
164 hr = Direct3DCreate9Ex(D3D_SDK_VERSION, d3d.Receive());
165 if (FAILED(hr))
166 return;
167
168 D3DPRESENT_PARAMETERS parameters = { 0 };
169 parameters.BackBufferWidth = 1;
170 parameters.BackBufferHeight = 1;
171 parameters.BackBufferCount = 1;
172 parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
173 parameters.hDeviceWindow = window_;
174 parameters.Windowed = TRUE;
175 parameters.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
176 parameters.SwapEffect = D3DSWAPEFFECT_COPY;
177
178 hr = d3d->CreateDeviceEx(
179 D3DADAPTER_DEFAULT,
180 D3DDEVTYPE_HAL,
181 window_,
182 D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING |
183 D3DCREATE_MULTITHREADED,
184 &parameters,
185 NULL,
186 device_.Receive());
187 if (FAILED(hr))
188 return;
189
190 hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive());
191 if (FAILED(hr)) {
192 device_ = NULL;
193 return;
194 }
195
196 return;
197 }
198
199 void AcceleratedSurface::DoDestroy(
200 const scoped_refptr<base::MessageLoopProxy>& ui_message_loop) {
201 base::AutoLock locked(lock_);
202
203 device_ = NULL;
204 query_ = NULL;
205 }
206
207 void AcceleratedSurface::DoResize(const gfx::Size& size) {
208 HRESULT hr;
209
210 base::AtomicRefCountDec(&num_pending_resizes_);
211
212 D3DPRESENT_PARAMETERS parameters = { 0 };
213 parameters.BackBufferWidth = size.width();
214 parameters.BackBufferHeight = size.height();
215 parameters.BackBufferCount = 1;
216 parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
217 parameters.hDeviceWindow = window_;
218 parameters.Windowed = TRUE;
219 parameters.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
220 parameters.SwapEffect = D3DSWAPEFFECT_COPY;
221
222 hr = device_->ResetEx(&parameters, NULL);
223 if (FAILED(hr))
224 return;
225
226 size_ = size;
227
228 device_->Clear(0, NULL, D3DCLEAR_TARGET, 0xFFFFFFFF, 0, 0);
229 }
230
231 void AcceleratedSurface::DoPresentAndAcknowledge(
232 const gfx::Size& size,
233 int64 surface_id,
234 base::Closure completion_task) {
235 HRESULT hr;
236
237 base::AutoLock locked(lock_);
238
239 if (!window_)
240 return;
241
242 HANDLE handle = reinterpret_cast<HANDLE>(surface_id);
243 if (!handle)
244 return;
245
246 base::win::ScopedComPtr<IDirect3DTexture9> source_texture;
247 hr = device_->CreateTexture(size.width(),
248 size.height(),
249 1,
250 D3DUSAGE_RENDERTARGET,
251 D3DFMT_A8R8G8B8,
252 D3DPOOL_DEFAULT,
253 source_texture.Receive(),
254 &handle);
255 if (FAILED(hr))
256 return;
257
258 base::win::ScopedComPtr<IDirect3DSurface9> source_surface;
259 hr = source_texture->GetSurfaceLevel(0, source_surface.Receive());
260 if (FAILED(hr))
261 return;
262
263 base::win::ScopedComPtr<IDirect3DSurface9> dest_surface;
264 hr = device_->GetRenderTarget(0, dest_surface.Receive());
265 if (FAILED(hr))
266 return;
267
268 RECT rect = {
269 0, 0,
270 size.width(), size.height()
271 };
272
273 hr = device_->StretchRect(source_surface,
274 &rect,
275 dest_surface,
276 &rect,
277 D3DTEXF_NONE);
278 if (FAILED(hr))
279 return;
280
281 hr = query_->Issue(D3DISSUE_END);
282 if (FAILED(hr))
283 return;
284
285 // Flush so the StretchRect can be processed by the GPU while the window is
286 // being resized.
287 query_->GetData(NULL, 0, D3DGETDATA_FLUSH);
288
289 ::SetWindowPos(
290 window_,
291 NULL,
292 0, 0,
293 size.width(), size.height(),
294 SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE |SWP_NOOWNERZORDER |
295 SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_NOSENDCHANGING |
296 SWP_ASYNCWINDOWPOS);
297
298 // Wait for the StretchRect to complete before notifying the GPU process
299 // that it is safe to write to its backing store again.
300 do {
301 hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH);
302
303 if (hr == S_FALSE)
304 Sleep(0);
305 } while (hr == S_FALSE);
306
307 if (!completion_task.is_null())
308 completion_task.Run();
309
310 hr = device_->Present(&rect, &rect, NULL, NULL);
311 if (FAILED(hr))
312 return;
313 }
314
315 LRESULT CALLBACK AcceleratedSurface::ChildWndProc(HWND window,
316 unsigned int message,
317 WPARAM wparam,
318 LPARAM lparam) {
319 AcceleratedSurface* self = static_cast<AcceleratedSurface*>(
320 ui::GetWindowUserData(window));
321 switch (message) {
322 case WM_PAINT: {
323 PAINTSTRUCT paint_struct;
324 if (BeginPaint(window, &paint_struct)) {
325 self->Present();
326 EndPaint(window, &paint_struct);
327 }
328 return 0;
329 }
330 case WM_ERASEBKGND:
331 return 1;
332 }
333
334 return DefWindowProc(window, message, wparam, lparam);
335 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698