| OLD | NEW |
| (Empty) |
| 1 // 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" | |
| 9 #include "build/build_config.h" | |
| 10 #include "chrome/gpu/gpu_channel.h" | |
| 11 #include "chrome/gpu/gpu_command_buffer_stub.h" | |
| 12 #include "chrome/gpu/gpu_thread.h" | |
| 13 #include "content/common/child_thread.h" | |
| 14 #include "content/common/gpu_messages.h" | |
| 15 | |
| 16 using gpu::Buffer; | |
| 17 | |
| 18 #if defined(OS_WIN) | |
| 19 #define kCompositorWindowOwner L"CompositorWindowOwner" | |
| 20 #endif // defined(OS_WIN) | |
| 21 | |
| 22 GpuCommandBufferStub::GpuCommandBufferStub( | |
| 23 GpuChannel* channel, | |
| 24 gfx::PluginWindowHandle handle, | |
| 25 GpuCommandBufferStub* parent, | |
| 26 const gfx::Size& size, | |
| 27 const std::string& allowed_extensions, | |
| 28 const std::vector<int32>& attribs, | |
| 29 uint32 parent_texture_id, | |
| 30 int32 route_id, | |
| 31 int32 renderer_id, | |
| 32 int32 render_view_id) | |
| 33 : channel_(channel), | |
| 34 handle_(handle), | |
| 35 parent_( | |
| 36 parent ? parent->AsWeakPtr() : base::WeakPtr<GpuCommandBufferStub>()), | |
| 37 initial_size_(size), | |
| 38 allowed_extensions_(allowed_extensions), | |
| 39 requested_attribs_(attribs), | |
| 40 parent_texture_id_(parent_texture_id), | |
| 41 route_id_(route_id), | |
| 42 #if defined(OS_WIN) | |
| 43 compositor_window_(NULL), | |
| 44 #endif // defined(OS_WIN) | |
| 45 renderer_id_(renderer_id), | |
| 46 render_view_id_(render_view_id) { | |
| 47 } | |
| 48 | |
| 49 #if defined(OS_WIN) | |
| 50 static LRESULT CALLBACK CompositorWindowProc( | |
| 51 HWND hwnd, | |
| 52 UINT message, | |
| 53 WPARAM wparam, | |
| 54 LPARAM lparam) { | |
| 55 switch (message) { | |
| 56 case WM_ERASEBKGND: | |
| 57 return 0; | |
| 58 case WM_DESTROY: | |
| 59 RemoveProp(hwnd, kCompositorWindowOwner); | |
| 60 return 0; | |
| 61 case WM_PAINT: { | |
| 62 PAINTSTRUCT paint; | |
| 63 HDC dc = BeginPaint(hwnd, &paint); | |
| 64 if (dc) { | |
| 65 HANDLE h = GetProp(hwnd, kCompositorWindowOwner); | |
| 66 if (h) { | |
| 67 GpuCommandBufferStub* stub = | |
| 68 reinterpret_cast<GpuCommandBufferStub*>(h); | |
| 69 stub->OnCompositorWindowPainted(); | |
| 70 } | |
| 71 EndPaint(hwnd, &paint); | |
| 72 } | |
| 73 break; | |
| 74 } | |
| 75 default: | |
| 76 return DefWindowProc(hwnd, message, wparam, lparam); | |
| 77 } | |
| 78 return 0; | |
| 79 } | |
| 80 | |
| 81 bool GpuCommandBufferStub::CreateCompositorWindow() { | |
| 82 DCHECK(handle_ != gfx::kNullPluginWindow); | |
| 83 HWND host_window = static_cast<HWND>(handle_); | |
| 84 | |
| 85 // Create the compositor window itself. | |
| 86 DCHECK(host_window); | |
| 87 static ATOM window_class = 0; | |
| 88 if (!window_class) { | |
| 89 WNDCLASSEX wcex; | |
| 90 wcex.cbSize = sizeof(wcex); | |
| 91 wcex.style = 0; | |
| 92 wcex.lpfnWndProc = CompositorWindowProc; | |
| 93 wcex.cbClsExtra = 0; | |
| 94 wcex.cbWndExtra = 0; | |
| 95 wcex.hInstance = GetModuleHandle(NULL); | |
| 96 wcex.hIcon = 0; | |
| 97 wcex.hCursor = 0; | |
| 98 wcex.hbrBackground = NULL; | |
| 99 wcex.lpszMenuName = 0; | |
| 100 wcex.lpszClassName = L"CompositorWindowClass"; | |
| 101 wcex.hIconSm = 0; | |
| 102 window_class = RegisterClassEx(&wcex); | |
| 103 DCHECK(window_class); | |
| 104 } | |
| 105 | |
| 106 HWND compositor_window = CreateWindowEx( | |
| 107 WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR, | |
| 108 MAKEINTATOM(window_class), | |
| 109 0, | |
| 110 WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_DISABLED, | |
| 111 0, 0, | |
| 112 0, 0, | |
| 113 host_window, | |
| 114 0, | |
| 115 GetModuleHandle(NULL), | |
| 116 0); | |
| 117 if (!compositor_window) { | |
| 118 compositor_window_ = gfx::kNullPluginWindow; | |
| 119 return false; | |
| 120 } | |
| 121 SetProp(compositor_window, kCompositorWindowOwner, | |
| 122 reinterpret_cast<HANDLE>(this)); | |
| 123 | |
| 124 RECT parent_rect; | |
| 125 GetClientRect(host_window, &parent_rect); | |
| 126 | |
| 127 UINT flags = SWP_NOSENDCHANGING | SWP_NOCOPYBITS | SWP_NOZORDER | | |
| 128 SWP_NOACTIVATE | SWP_DEFERERASE | SWP_SHOWWINDOW; | |
| 129 SetWindowPos(compositor_window, | |
| 130 NULL, | |
| 131 0, 0, | |
| 132 parent_rect.right - parent_rect.left, | |
| 133 parent_rect.bottom - parent_rect.top, | |
| 134 flags); | |
| 135 compositor_window_ = static_cast<gfx::PluginWindowHandle>(compositor_window); | |
| 136 return true; | |
| 137 } | |
| 138 | |
| 139 void GpuCommandBufferStub::OnCompositorWindowPainted() { | |
| 140 GpuThread* gpu_thread = channel_->gpu_thread(); | |
| 141 gpu_thread->Send(new GpuHostMsg_ScheduleComposite( | |
| 142 renderer_id_, render_view_id_)); | |
| 143 } | |
| 144 #endif // defined(OS_WIN) | |
| 145 | |
| 146 | |
| 147 GpuCommandBufferStub::~GpuCommandBufferStub() { | |
| 148 if (processor_.get()) { | |
| 149 processor_->Destroy(); | |
| 150 } | |
| 151 #if defined(OS_WIN) | |
| 152 if (compositor_window_) { | |
| 153 DestroyWindow(static_cast<HWND>(compositor_window_)); | |
| 154 compositor_window_ = NULL; | |
| 155 } | |
| 156 #endif // defined(OS_WIN) | |
| 157 | |
| 158 GpuThread* gpu_thread = channel_->gpu_thread(); | |
| 159 gpu_thread->Send(new GpuHostMsg_DestroyCommandBuffer( | |
| 160 handle_, renderer_id_, render_view_id_)); | |
| 161 } | |
| 162 | |
| 163 bool GpuCommandBufferStub::OnMessageReceived(const IPC::Message& message) { | |
| 164 bool handled = true; | |
| 165 IPC_BEGIN_MESSAGE_MAP(GpuCommandBufferStub, message) | |
| 166 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_Initialize, OnInitialize); | |
| 167 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_GetState, OnGetState); | |
| 168 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_AsyncGetState, OnAsyncGetState); | |
| 169 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_Flush, OnFlush); | |
| 170 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_AsyncFlush, OnAsyncFlush); | |
| 171 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_CreateTransferBuffer, | |
| 172 OnCreateTransferBuffer); | |
| 173 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_RegisterTransferBuffer, | |
| 174 OnRegisterTransferBuffer); | |
| 175 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_DestroyTransferBuffer, | |
| 176 OnDestroyTransferBuffer); | |
| 177 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_GetTransferBuffer, | |
| 178 OnGetTransferBuffer); | |
| 179 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_ResizeOffscreenFrameBuffer, | |
| 180 OnResizeOffscreenFrameBuffer); | |
| 181 #if defined(OS_MACOSX) | |
| 182 IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_SetWindowSize, OnSetWindowSize); | |
| 183 #endif // defined(OS_MACOSX) | |
| 184 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 185 IPC_END_MESSAGE_MAP() | |
| 186 DCHECK(handled); | |
| 187 return handled; | |
| 188 } | |
| 189 | |
| 190 bool GpuCommandBufferStub::Send(IPC::Message* message) { | |
| 191 return channel_->Send(message); | |
| 192 } | |
| 193 | |
| 194 void GpuCommandBufferStub::OnInitialize( | |
| 195 base::SharedMemoryHandle ring_buffer, | |
| 196 int32 size, | |
| 197 bool* result) { | |
| 198 DCHECK(!command_buffer_.get()); | |
| 199 | |
| 200 *result = false; | |
| 201 | |
| 202 command_buffer_.reset(new gpu::CommandBufferService); | |
| 203 | |
| 204 // Create the child window, if needed | |
| 205 #if defined(OS_WIN) | |
| 206 gfx::PluginWindowHandle output_window_handle; | |
| 207 if (handle_) { | |
| 208 if (!CreateCompositorWindow()) { | |
| 209 return; | |
| 210 } | |
| 211 output_window_handle = compositor_window_; | |
| 212 } else { | |
| 213 output_window_handle = handle_; | |
| 214 } | |
| 215 #else | |
| 216 gfx::PluginWindowHandle output_window_handle = handle_; | |
| 217 #endif // defined(OS_WIN) | |
| 218 | |
| 219 #if defined(OS_WIN) | |
| 220 // Windows dups the shared memory handle it receives into the current process | |
| 221 // and closes it when this variable goes out of scope. | |
| 222 base::SharedMemory shared_memory(ring_buffer, | |
| 223 false, | |
| 224 channel_->renderer_process()); | |
| 225 #else | |
| 226 // POSIX receives a dup of the shared memory handle and closes the dup when | |
| 227 // this variable goes out of scope. | |
| 228 base::SharedMemory shared_memory(ring_buffer, false); | |
| 229 #endif | |
| 230 | |
| 231 // Initialize the CommandBufferService and GPUProcessor. | |
| 232 if (command_buffer_->Initialize(&shared_memory, size)) { | |
| 233 gpu::GPUProcessor* parent_processor = | |
| 234 parent_ ? parent_->processor_.get() : NULL; | |
| 235 processor_.reset(new gpu::GPUProcessor(command_buffer_.get(), NULL)); | |
| 236 if (processor_->Initialize( | |
| 237 output_window_handle, | |
| 238 initial_size_, | |
| 239 allowed_extensions_.c_str(), | |
| 240 requested_attribs_, | |
| 241 parent_processor, | |
| 242 parent_texture_id_)) { | |
| 243 command_buffer_->SetPutOffsetChangeCallback( | |
| 244 NewCallback(processor_.get(), | |
| 245 &gpu::GPUProcessor::ProcessCommands)); | |
| 246 processor_->SetSwapBuffersCallback( | |
| 247 NewCallback(this, &GpuCommandBufferStub::OnSwapBuffers)); | |
| 248 | |
| 249 #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 } | |
| 259 #endif // defined(OS_MACOSX) | |
| 260 | |
| 261 // Set up a pathway for resizing the output window or framebuffer at the | |
| 262 // right time relative to other GL commands. | |
| 263 processor_->SetResizeCallback( | |
| 264 NewCallback(this, &GpuCommandBufferStub::ResizeCallback)); | |
| 265 | |
| 266 *result = true; | |
| 267 } else { | |
| 268 processor_.reset(); | |
| 269 command_buffer_.reset(); | |
| 270 } | |
| 271 } | |
| 272 } | |
| 273 | |
| 274 void GpuCommandBufferStub::OnGetState(gpu::CommandBuffer::State* state) { | |
| 275 *state = command_buffer_->GetState(); | |
| 276 } | |
| 277 | |
| 278 void GpuCommandBufferStub::OnAsyncGetState() { | |
| 279 gpu::CommandBuffer::State state = command_buffer_->GetState(); | |
| 280 Send(new GpuCommandBufferMsg_UpdateState(route_id_, state)); | |
| 281 } | |
| 282 | |
| 283 void GpuCommandBufferStub::OnFlush(int32 put_offset, | |
| 284 gpu::CommandBuffer::State* state) { | |
| 285 #if defined(OS_MACOSX) | |
| 286 // See comment in |DidDestroySurface()| in gpu_processor_mac.cc. | |
| 287 if (channel_->IsRenderViewGone(render_view_id_)) | |
| 288 processor_->DidDestroySurface(); | |
| 289 #endif | |
| 290 *state = command_buffer_->FlushSync(put_offset); | |
| 291 } | |
| 292 | |
| 293 void GpuCommandBufferStub::OnAsyncFlush(int32 put_offset) { | |
| 294 gpu::CommandBuffer::State state = command_buffer_->FlushSync(put_offset); | |
| 295 Send(new GpuCommandBufferMsg_UpdateState(route_id_, state)); | |
| 296 } | |
| 297 | |
| 298 void GpuCommandBufferStub::OnCreateTransferBuffer(int32 size, int32* id) { | |
| 299 *id = command_buffer_->CreateTransferBuffer(size); | |
| 300 } | |
| 301 | |
| 302 void GpuCommandBufferStub::OnRegisterTransferBuffer( | |
| 303 base::SharedMemoryHandle transfer_buffer, | |
| 304 size_t size, | |
| 305 int32* id) { | |
| 306 #if defined(OS_WIN) | |
| 307 // Windows dups the shared memory handle it receives into the current process | |
| 308 // and closes it when this variable goes out of scope. | |
| 309 base::SharedMemory shared_memory(transfer_buffer, | |
| 310 false, | |
| 311 channel_->renderer_process()); | |
| 312 #else | |
| 313 // POSIX receives a dup of the shared memory handle and closes the dup when | |
| 314 // this variable goes out of scope. | |
| 315 base::SharedMemory shared_memory(transfer_buffer, false); | |
| 316 #endif | |
| 317 | |
| 318 *id = command_buffer_->RegisterTransferBuffer(&shared_memory, size); | |
| 319 } | |
| 320 | |
| 321 void GpuCommandBufferStub::OnDestroyTransferBuffer(int32 id) { | |
| 322 command_buffer_->DestroyTransferBuffer(id); | |
| 323 } | |
| 324 | |
| 325 void GpuCommandBufferStub::OnGetTransferBuffer( | |
| 326 int32 id, | |
| 327 base::SharedMemoryHandle* transfer_buffer, | |
| 328 uint32* size) { | |
| 329 *transfer_buffer = base::SharedMemoryHandle(); | |
| 330 *size = 0; | |
| 331 | |
| 332 // Fail if the renderer process has not provided its process handle. | |
| 333 if (!channel_->renderer_process()) | |
| 334 return; | |
| 335 | |
| 336 Buffer buffer = command_buffer_->GetTransferBuffer(id); | |
| 337 if (buffer.shared_memory) { | |
| 338 // Assume service is responsible for duplicating the handle to the calling | |
| 339 // process. | |
| 340 buffer.shared_memory->ShareToProcess(channel_->renderer_process(), | |
| 341 transfer_buffer); | |
| 342 *size = buffer.size; | |
| 343 } | |
| 344 } | |
| 345 | |
| 346 void GpuCommandBufferStub::OnResizeOffscreenFrameBuffer(const gfx::Size& size) { | |
| 347 processor_->ResizeOffscreenFrameBuffer(size); | |
| 348 } | |
| 349 | |
| 350 void GpuCommandBufferStub::OnSwapBuffers() { | |
| 351 Send(new GpuCommandBufferMsg_SwapBuffers(route_id_)); | |
| 352 } | |
| 353 | |
| 354 #if defined(OS_MACOSX) | |
| 355 void GpuCommandBufferStub::OnSetWindowSize(const gfx::Size& size) { | |
| 356 GpuThread* gpu_thread = channel_->gpu_thread(); | |
| 357 // Try using the IOSurface version first. | |
| 358 uint64 new_backing_store = processor_->SetWindowSizeForIOSurface(size); | |
| 359 if (new_backing_store) { | |
| 360 GpuHostMsg_AcceleratedSurfaceSetIOSurface_Params params; | |
| 361 params.renderer_id = renderer_id_; | |
| 362 params.render_view_id = render_view_id_; | |
| 363 params.window = handle_; | |
| 364 params.width = size.width(); | |
| 365 params.height = size.height(); | |
| 366 params.identifier = new_backing_store; | |
| 367 gpu_thread->Send(new GpuHostMsg_AcceleratedSurfaceSetIOSurface(params)); | |
| 368 } else { | |
| 369 // TODO(kbr): figure out what to do here. It wouldn't be difficult | |
| 370 // to support the compositor on 10.5, but the performance would be | |
| 371 // questionable. | |
| 372 NOTREACHED(); | |
| 373 } | |
| 374 } | |
| 375 | |
| 376 void GpuCommandBufferStub::SwapBuffersCallback() { | |
| 377 OnSwapBuffers(); | |
| 378 GpuThread* gpu_thread = channel_->gpu_thread(); | |
| 379 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; | |
| 380 params.renderer_id = renderer_id_; | |
| 381 params.render_view_id = render_view_id_; | |
| 382 params.window = handle_; | |
| 383 params.surface_id = processor_->GetSurfaceId(); | |
| 384 params.route_id = route_id(); | |
| 385 params.swap_buffers_count = processor_->swap_buffers_count(); | |
| 386 gpu_thread->Send(new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params)); | |
| 387 } | |
| 388 | |
| 389 void GpuCommandBufferStub::AcceleratedSurfaceBuffersSwapped( | |
| 390 uint64 swap_buffers_count) { | |
| 391 processor_->set_acknowledged_swap_buffers_count(swap_buffers_count); | |
| 392 // Wake up the GpuProcessor to start doing work again. | |
| 393 processor_->ScheduleProcessCommands(); | |
| 394 } | |
| 395 #endif // defined(OS_MACOSX) | |
| 396 | |
| 397 void GpuCommandBufferStub::ResizeCallback(gfx::Size size) { | |
| 398 if (handle_ == gfx::kNullPluginWindow) { | |
| 399 processor_->decoder()->ResizeOffscreenFrameBuffer(size); | |
| 400 processor_->decoder()->UpdateOffscreenFrameBufferSize(); | |
| 401 } else { | |
| 402 #if defined(OS_LINUX) && !defined(TOUCH_UI) | |
| 403 GpuThread* gpu_thread = channel_->gpu_thread(); | |
| 404 bool result = false; | |
| 405 gpu_thread->Send( | |
| 406 new GpuHostMsg_ResizeXID(handle_, size, &result)); | |
| 407 #elif defined(OS_WIN) | |
| 408 HWND hwnd = static_cast<HWND>(compositor_window_); | |
| 409 UINT swp_flags = SWP_NOSENDCHANGING | SWP_NOOWNERZORDER | SWP_NOCOPYBITS | | |
| 410 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE; | |
| 411 SetWindowPos(hwnd, NULL, 0, 0, size.width(), size.height(), swp_flags); | |
| 412 #endif // defined(OS_LINUX) | |
| 413 } | |
| 414 } | |
| 415 | |
| 416 #endif // defined(ENABLE_GPU) | |
| OLD | NEW |