blob: 592e04f91a97cdaab4c65ea1411969ef948b2950 [file] [log] [blame]
[email protected]246a70452010-03-05 21:53:501// Copyright (c) 2010 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#if defined(ENABLE_GPU)
6
7#include "base/process_util.h"
8#include "base/shared_memory.h"
[email protected]6217d392010-03-25 22:08:359#include "build/build_config.h"
[email protected]77e74db2010-08-04 17:46:2310#include "chrome/common/child_thread.h"
[email protected]246a70452010-03-05 21:53:5011#include "chrome/common/gpu_messages.h"
12#include "chrome/gpu/gpu_channel.h"
13#include "chrome/gpu/gpu_command_buffer_stub.h"
14
15using gpu::Buffer;
16
[email protected]50bd6452010-11-27 19:39:4217#if defined(OS_WIN)
18#define kCompositorWindowOwner L"CompositorWindowOwner"
[email protected]8e5cc282010-12-05 18:11:3919#endif // defined(OS_WIN)
[email protected]50bd6452010-11-27 19:39:4220
[email protected]a3ded6d2010-10-19 06:44:3921GpuCommandBufferStub::GpuCommandBufferStub(
22 GpuChannel* channel,
23 gfx::PluginWindowHandle handle,
24 GpuCommandBufferStub* parent,
25 const gfx::Size& size,
26 const std::string& allowed_extensions,
27 const std::vector<int32>& attribs,
28 uint32 parent_texture_id,
29 int32 route_id,
30 int32 renderer_id,
31 int32 render_view_id)
[email protected]246a70452010-03-05 21:53:5032 : channel_(channel),
[email protected]6ebf2fc2010-07-01 01:06:3233 handle_(handle),
[email protected]274aa5882010-07-15 21:12:2334 parent_(
35 parent ? parent->AsWeakPtr() : base::WeakPtr<GpuCommandBufferStub>()),
[email protected]6217d392010-03-25 22:08:3536 initial_size_(size),
[email protected]bc518752010-10-20 21:38:2737 allowed_extensions_(allowed_extensions),
[email protected]34ff8b0c2010-10-01 20:06:0238 requested_attribs_(attribs),
[email protected]6217d392010-03-25 22:08:3539 parent_texture_id_(parent_texture_id),
[email protected]77e74db2010-08-04 17:46:2340 route_id_(route_id),
[email protected]8e5cc282010-12-05 18:11:3941#if defined(OS_WIN)
42 compositor_window_(NULL),
43#endif // defined(OS_WIN)
[email protected]77e74db2010-08-04 17:46:2344 renderer_id_(renderer_id),
45 render_view_id_(render_view_id) {
[email protected]246a70452010-03-05 21:53:5046}
47
[email protected]50bd6452010-11-27 19:39:4248#if defined(OS_WIN)
49static LRESULT CALLBACK CompositorWindowProc(
50 HWND hwnd,
51 UINT message,
52 WPARAM wparam,
53 LPARAM lparam) {
54 switch (message) {
55 case WM_ERASEBKGND:
56 return 0;
57 case WM_DESTROY:
58 RemoveProp(hwnd, kCompositorWindowOwner);
59 return 0;
60 case WM_PAINT: {
61 PAINTSTRUCT paint;
62 HDC dc = BeginPaint(hwnd, &paint);
63 if (dc) {
64 HANDLE h = GetProp(hwnd, kCompositorWindowOwner);
65 if (h) {
66 GpuCommandBufferStub* stub =
67 reinterpret_cast<GpuCommandBufferStub*>(h);
68 stub->OnCompositorWindowPainted();
69 }
70 EndPaint(hwnd, &paint);
71 }
72 break;
73 }
74 default:
75 return DefWindowProc(hwnd, message, wparam, lparam);
76 }
77 return 0;
78}
79
80bool GpuCommandBufferStub::CreateCompositorWindow() {
81 DCHECK(handle_ != gfx::kNullPluginWindow);
82
83 // Ask the browser to create the the host window.
84 ChildThread* gpu_thread = ChildThread::current();
85 gfx::PluginWindowHandle host_window_id = gfx::kNullPluginWindow;
[email protected]f523b682010-12-06 19:01:0686 gpu_thread->Send(new GpuHostMsg_GetCompositorHostWindow(
[email protected]3f9331a2010-12-02 00:19:3487 renderer_id_,
88 render_view_id_,
89 &host_window_id));
[email protected]50bd6452010-11-27 19:39:4290 if (host_window_id == gfx::kNullPluginWindow)
91 return false;
92 HWND host_window = static_cast<HWND>(host_window_id);
93
94 // Create the compositor window itself.
95 DCHECK(host_window);
96 static ATOM window_class = 0;
97 if (!window_class) {
98 WNDCLASSEX wcex;
99 wcex.cbSize = sizeof(wcex);
100 wcex.style = 0;
101 wcex.lpfnWndProc = CompositorWindowProc;
102 wcex.cbClsExtra = 0;
103 wcex.cbWndExtra = 0;
104 wcex.hInstance = GetModuleHandle(NULL);
105 wcex.hIcon = 0;
106 wcex.hCursor = 0;
107 wcex.hbrBackground = NULL;
108 wcex.lpszMenuName = 0;
109 wcex.lpszClassName = L"CompositorWindowClass";
110 wcex.hIconSm = 0;
111 window_class = RegisterClassEx(&wcex);
112 DCHECK(window_class);
113 }
114
115 HWND compositor_window = CreateWindowEx(
116 WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
117 MAKEINTATOM(window_class),
118 0,
119 WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_DISABLED,
120 0, 0,
121 0, 0,
122 host_window,
123 0,
124 GetModuleHandle(NULL),
125 0);
126 if (!compositor_window) {
127 compositor_window_ = gfx::kNullPluginWindow;
128 return false;
129 }
130 SetProp(compositor_window, kCompositorWindowOwner,
131 reinterpret_cast<HANDLE>(this));
132
133 RECT parent_rect;
134 GetClientRect(host_window, &parent_rect);
135
136 UINT flags = SWP_NOSENDCHANGING | SWP_NOCOPYBITS | SWP_NOZORDER |
137 SWP_NOACTIVATE | SWP_DEFERERASE | SWP_SHOWWINDOW;
138 SetWindowPos(compositor_window,
139 NULL,
140 0, 0,
141 parent_rect.right - parent_rect.left,
142 parent_rect.bottom - parent_rect.top,
143 flags);
144 compositor_window_ = static_cast<gfx::PluginWindowHandle>(compositor_window);
145 return true;
146}
147
148void GpuCommandBufferStub::OnCompositorWindowPainted() {
149 ChildThread* gpu_thread = ChildThread::current();
150 gpu_thread->Send(new GpuHostMsg_ScheduleComposite(
151 renderer_id_, render_view_id_));
152}
153#endif // defined(OS_WIN)
154
155
[email protected]246a70452010-03-05 21:53:50156GpuCommandBufferStub::~GpuCommandBufferStub() {
[email protected]6217d392010-03-25 22:08:35157 if (processor_.get()) {
158 processor_->Destroy();
159 }
[email protected]50bd6452010-11-27 19:39:42160#if defined(OS_WIN)
161 if (compositor_window_) {
162 DestroyWindow(static_cast<HWND>(compositor_window_));
163 compositor_window_ = NULL;
164 }
[email protected]dd10939a2010-11-30 17:42:42165#elif defined(OS_LINUX)
166 ChildThread* gpu_thread = ChildThread::current();
167 gpu_thread->Send(
168 new GpuHostMsg_ReleaseXID(handle_));
[email protected]8e5cc282010-12-05 18:11:39169#endif // defined(OS_WIN)
[email protected]246a70452010-03-05 21:53:50170}
171
[email protected]a95986a82010-12-24 06:19:28172bool GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) {
173 bool handled = true;
[email protected]246a70452010-03-05 21:53:50174 IPC_BEGIN_MESSAGE_MAP(GpuCommandBufferStub, message)
175 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_Initialize, OnInitialize);
176 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_GetState, OnGetState);
177 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_AsyncGetState, OnAsyncGetState);
178 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_Flush, OnFlush);
179 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_AsyncFlush, OnAsyncFlush);
180 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_CreateTransferBuffer,
181 OnCreateTransferBuffer);
182 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_DestroyTransferBuffer,
183 OnDestroyTransferBuffer);
184 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_GetTransferBuffer,
185 OnGetTransferBuffer);
[email protected]6217d392010-03-25 22:08:35186 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_ResizeOffscreenFrameBuffer,
187 OnResizeOffscreenFrameBuffer);
[email protected]77e74db2010-08-04 17:46:23188#if defined(OS_MACOSX)
189 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SetWindowSize, OnSetWindowSize);
[email protected]8e5cc282010-12-05 18:11:39190#endif // defined(OS_MACOSX)
[email protected]a95986a82010-12-24 06:19:28191 IPC_MESSAGE_UNHANDLED(handled = false)
[email protected]246a70452010-03-05 21:53:50192 IPC_END_MESSAGE_MAP()
[email protected]a95986a82010-12-24 06:19:28193 DCHECK(handled);
194 return handled;
[email protected]246a70452010-03-05 21:53:50195}
196
197bool GpuCommandBufferStub::Send(IPC::Message* message) {
198 return channel_->Send(message);
199}
200
201void GpuCommandBufferStub::OnInitialize(
202 int32 size,
203 base::SharedMemoryHandle* ring_buffer) {
204 DCHECK(!command_buffer_.get());
205
206 *ring_buffer = base::SharedMemory::NULLHandle();
207
208 command_buffer_.reset(new gpu::CommandBufferService);
209
[email protected]50bd6452010-11-27 19:39:42210 // Create the child window, if needed
211#if defined(OS_WIN)
212 gfx::PluginWindowHandle output_window_handle;
213 if (handle_) {
214 if (!CreateCompositorWindow()) {
215 return;
216 }
217 output_window_handle = compositor_window_;
218 } else {
219 output_window_handle = handle_;
220 }
221#else
222 gfx::PluginWindowHandle output_window_handle = handle_;
[email protected]8e5cc282010-12-05 18:11:39223#endif // defined(OS_WIN)
[email protected]50bd6452010-11-27 19:39:42224
[email protected]246a70452010-03-05 21:53:50225 // Initialize the CommandBufferService and GPUProcessor.
226 if (command_buffer_->Initialize(size)) {
227 Buffer buffer = command_buffer_->GetRingBuffer();
228 if (buffer.shared_memory) {
[email protected]6217d392010-03-25 22:08:35229 gpu::GPUProcessor* parent_processor =
230 parent_ ? parent_->processor_.get() : NULL;
[email protected]a3ded6d2010-10-19 06:44:39231 processor_.reset(new gpu::GPUProcessor(command_buffer_.get(), NULL));
[email protected]6217d392010-03-25 22:08:35232 if (processor_->Initialize(
[email protected]50bd6452010-11-27 19:39:42233 output_window_handle,
[email protected]6217d392010-03-25 22:08:35234 initial_size_,
[email protected]a3ded6d2010-10-19 06:44:39235 allowed_extensions_.c_str(),
[email protected]34ff8b0c2010-10-01 20:06:02236 requested_attribs_,
[email protected]d37231fa2010-04-09 21:16:02237 parent_processor,
[email protected]6217d392010-03-25 22:08:35238 parent_texture_id_)) {
[email protected]246a70452010-03-05 21:53:50239 command_buffer_->SetPutOffsetChangeCallback(
240 NewCallback(processor_.get(),
241 &gpu::GPUProcessor::ProcessCommands));
[email protected]69cd41f2010-08-06 20:36:07242 processor_->SetSwapBuffersCallback(
243 NewCallback(this, &GpuCommandBufferStub::OnSwapBuffers));
[email protected]246a70452010-03-05 21:53:50244
245 // Assume service is responsible for duplicating the handle from the
246 // calling process.
247 buffer.shared_memory->ShareToProcess(channel_->renderer_handle(),
248 ring_buffer);
[email protected]77e74db2010-08-04 17:46:23249#if defined(OS_MACOSX)
250 if (handle_) {
251 // This context conceptually puts its output directly on the
252 // screen, rendered by the accelerated plugin layer in
253 // RenderWidgetHostViewMac. Set up a pathway to notify the
254 // browser process when its contents change.
255 processor_->SetSwapBuffersCallback(
256 NewCallback(this,
257 &GpuCommandBufferStub::SwapBuffersCallback));
258 }
[email protected]50bd6452010-11-27 19:39:42259#elif defined(OS_LINUX) || defined(OS_WIN)
[email protected]7ff86b92010-11-25 17:50:00260 if (handle_) {
[email protected]50bd6452010-11-27 19:39:42261 // Set up a pathway for resizing the output window at the right time
262 // relative to other GL commands.
[email protected]7ff86b92010-11-25 17:50:00263 processor_->SetResizeCallback(
264 NewCallback(this,
265 &GpuCommandBufferStub::ResizeCallback));
266 }
[email protected]8e5cc282010-12-05 18:11:39267#endif // defined(OS_MACOSX)
[email protected]246a70452010-03-05 21:53:50268 } else {
[email protected]6217d392010-03-25 22:08:35269 processor_.reset();
[email protected]246a70452010-03-05 21:53:50270 command_buffer_.reset();
271 }
272 }
273 }
274}
275
276void GpuCommandBufferStub::OnGetState(gpu::CommandBuffer::State* state) {
277 *state = command_buffer_->GetState();
278}
279
280void GpuCommandBufferStub::OnAsyncGetState() {
281 gpu::CommandBuffer::State state = command_buffer_->GetState();
282 Send(new GpuCommandBufferMsg_UpdateState(route_id_, state));
283}
284
285void GpuCommandBufferStub::OnFlush(int32 put_offset,
286 gpu::CommandBuffer::State* state) {
[email protected]b2e52d12010-12-22 23:33:58287#if defined(OS_MACOSX)
288 // See comment in |DidDestroySurface()| in gpu_processor_mac.cc.
289 if (channel_->IsRenderViewGone(render_view_id_))
290 processor_->DidDestroySurface();
291#endif
[email protected]246a70452010-03-05 21:53:50292 *state = command_buffer_->Flush(put_offset);
293}
294
295void GpuCommandBufferStub::OnAsyncFlush(int32 put_offset) {
296 gpu::CommandBuffer::State state = command_buffer_->Flush(put_offset);
297 Send(new GpuCommandBufferMsg_UpdateState(route_id_, state));
298}
299
300void GpuCommandBufferStub::OnCreateTransferBuffer(int32 size, int32* id) {
301 *id = command_buffer_->CreateTransferBuffer(size);
302}
303
304void GpuCommandBufferStub::OnDestroyTransferBuffer(int32 id) {
305 command_buffer_->DestroyTransferBuffer(id);
306}
307
308void GpuCommandBufferStub::OnGetTransferBuffer(
309 int32 id,
310 base::SharedMemoryHandle* transfer_buffer,
311 uint32* size) {
312 *transfer_buffer = base::SharedMemoryHandle();
313 *size = 0;
314
315 Buffer buffer = command_buffer_->GetTransferBuffer(id);
316 if (buffer.shared_memory) {
317 // Assume service is responsible for duplicating the handle to the calling
318 // process.
319 buffer.shared_memory->ShareToProcess(channel_->renderer_handle(),
320 transfer_buffer);
[email protected]54e3dfa22010-10-27 18:16:06321 *size = buffer.shared_memory->created_size();
[email protected]246a70452010-03-05 21:53:50322 }
323}
324
[email protected]6217d392010-03-25 22:08:35325void GpuCommandBufferStub::OnResizeOffscreenFrameBuffer(const gfx::Size& size) {
326 processor_->ResizeOffscreenFrameBuffer(size);
327}
328
[email protected]69cd41f2010-08-06 20:36:07329void GpuCommandBufferStub::OnSwapBuffers() {
330 Send(new GpuCommandBufferMsg_SwapBuffers(route_id_));
331}
332
[email protected]77e74db2010-08-04 17:46:23333#if defined(OS_MACOSX)
334void GpuCommandBufferStub::OnSetWindowSize(const gfx::Size& size) {
335 ChildThread* gpu_thread = ChildThread::current();
336 // Try using the IOSurface version first.
337 uint64 new_backing_store = processor_->SetWindowSizeForIOSurface(size);
338 if (new_backing_store) {
339 GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params params;
340 params.renderer_id = renderer_id_;
341 params.render_view_id = render_view_id_;
342 params.window = handle_;
343 params.width = size.width();
344 params.height = size.height();
345 params.identifier = new_backing_store;
346 gpu_thread->Send(new GpuHostMsg_AcceleratedSurfaceSetIOSurface(params));
347 } else {
348 // TODO(kbr): figure out what to do here. It wouldn't be difficult
349 // to support the compositor on 10.5, but the performance would be
350 // questionable.
351 NOTREACHED();
352 }
353}
354
355void GpuCommandBufferStub::SwapBuffersCallback() {
[email protected]33da8042010-11-26 20:16:18356 OnSwapBuffers();
[email protected]77e74db2010-08-04 17:46:23357 ChildThread* gpu_thread = ChildThread::current();
[email protected]33da8042010-11-26 20:16:18358 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
359 params.renderer_id = renderer_id_;
360 params.render_view_id = render_view_id_;
361 params.window = handle_;
362 params.surface_id = processor_->GetSurfaceId();
363 params.route_id = route_id();
[email protected]33da8042010-11-26 20:16:18364 params.swap_buffers_count = processor_->swap_buffers_count();
[email protected]33da8042010-11-26 20:16:18365 gpu_thread->Send(new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params));
366}
367
368void GpuCommandBufferStub::AcceleratedSurfaceBuffersSwapped(
369 uint64 swap_buffers_count) {
370 processor_->set_acknowledged_swap_buffers_count(swap_buffers_count);
371 // Wake up the GpuProcessor to start doing work again.
372 processor_->ScheduleProcessCommands();
[email protected]77e74db2010-08-04 17:46:23373}
374#endif // defined(OS_MACOSX)
375
[email protected]7ff86b92010-11-25 17:50:00376void GpuCommandBufferStub::ResizeCallback(gfx::Size size) {
[email protected]50bd6452010-11-27 19:39:42377 if (handle_ == gfx::kNullPluginWindow)
378 return;
379
380#if defined(OS_LINUX)
[email protected]7ff86b92010-11-25 17:50:00381 ChildThread* gpu_thread = ChildThread::current();
382 bool result = false;
383 gpu_thread->Send(
384 new GpuHostMsg_ResizeXID(handle_, size, &result));
[email protected]50bd6452010-11-27 19:39:42385#elif defined(OS_WIN)
386 HWND hwnd = static_cast<HWND>(compositor_window_);
387 UINT swp_flags = SWP_NOSENDCHANGING | SWP_NOOWNERZORDER | SWP_NOCOPYBITS |
388 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE;
389 SetWindowPos(hwnd, NULL, 0, 0, size.width(), size.height(), swp_flags);
[email protected]8e5cc282010-12-05 18:11:39390#endif // defined(OS_LINUX)
[email protected]7ff86b92010-11-25 17:50:00391}
[email protected]7ff86b92010-11-25 17:50:00392
[email protected]8e5cc282010-12-05 18:11:39393#endif // defined(ENABLE_GPU)