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