Monday, July 8, 2013

How GPU Process work in multi process

I analysed GPU Process in InProcess mode. Refer to http://luxtella.blogspot.de/2013/06/gpu-process-analysis-hellotriangleexe.html

In this article, I analyse GPU Process in multi processs.

In Host

Pivotal classes are WebGraphicsContext3DCommandBufferImpl, CommandBufferProxyImpl, CommandBufferHelper.

Store cmd in Ring buffer

stack trace is as follows
gpu::CommandBufferHelper::WaitForAvailableEntries()
gpu::CommandBufferHelper::GetSpace()
gpu::gles2::GLES2Implementation::BindTexture()
content::WebGraphicsContext3DCommandBufferImpl::bindTexture()
cc::ResourceProvider::BindForSampling()
cc::GLRenderer::DrawContentQuad()
cc::GLRenderer::DoDrawQuad()
cc::DirectRenderer::DrawRenderPass()
cc::DirectRenderer::DrawFrame()
cc::LayerTreeHostImpl::DrawLayers()
cc::SingleThreadProxy::DoComposite()
cc::SingleThreadProxy::CommitAndComposite()
cc::SingleThreadProxy::CompositeImmediately()
content::RenderWidget::Composite()
content::RenderWidget::DoDeferredUpdate()
content::RenderWidget::DoDeferredUpdateAndSendInputAck()
content::RenderWidget::OnViewContextSwapBuffersComplete()
base::MessageLoop::RunTask()
base::MessageLoop::DeferOrRunPendingTask()
base::MessageLoop::DoWork()
base::MessagePumpDefault::Run()
base::MessageLoop::RunInternal()
base::RunLoop::Run()
base::MessageLoop::Run()
content::RendererMain()
content::RunZygote()
content::RunNamedProcessTypeMain()
content::ContentMainRunnerImpl::Run()
content::ContentMain()
main

WebGraphicsContext3D::bindTexture() calls GLES2Implementation::BindTexture()
void GLES2Implementation::BindTexture(GLenum target, GLuint texture) {
  ...
  if (IsTextureReservedId(texture)) {
    SetGLError(GL_INVALID_OPERATION, "BindTexture", "texture reserved id");
    return;
  }
  if (BindTextureHelper(target, texture)) {
    helper_->BindTexture(target, texture);
  }
  CheckGLError();
}

and GLES2CmdHelper::BindTexture is called.
void BindTexture(GLenum target, GLuint texture) {
    gles2::cmds::BindTexture* c = GetCmdSpace[gles2::cmds::BindTexture]();
    if (c) {
      c->Init(target, texture);
    }
  }

and CommandBufferHelper::GetSpace is called to alloc msg.
CommandBufferEntry* CommandBufferHelper::GetSpace(uint32 entries) {
  AllocateRingBuffer();
  if (!usable()) {
    return NULL;
  }
  GPU_DCHECK(HaveRingBuffer());
  ++commands_issued_;
  WaitForAvailableEntries(entries);
  CommandBufferEntry* space = &entries_[put_];
  put_ += entries;
  GPU_DCHECK_LE(put_, total_entry_count_);
  if (put_ == total_entry_count_) {
    put_ = 0;
  }
  return space;
}

WaitForAvailableEntries() calls CommandBufferHelper::FlushSync() if ring buffer is full.

Send cmd to GPU Process

stack trace is as follows
In common, SwapBuffer sends msg to GPU Process.
content::CommandBufferProxyImpl::Flush()
content::CompositorOutputSurface::SwapBuffers()
cc::GLRenderer::SwapBuffers()
cc::LayerTreeHostImpl::SwapBuffers()
cc::SingleThreadProxy::CompositeImmediately()
content::RenderWidget::Composite()
content::RenderWidget::DoDeferredUpdate()
content::RenderWidget::DoDeferredUpdateAndSendInputAck()
content::RenderWidget::OnViewContextSwapBuffersComplete()
base::MessageLoop::RunTask()
base::MessageLoop::DeferOrRunPendingTask()
base::MessageLoop::DoWork()
base::MessagePumpDefault::Run()
base::MessageLoop::RunInternal()
base::RunLoop::Run()
base::MessageLoop::Run()
content::RendererMain()
content::RunZygote()
content::RunNamedProcessTypeMain()
content::ContentMainRunnerImpl::Run()
content::ContentMain()
main
It is important to remember that getter also sends msg to GPU Process.
content::CommandBufferProxyImpl::Flush()
content::CommandBufferProxyImpl::FlushSync()
gpu::CommandBufferHelper::FlushSync()
gpu::CommandBufferHelper::Finish()
gpu::gles2::GLES2Implementation::WaitForCmd()
gpu::gles2::GLES2Implementation::GetBucketContents()
gpu::gles2::GLES2Implementation::GetBucketAsString()
gpu::gles2::GLES2Implementation::GetStringHelper()
gpu::gles2::GLES2Implementation::GetString()
content::WebGraphicsContext3DCommandBufferImpl::getString()
cc::GLRenderer::Initialize()
cc::GLRenderer::Create()
cc::LayerTreeHostImpl::CreateAndSetRenderer()
cc::LayerTreeHostImpl::InitializeRenderer()
cc::SingleThreadProxy::CreateAndInitializeOutputSurface()
cc::LayerTreeHost::InitializeOutputSurfaceIfNeeded()
cc::SingleThreadProxy::CommitAndComposite()
cc::SingleThreadProxy::CompositeImmediately()
content::RenderWidget::Composite()
content::RenderWidget::DoDeferredUpdate()
content::RenderWidget::DoDeferredUpdateAndSendInputAck()
content::RenderWidget::InvalidationCallback()
base::MessageLoop::RunTask()
...

CommandBufferProxyImpl::Flush() send GpuCommandBufferMsg_AsyncFlush to GPU Process to run stored cmds.
When sending GpuCommandBufferMsg_AsyncFlush, send offset on ring buffer and flush count as flush id.
void CommandBufferProxyImpl::Flush(int32 put_offset) {
  ...
  Send(new GpuCommandBufferMsg_AsyncFlush(route_id_,
                                          put_offset,
                                          ++flush_count_));
}

FYI, just see how cmd looks like

GLES2CmdHelper::BindTexture calls gles2::cmds::BindTexture::Init()
in gles2_cmd_format_autogen.h
struct BindTexture {
  typedef BindTexture ValueType;
  static const CommandId kCmdId = kBindTexture;
  static const cmd::ArgFlags kArgFlags = cmd::kFixed;

  static uint32 ComputeSize() {
    return static_cast(sizeof(ValueType));  // NOLINT
  }

  void SetHeader() {
    header.SetCmd();
  }

  void Init(GLenum _target, GLuint _texture) {
    SetHeader();
    target = _target;
    texture = _texture;
  }

  void* Set(void* cmd, GLenum _target, GLuint _texture) {
    static_cast(cmd)->Init(_target, _texture);
    return NextCmdAddress(cmd);
  }

  gpu::CommandHeader header;
  uint32 target;
  uint32 texture;
};

In GPU Process

Pivotal classes are GpuCommandBufferStub, CommandBufferService, GpuScheduler, CommandParser, GLES2DecoderImpl

Run cmd

stacktrace is as follows
gpu::gles2::GLES2DecoderImpl::DoBindTexture()
gpu::gles2::GLES2DecoderImpl::HandleBindTexture()
gpu::gles2::GLES2DecoderImpl::DoCommand()
gpu::CommandParser::ProcessCommand()
gpu::GpuScheduler::PutChanged()
gpu::CommandBufferService::Flush()
content::GpuCommandBufferStub::OnAsyncFlush()
_ZN30GpuCommandBufferMsg_AsyncFlush8DispatchIN7content20GpuCommandBufferStubES2_MS2_FvijEEEbPKN3IPC7MessageEPT_PT0_T1_.isra.51
content::GpuCommandBufferStub::OnMessageReceived()
content::MessageRouter::RouteMessage()
content::GpuChannel::HandleMessage()
base::MessageLoop::RunTask()
base::MessageLoop::DeferOrRunPendingTask()
base::MessageLoop::DoWork()
base::MessagePumpDefault::Run()
base::MessageLoop::RunInternal()
base::RunLoop::Run()
base::MessageLoop::Run()
content::GpuMain()
content::RunNamedProcessTypeMain()
content::ContentMainRunnerImpl::Run()
content::ContentMain()
main

As I mentioned in previous article, GLES2DecoderImpl calls real gl call via GLApi. Refer to gl_bindings_autogen_gl.cc and gl_gl_api_implementation.h

Where MakeCurrent()

GpuCommandBufferStub::OnMessageReceived() call GpuCommandBufferStub::MakeCurrent() before handling msg.
GpuCommandBufferStub::MakeCurrent() has two tasks.
1. glMakeCurrent() via decoder
2. If there is a error, handle lostContext.
bool GpuCommandBufferStub::MakeCurrent() {
  if (decoder_->MakeCurrent())
    return true;
  DLOG(ERROR) << "Context lost because MakeCurrent failed.";
  command_buffer_->SetContextLostReason(decoder_->GetContextLostReason());
  command_buffer_->SetParseError(gpu::error::kLostContext);
  if (gfx::GLContext::LosesAllContextsOnContextLost())
    channel_->LoseAllContexts();
  return false;
}


Compare to InProcess.

CommandBuffer

- Multi Process: WebGraphicsContext3DCommandBufferImpl uses CommandBufferProxyImpl. CommandBufferProxyImpl communicates to CommandBufferService via IPC
- InProcess : WebGraphicsContext3DInProcessCommandBufferImpl use directly CommandBufferService

Who control CommandBufferService. They must handle various exceptions (i.e. lostContext)

- Multi Process: GpuCommandBufferStub
- InProcess: GLInProcessContext

Both handle exceptions before gpu::GpuScheduler::PutChanged(). How does CommandBufferService::Flush() calls gpu::GpuScheduler::PutChanged() while CommandBufferService does not know GpuScheduler.

in GpuCommandBufferStub::OnInitialize()
  command_buffer_->SetPutOffsetChangeCallback(
      base::Bind(&GpuCommandBufferStub::PutChanged, base::Unretained(this)));

in GLInProcessContext::Initialize()
  command_buffer->SetPutOffsetChangeCallback(base::Bind(
      &GLInProcessContextImpl::PumpCommands, base::Unretained(this)));
Both register various callbacks to CommandBufferService as well as OffsetChangeCallback.

Tuesday, June 25, 2013

Extract Path and Symbols from Chromium to index Eclipse CDT

Eclipse CDT can analysis build message and extract Path and Symbols.
I use Ubuntu 13.04. Other OS I don't care. I hate both Mac and Window.

There is not one way to do that. However, I prefer what I describe here, because I don't like build chromium in Eclipse.

If you like to build chromium in Eclipse, refer to https://code.google.com/p/chromium/wiki/LinuxEclipseDev
For more information, refer to https://developer.mozilla.org/en-US/docs/Eclipse_CDT

My way consists of 2 step.
1. record build message
2. extract Path and Symbols using power of CDT.

1. record build message

> ninja -C out/Debug -j 80 -v -n chrome content_shell > build-message
> sed -i "s/g++/gcc/g" build-message
> sed -i "s/\[\S* gcc/gcc/g" build-message
> sed -i "s/-I\.\.\/\./-I/g" build-message

2. extract Path and Symbols using power of CDT.

1. open project Properties window
2. go "C/C++ Build > Discovery Options"
3. Select "Configuration-wide" in "Discovery profiles scope"
 a. check "Automate discovery of paths and symbols"
 b. check Report path deltection problems"
 c. "GCC per file scanner infor profile" in Discovery profile
 d. check Enable build output scanner info discovery
4. select "build-message" file via Browse... button.
5. click Load button

6. Refresh project
7. Rebuild index

build message for WebKit

QT
make -B -n make_default > build-message

GTK
make -B -n all-am > build-message



expand your Eclipse memory

CDT indexing needs so much memory


change your eclipse.ini file, my settings


org.eclipse.platform
--launcher.XXMaxPermSize
2G
--launcher.defaultAction
openFile
-vmargs
-Dosgi.requiredJavaVersion=1.5
-Dhelp.lucene.tokenizer=standard
-XX:MaxPermSize=2G
-Xms2G
-Xmx7G

increase your index memory

1. open Window>Preferences
2. go C/C++ > Indexer
3. change Cache limits : in my settings, 70%, 6144MB, 6144MB



trouble shooting

You will feel that indexing is gradually slow with repeated updating index.

It it time to rebuild index. Don't assume that clicking rebuild is fine. Real rebuild is a bit more complicated.

go to indexing directory
> cd [workspace]/.metadata/.plugins/org.eclipse.cdt.core
> rm [project name]*

Indexing is not free, it is stored in your persistent storage. Chromium indexing consume about 1GB.

And click rebuild.




Thursday, June 20, 2013

GPU Process analysis: hello_triangle_exe (GPU Process on single process and single thread)

GPU Process has demo project for example. There is hello_triangle_exe. I analysis hellow_triangle_exe to understand GPU Process.

How to build

> export GYP_GENERATORS='ninja'
> export GYP_GENERATOR_FLAGS="output_dir=out_gpu"
> export CHROMIUM_GYP_FILE="gpu/demos/demos.gyp"
> ./build/gyp_chromium
> ninja -C out_gpu/Release -j 6 hello_triangle_exe


Overview (seq. diagram)

origin: http://www.diagrammr.com/edit?key=dQ65fKDGRSz

demo does not launch gpu process or thread. However if we create GLES2SmdHelper with CommandBufferProxy instead of CommandBufferService, it would be possible to launch gpu process. How? I don't know yet.

callstack

Final glcall's callstack in above fig.
gfx::GLApiBase::glShaderSourceFn - gl_bindings_autogen_gl.cc, line 3817
gpu::gles2::ProgramManager::ForceCompileShader - program_manager.cc, line 489
gpu::gles2::ProgramManager::DoCompileShader - program_manager.cc, line 461
gpu::gles2::GLES2DecoderImpl::DoCompileShader - gles2_cmd_decoder.cc, line 6258
gpu::gles2::GLES2DecoderImpl::HandleCompileShader - gles2_cmd_decoder_autogen.h, line 330
gpu::gles2::GLES2DecoderImpl::DoCommand - gles2_cmd_decoder.cc, line 3490
gpu::CommandParser::ProcessCommand - cmd_parser.cc, line 72
gpu::GpuScheduler::PutChanged - gpu_scheduler.cc, line 78
base::internal::RunnableAdapter{void (gpu::GpuScheduler::*)()}::Run - bind_internal.h, line 134
base::internal::InvokeHelper{fals - bind_internal.h, line 871
base::internal::Invoker{ - bind_internal.h, line 1169
base::Callback{void ()}::Run() const - callback.h, line 396
gpu::CommandBufferService::FlushSync - command_buffer_service.cc, line 78
gpu::CommandBufferHelper::FlushSync - cmd_buffer_helper.cc, line 109
gpu::CommandBufferHelper::Finish - cmd_buffer_helper.cc, line 136
gpu::gles2::GLES2Implementation::WaitForCmd - gles2_implementation.cc, line 317
gpu::gles2::GLES2Implementation::GetShaderiv - gles2_implementation_impl_autogen.h, line 711
GLES2GetShaderiv - gles2_c_lib_autogen.h, line 254
esLoadShader - esShader.c, line 61
esLoadProgram - esShader.c, line 104
htInit - Hello_Triangle.c, line 47
gpu::demos::gles2_book::Example{HTUserData}::InitGL - example.h, line 54
gpu::demos::Window::Init - window.cc, line 63
main - main_exe.cc, line 34

How to control which call either GLES2Impl or GLApi


use GLES2Impl
It means using GPU Process.

  • #include <GLES2/gl2.h> 
  • #include "gpu/command_buffer/client/gles2_lib.h" and call like ::gles2::GetGLContext()->SwapBuffers() 
use GLApi
It means calling gl directly.
  • #include "ui/gl/gl_gl_api_implementation.h"




Tuesday, June 18, 2013

backtrace of creating root window and focus handling of chromium aura

It is not well-defined article. It is just note to help me remember something.

1. backtrace when web contents get focus by pushing tab key.

views::corewm::FocusController::FocusWindow() at focus_controller.cc:128 0x555559ed281a 
aura::Window::Focus() at window.cc:579 0x5555577648a8 
content::RenderWidgetHostViewAura::Focus() at render_widget_host_view_aura.cc:937 0x555558b07b4a 
content::WebContentsViewAura::Focus() at web_contents_view_aura.cc:907 0x555558b84699 
views::WebView::OnFocus() at webview.cc:129 0x55555968fee0 
views::View::Focus() at view.cc:1,527 0x555559e8631c 
views::FocusManager::SetFocusedViewWithReason() at focus_manager.cc:335 0x555559e6b1d2 
views::FocusManager::AdvanceFocus() at focus_manager.cc:154 0x555559e6a8d0 
views::FocusManager::OnKeyEvent() at focus_manager.cc:87 0x555559e6a43f 
views::DesktopNativeWidgetAura::OnKeyEvent() at desktop_native_widget_aura.cc:713 0x555559e91405 
ui::EventHandler::OnEvent() at event_handler.cc:25 0x55555a91db90 
ui::EventTarget::OnEvent() at event_target.cc:54 0x55555a91f021 
ui::EventDispatcher::DispatchEvent() at event_dispatcher.cc:145 0x55555a91cb62 
ui::EventDispatcher::ProcessEvent() at event_dispatcher.cc:93 0x55555a91c6e3 
ui::EventDispatcherDelegate::DispatchEvent() at event_dispatcher.cc:48 0x55555a91c415 
aura::RootWindow::ProcessEvent() at root_window.cc:761 0x555557773d84 
aura::RootWindow::OnHostKeyEvent() at root_window.cc:896 0x555557774670 
views::corewm::InputMethodEventFilter::DispatchKeyEventPostIME() at input_method_event_filter.cc:72 0x555559ed7771 
ui::FakeInputMethod::DispatchKeyEvent() at fake_input_method.cc:82 0x55555a9a2f2e 
views::corewm::InputMethodEventFilter::OnKeyEvent() at input_method_event_filter.cc:54 0x555559ed76c5 
views::corewm::CompoundEventFilter::FilterKeyEvent() at compound_event_filter.cc:147 0x555559ecd1ab 
views::corewm::CompoundEventFilter::OnKeyEvent() at compound_event_filter.cc:213 0x555559ecd53e 
ui::EventHandler::OnEvent() at event_handler.cc:25 0x55555a91db90 
ui::EventDispatcher::DispatchEvent() at event_dispatcher.cc:145 0x55555a91cb62 
ui::EventDispatcher::DispatchEventToEventHandlers() at event_dispatcher.cc:124 0x55555a91c947 
ui::EventDispatcher::ProcessEvent() at event_dispatcher.cc:82 0x55555a91c656 
ui::EventDispatcherDelegate::DispatchEvent() at event_dispatcher.cc:48 0x55555a91c415 
aura::RootWindow::ProcessEvent() at root_window.cc:761 0x555557773d84 
aura::RootWindow::OnHostKeyEvent() at root_window.cc:896 0x555557774670 
views::DesktopRootWindowHostX11::Dispatch() at desktop_root_window_host_x11.cc:940 0x555559e976d3 
base::MessagePumpAuraX11::Dispatch() at message_pump_aurax11.cc:304 0x55555a04920b 
base::MessagePumpAuraX11::ProcessXEvent() at message_pump_aurax11.cc:249 0x55555a048e49 
base::MessagePumpAuraX11::DispatchXEvents() at message_pump_aurax11.cc:191 0x55555a0487b6 
() at message_pump_aurax11.cc:33 0x55555a047f42 
g_main_dispatch() at gmain.c:2,715 0x7ffff6d80ab5 
g_main_context_dispatch() at gmain.c:3,219 0x7ffff6d80ab5 
g_main_context_iterate() at gmain.c:3,290 0x7ffff6d80de8 
g_main_context_iteration() at gmain.c:3,351 0x7ffff6d80ea4 
base::MessagePumpGlib::RunWithDispatcher() at message_pump_glib.cc:199 0x55555a0461c2 
base::MessagePumpGlib::Run() at message_pump_glib.cc:296 0x55555a0466fe 
base::MessageLoop::RunInternal() at message_loop.cc:441 0x55555a096fa2 
base::MessageLoop::RunHandler() at message_loop.cc:414 0x55555a096e4c 
base::RunLoop::Run() at run_loop.cc:45 0x55555a0c891c 
ChromeBrowserMainParts::MainMessageLoopRun() at chrome_browser_main.cc:1,620 0x55555656d0c0 
content::BrowserMainLoop::RunMainMessageLoopParts() at browser_main_loop.cc:620 0x555558937bb0 
content::BrowserMainRunnerImpl::Run() at browser_main_runner.cc:113 0x555558bc4704 
content::BrowserMain() at browser_main.cc:22 0x55555bc8301c 
content::RunNamedProcessTypeMain() at content_main_runner.cc:433 0x55555a48c2b0 
content::ContentMainRunnerImpl::Run() at content_main_runner.cc:756 0x55555a48d307 
content::ContentMain() at content_main.cc:35 0x55555a48b677 
ChromeMain() at chrome_main.cc:32 0x555555e6f535 
main() at chrome_exe_main_aura.cc:17 0x555555e6f500 

2. backtrace when web contents loses focus.

views::FocusManager::AdvanceFocus() at focus_manager.cc:142 0x555559e6a857 
ChromeWebContentsViewDelegateViews::TakeFocus() at chrome_web_contents_view_delegate_views.cc:90 0x555558ee8494 
content::WebContentsViewAura::TakeFocus() at web_contents_view_aura.cc:1,149 0x555558b85688 
content::RenderViewHostImpl::OnTakeFocus() at render_view_host_impl.cc:1,521 0x555558ad3cca 
DispatchToMethod{content::RenderViewHostImpl, void () at tuple.h:546 0x555558adb26f 
ViewHostMsg_TakeFocus::Dispatch{content::RenderViewHostImpl, content::RenderViewHostImpl, void () at view_messages.h:1,942 0x555558ad8e3e 
content::RenderViewHostImpl::OnMessageReceived() at render_view_host_impl.cc:979 0x555558ad10e1 
content::RenderProcessHostImpl::OnMessageReceived() at render_process_host_impl.cc:1,224 0x555558ab992e 
IPC::ChannelProxy::Context::OnDispatchMessage() at ipc_channel_proxy.cc:261 0x5555569ee4c3 
base::internal::RunnableAdapter{void () at bind_internal.h:190 0x5555569f1e9d 
base::internal::InvokeHelper{false, void, base::internal::RunnableAdapter{void () at bind_internal.h:898 0x5555569f1982 
base::internal::Invoker{2, base::internal::BindState{base::internal::RunnableAdapter{void () at bind_internal.h:1,253 0x5555569f11c0 
base::Callback{void () at callback.h:396 0x555555efcb8a 
base::MessageLoop::RunTask() at message_loop.cc:484 0x55555a097407 
base::MessageLoop::DeferOrRunPendingTask() at message_loop.cc:496 0x55555a097536 
base::MessageLoop::DoWork() at message_loop.cc:688 0x55555a097e77 
base::MessagePumpGlib::HandleDispatch() at message_pump_glib.cc:273 0x55555a046625 
() at message_pump_glib.cc:105 0x55555a045ded 


3. backtrace when creating rootwindow by dragging TabStrip.

views::DesktopRootWindowHostX11::Init() at desktop_root_window_host_x11.cc:343 0x555559e94c8f 
views::DesktopNativeWidgetAura::InitNativeWidget() at desktop_native_widget_aura.cc:240 0x555559e8f775 
DesktopBrowserFrameAura::InitNativeWidget() at desktop_browser_frame_aura.cc:54 0x55555904bb69 
views::Widget::Init() at widget.cc:374 0x555559ea73e1 
BrowserFrame::InitBrowserFrame() at browser_frame.cc:78 0x555559049423 
BrowserWindow::CreateBrowserWindow() at browser_view.cc:2,618 0x555558e9df6d 
() at browser.cc:235 0x555558db983c 
Browser::Browser() at browser.cc:402 0x555558dba8a8 
TabDragController::CreateBrowserForDrag() at tab_drag_controller.cc:2,037 0x5555590780a8 
TabDragController::DetachIntoNewBrowserAndRunMoveLoop() at tab_drag_controller.cc:1,320 0x555559074cb3 
TabDragController::DragBrowserToNewTabStrip() at tab_drag_controller.cc:827 0x555559072325 
TabDragController::ContinueDragging() at tab_drag_controller.cc:785 0x555559072072 
TabDragController::Drag() at tab_drag_controller.cc:510 0x555559070c28 
TabStrip::ContinueDrag() at tab_strip.cc:1,150 0x555558ef93ed 
TabStrip::OnMouseDragged() at tab_strip.cc:1,527 0x555558efab67 
views::View::ProcessMouseDragged() at view.cc:2,146 0x555559e88f94 
views::View::OnMouseEvent() at view.cc:973 0x555559e8401e 
ui::EventHandler::OnEvent() at event_handler.cc:27 0x55555a91dbc3 
ui::EventTarget::OnEvent() at event_target.cc:56 0x55555a91f03c 
ui::EventDispatcher::DispatchEvent() at event_dispatcher.cc:145 0x55555a91cb62 
ui::EventDispatcher::ProcessEvent() at event_dispatcher.cc:93 0x55555a91c6e3 
ui::EventDispatcherDelegate::DispatchEvent() at event_dispatcher.cc:48 0x55555a91c415 
views::internal::RootView::DispatchEventToTarget() at root_view.cc:666 0x555559e9fb84 
views::internal::RootView::OnMouseDragged() at root_view.cc:468 0x555559e9ed44 
views::Widget::OnMouseEvent() at widget.cc:1,160 0x555559ea9ed6 
views::DesktopNativeWidgetAura::OnMouseEvent() at desktop_native_widget_aura.cc:721 0x555559e9157c 
ui::EventHandler::OnEvent() at event_handler.cc:27 0x55555a91dbc3 
ui::EventTarget::OnEvent() at event_target.cc:54 0x55555a91f021 
ui::EventDispatcher::DispatchEvent() at event_dispatcher.cc:145 0x55555a91cb62 
ui::EventDispatcher::ProcessEvent() at event_dispatcher.cc:93 0x55555a91c6e3 
ui::EventDispatcherDelegate::DispatchEvent() at event_dispatcher.cc:48 0x55555a91c415 
aura::RootWindow::ProcessEvent() at root_window.cc:761 0x555557773d84 
aura::RootWindow::DispatchMouseEventToTarget() at root_window.cc:1,079 0x55555777511e 
aura::RootWindow::DispatchMouseEventImpl() at root_window.cc:1,023 0x555557774dfc 
aura::RootWindow::OnHostMouseEvent() at root_window.cc:916 0x55555777475d 
views::DesktopRootWindowHostX11::DispatchMouseEvent() at desktop_root_window_host_x11.cc:559 0x555559e95bbd 
views::DesktopRootWindowHostX11::Dispatch() at desktop_root_window_host_x11.cc:1,062 0x555559e97dfa 
base::MessagePumpAuraX11::Dispatch() at message_pump_aurax11.cc:304 0x55555a04920b 
base::MessagePumpAuraX11::ProcessXEvent() at message_pump_aurax11.cc:249 0x55555a048e49 
base::MessagePumpAuraX11::DispatchXEvents() at message_pump_aurax11.cc:191 0x55555a0487b6 
() at message_pump_aurax11.cc:33 0x55555a047f42 
g_main_dispatch() at gmain.c:2,715 0x7ffff6d80ab5 

4. backtrace when creating rootwindow by popping up context menu.

views::DesktopRootWindowHostX11::Init() at desktop_root_window_host_x11.cc:343 0x555559e94c8f 
views::DesktopNativeWidgetAura::InitNativeWidget() at desktop_native_widget_aura.cc:240 0x555559e8f775 
views::Widget::Init() at widget.cc:374 0x555559ea73e1 
views::MenuHost::InitMenuHost() at menu_host.cc:53 0x555559ec6fc4 
views::SubmenuView::ShowAt() at submenu_view.cc:312 0x555559e36167 
views::MenuController::OpenMenuImpl() at menu_controller.cc:1,529 0x555559ebf240 
views::MenuController::OpenMenu() at menu_controller.cc:1,504 0x555559ebf067 
views::MenuController::CommitPendingSelection() at menu_controller.cc:1,468 0x555559ebebcf 
views::MenuController::SetSelection() at menu_controller.cc:811 0x555559ebc4de 
views::MenuController::Run() at menu_controller.cc:333 0x555559eba633 
views::internal::MenuRunnerImpl::RunMenuAt() at menu_runner.cc:225 0x555559e327a9 
views::MenuRunner::RunMenuAt() at menu_runner.cc:351 0x555559e32e32 
RenderViewContextMenuViews::RunMenuAt() at render_view_context_menu_views.cc:52 0x555558ee8faa 
ChromeWebContentsViewDelegateViews::ShowContextMenu() at chrome_web_contents_view_delegate_views.cc:169 0x555558ee8783 
content::WebContentsViewAura::ShowContextMenu() at web_contents_view_aura.cc:1,061 0x555558b85076 
content::WebContentsImpl::ShowContextMenu() at web_contents_impl.cc:1,695 0x555558b6943b 
content::RenderViewHostImpl::OnContextMenu() at render_view_host_impl.cc:1,364 0x555558ad324d 
DispatchToMethod{content::RenderViewHostImpl, void () at tuple.h:546 0x555558adb202 
ViewHostMsg_ContextMenu::Dispatch{content::RenderViewHostImpl, content::RenderViewHostImpl, void () at view_messages.h:1,435 0x555558ad8747 
content::RenderViewHostImpl::OnMessageReceived() at render_view_host_impl.cc:956 0x555558ad07b3 
content::RenderProcessHostImpl::OnMessageReceived() at render_process_host_impl.cc:1,224 0x555558ab992e 
IPC::ChannelProxy::Context::OnDispatchMessage() at ipc_channel_proxy.cc:261 0x5555569ee4c3 
base::internal::RunnableAdapter{void () at bind_internal.h:190 0x5555569f1e9d 
base::internal::InvokeHelper{false, void, base::internal::RunnableAdapter{void () at bind_internal.h:898 0x5555569f1982 
base::internal::Invoker{2, base::internal::BindState{base::internal::RunnableAdapter{void () at bind_internal.h:1,253 0x5555569f11c0 
base::Callback{void () at callback.h:396 0x555555efcb8a 
base::MessageLoop::RunTask() at message_loop.cc:484 0x55555a097407 
base::MessageLoop::DeferOrRunPendingTask() at message_loop.cc:496 0x55555a097536 
base::MessageLoop::DoWork() at message_loop.cc:688 0x55555a097e77 
base::MessagePumpGlib::HandleDispatch() at message_pump_glib.cc:273 0x55555a046625 
() at message_pump_glib.cc:105 0x55555a045ded 
g_main_dispatch() at gmain.c:2,715 0x7ffff6d80ab5 

Thursday, May 30, 2013

content_shell with aura : XWindow and event loop

Let's look around how content_shell with aura creates XWindow and handle X input events.

Before reading this article, plz read http://luxtella.blogspot.de/2013/05/chromium-launching-process.html

Create MessagePump needed for TYPE_UI MessageLoops.

aura uses g_main_context for event source. why does aura depend on glib although creating pure X Window. It is just because of convenience. aura developers just did not want to reinvent timer and event source. let's look at how to integrate g_main_context and XDisplay events.

MessagePumpGlib plays a role to create g_main_context and event sources to receive tasks from another thread. MessagePumpGlib is reused by MessagePumpGtk.
MessagePumpGlib::MessagePumpGlib()
    : state_(NULL),
      context_(g_main_context_default()),
      wakeup_gpollfd_(new GPollFD) {
  ...
}

Before looking at MessagePumpAuraX11, let's look at MessagePumpGtk.
MessagePumpGtk plays a role to dispatch input events to main context.
MessagePumpGtk::MessagePumpGtk() : MessagePumpGlib() {
  gdk_event_handler_set(&EventDispatcher, this, NULL);
}

So we can expect MessagePumpAuraX11's role is to dispatching X Display events to main loop. how to cast magic?
InitXSource() is crucial. It creates g event source monitoring X Display. When g_main_context handles the event source, XSourceDispatch() will be called. how smart!
MessagePumpAuraX11::MessagePumpAuraX11() : MessagePumpGlib(),
    x_source_(NULL) {
  InitializeXInput2();
  InitializeXkb();
  InitXSource();

  // Can't put this in the initializer list because g_xdisplay may not exist
  // until after InitXSource().
  x_root_window_ = DefaultRootWindow(g_xdisplay);
}

void MessagePumpAuraX11::InitXSource() {
  Display* display = GetDefaultXDisplay();
  x_poll_.reset(new GPollFD());
  x_poll_->fd = ConnectionNumber(display);
  x_poll_->events = G_IO_IN;

  x_source_ = g_source_new(&XSourceFuncs, sizeof(GSource));
  g_source_add_poll(x_source_, x_poll_.get());
  g_source_set_can_recurse(x_source_, TRUE);
  g_source_set_callback(x_source_, NULL, this, NULL);
  g_source_attach(x_source_, g_main_context_default());
}

GSourceFuncs XSourceFuncs = {
  XSourcePrepare,
  XSourceCheck,
  XSourceDispatch,
  NULL
};

gboolean XSourceDispatch(GSource* source,
                         GSourceFunc unused_func,
                         gpointer data) {
  base::MessagePumpAuraX11* pump = static_cast{base::MessagePumpAuraX11*}(data);
  return pump->DispatchXEvents();
}
base::MessagePumpGlib::MessagePumpGlib() at message_pump_glib.cc:142 0x4d5ec6 
base::MessagePumpAuraX11::MessagePumpAuraX11() at message_pump_aurax11.cc:132 0x4d8510 
base::MessageLoop::MessageLoop() at message_loop.cc:182 0x471fbb 
content::BrowserMainLoop::MainMessageLoopStart() at browser_main_loop.cc:370 0x81aa6e 
content::BrowserMainRunnerImpl::Initialize() at browser_main_runner.cc:94 0x6010f0 
ShellBrowserMain() at shell_browser_main.cc:116 0x43cb76 
content::ShellMainDelegate::RunProcess() at shell_main_delegate.cc:155 0x422892 
content::RunNamedProcessTypeMain() at content_main_runner.cc:421 0xf12728 
content::ContentMainRunnerImpl::Run() at content_main_runner.cc:756 0xf13833 
content::ContentMain() at content_main.cc:35 0xf11b2f 
main() at shell_main.cc:36 0x4220cd 

Main loop

MessagePumpGlib::RunWithDispatcher() is main loop. Chromium does not use glib main loop because chromium want to run chromium's own tasks without starvation.
X Display input events are handled by g_main_context_iteration(context_, block), because the input events are bound to glib event source.
void MessagePumpGlib::RunWithDispatcher(Delegate* delegate,
                                        MessagePumpDispatcher* dispatcher) {
  ..
  for (;;) {
    ..
    more_work_is_plausible = g_main_context_iteration(context_, block);
    ..
    more_work_is_plausible |= state_->delegate->DoWork();
    ..
    more_work_is_plausible |= state_->delegate->DoDelayedWork(&delayed_work_time_);
    ..
    more_work_is_plausible = state_->delegate->DoIdleWork();
    ..
  }
  ..
}
base::MessagePumpGlib::RunWithDispatcher() at message_pump_glib.cc:199 0x4d6282 
base::MessagePumpGlib::Run() at message_pump_glib.cc:296 0x4d67be 
base::MessageLoop::RunInternal() at message_loop.cc:441 0x47385a 
base::MessageLoop::RunHandler() at message_loop.cc:414 0x473704 
base::RunLoop::Run() at run_loop.cc:45 0x497abc 
content::BrowserMainLoop::MainMessageLoopRun() at browser_main_loop.cc:873 0x81c6d7 
content::BrowserMainLoop::RunMainMessageLoopParts() at browser_main_loop.cc:571 0x81b85e 
content::BrowserMainRunnerImpl::Run() at browser_main_runner.cc:125 0x6012bc 
ShellBrowserMain() at shell_browser_main.cc:180 0x43cfe3 
content::ShellMainDelegate::RunProcess() at shell_main_delegate.cc:155 0x422892 
content::RunNamedProcessTypeMain() at content_main_runner.cc:421 0xf12728 
content::ContentMainRunnerImpl::Run() at content_main_runner.cc:756 0xf13833 
content::ContentMain() at content_main.cc:35 0xf11b2f 
main() at shell_main.cc:36 0x4220cd 

Create WebContentesViewAura.

This callstack is almost same to it of content_shell gtk. aura::Window is not related to native window or widget. It is something like cc::Layer + window event handler.

aura::Window::Window() at window.cc:51 0x51cfaa 
content::WebContentsViewAura::CreateView() at web_contents_view_aura.cc:944 0x7dab1b 
content::WebContentsImpl::Init() at web_contents_impl.cc:1,193 0x7bdcae 
content::WebContentsImpl::CreateWithOpener() at web_contents_impl.cc:405 0x7b897a 
content::WebContents::Create() at web_contents_impl.cc:262 0x7b78ed 
content::Shell::CreateNewWindow() at shell.cc:165 0x44db67 
content::ShellBrowserMainParts::PreMainMessageLoopRun() at shell_browser_main_parts.cc:132 0x453289 
content::BrowserMainLoop::CreateThreads() at browser_main_loop.cc:554 0x81b792 
content::BrowserMainRunnerImpl::Initialize() at browser_main_runner.cc:112 0x601108 
ShellBrowserMain() at shell_browser_main.cc:116 0x43cb76 
content::ShellMainDelegate::RunProcess() at shell_main_delegate.cc:155 0x422892 
content::RunNamedProcessTypeMain() at content_main_runner.cc:421 0xf12728 
content::ContentMainRunnerImpl::Run() at content_main_runner.cc:756 0xf13833 
content::ContentMain() at content_main.cc:35 0xf11b2f 
main() at shell_main.cc:36 0x4220cd 

On the other hands, when loading another page, new RenderWidgetHostViewAura is created and new aura::Window is also created.
aura::Window::Window() at window.cc:51 0x51cfaa 
content::RenderWidgetHostViewAura::RenderWidgetHostViewAura() at render_widget_host_view_aura.cc:626 0x75f75d 
content::RenderWidgetHostView::CreateViewForWidget() at render_widget_host_view_aura.cc:2,992 0x769eb5 
content::WebContentsViewAura::CreateViewForWidget() at web_contents_view_aura.cc:992 0x7dae49 
content::WebContentsImpl::CreateRenderViewForRenderManager() at web_contents_impl.cc:3,481 0x7c7895 
content::RenderViewHostManager::InitRenderView() at render_view_host_manager.cc:663 0x9c7720 
content::RenderViewHostManager::Navigate() at render_view_host_manager.cc:140 0x9c5a6d 
...

Create XWindow and RootWindow

Create XWindow

DesktopRootWindowHostX11 creates XWindow, installs dispatcher for XWindow (XDisplay receives all input events for all XWindows), and requests Input events to XServer.
void DesktopRootWindowHostX11::InitX11Window(
    const Widget::InitParams& params) {
  ..
  xwindow_ = XCreateWindow(
      xdisplay_, x_root_window_,
      ..
      &swa);
  base::MessagePumpAuraX11::Current()->AddDispatcherForWindow(this, xwindow_);

  // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().

  long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
                    KeyPressMask | KeyReleaseMask |
                    EnterWindowMask | LeaveWindowMask |
                    ExposureMask | VisibilityChangeMask |
                    StructureNotifyMask | PropertyChangeMask |
                    PointerMotionMask;
  XSelectInput(xdisplay_, xwindow_, event_mask);
  ..
}
views::DesktopRootWindowHostX11::InitX11Window() at desktop_root_window_host_x11.cc:157 0xce36cb 
views::DesktopRootWindowHostX11::Init() at desktop_root_window_host_x11.cc:357 0xce45c1 
views::DesktopNativeWidgetAura::InitNativeWidget() at desktop_native_widget_aura.cc:239 0xcdf031 
views::Widget::Init() at widget.cc:374 0xcf5219 
views::Widget::CreateWindowWithBounds() at widget.cc:239 0xcf4b5d 
content::Shell::PlatformCreateWindow() at shell_aura.cc:348 0x450379 
content::Shell::CreateShell() at shell.cc:105 0x44d753 
content::Shell::CreateNewWindow() at shell.cc:166 0x44db82 
content::ShellBrowserMainParts::PreMainMessageLoopRun() at shell_browser_main_parts.cc:132 0x453289 
content::BrowserMainLoop::CreateThreads() at browser_main_loop.cc:554 0x81b792 
content::BrowserMainRunnerImpl::Initialize() at browser_main_runner.cc:112 0x601108 
ShellBrowserMain() at shell_browser_main.cc:116 0x43cb76 
content::ShellMainDelegate::RunProcess() at shell_main_delegate.cc:155 0x422892 
content::RunNamedProcessTypeMain() at content_main_runner.cc:421 0xf12728 
content::ContentMainRunnerImpl::Run() at content_main_runner.cc:756 0xf13833 
content::ContentMain() at content_main.cc:35 0xf11b2f 
main() at shell_main.cc:36 0x4220cd 

Create RootWindow

DesktopRootWindowHostX11 creates aura::RootWindow. RootWindow owns Compositor. FYI, chrome can create multi RootWindows. For example, context menu requires a XWindow and RootWindow.
RootWindow::RootWindow(const CreateParams& params)
    : Window(NULL),
      ..
      repostable_event_factory_(this) {
  ..
  compositor_.reset(new ui::Compositor(this, host_->GetAcceleratedWidget()));
  ..
}
aura::RootWindow::RootWindow() at root_window.cc:162 0x512ef4 
views::DesktopRootWindowHostX11::InitRootWindow() at desktop_root_window_host_x11.cc:230 0xce3add 
views::DesktopRootWindowHostX11::Init() at desktop_root_window_host_x11.cc:358 0xce45d4 
views::DesktopNativeWidgetAura::InitNativeWidget() at desktop_native_widget_aura.cc:239 0xcdf031 
....

Handle mouse event

XDisplay input event is dispatched to MessagePumpAuraX11::DispatchXEvents(), because XDisplay events are bound with glib event source. Refer to "Create MessagePump needed for TYPE_UI MessageLoops."
DispatchXEvents() consumes all pending X events.
bool MessagePumpAuraX11::DispatchXEvents() {
  ...
  while (XPending(display)) {
    XEvent xev;
    XNextEvent(display, &xev);
    if (dispatcher && ProcessXEvent(dispatcher, &xev))
      return TRUE;
  }
  return TRUE;
}

DesktopRootWindowHostX11 installed dispatcher into MessagePumpAuraX11, so X event is dispatched to DesktopRootWindowHostX11 that owns specific X Window.

DesktopRootWindowHostX11::Dispatch(const base::NativeEvent& event) converts X Event to ui::Event.

And then finally aura::RootWindow::OnHostMouseEvent() handles ui::MouseEvent.
aura::RootWindow::OnHostMouseEvent() at root_window.cc:902 0x516c2d 
views::DesktopRootWindowHostX11::DispatchMouseEvent() at desktop_root_window_host_x11.cc:560 0xce540b 
views::DesktopRootWindowHostX11::Dispatch() at desktop_root_window_host_x11.cc:1,075 0xce7632 
base::MessagePumpAuraX11::Dispatch() at message_pump_aurax11.cc:304 0x4d92cb 
base::MessagePumpAuraX11::ProcessXEvent() at message_pump_aurax11.cc:249 0x4d8f09 
base::MessagePumpAuraX11::DispatchXEvents() at message_pump_aurax11.cc:191 0x4d8876 
() at message_pump_aurax11.cc:33 0x4d8002 
g_main_dispatch() at gmain.c:2,715 0x7ffff6973ab5 
g_main_context_dispatch() at gmain.c:3,219 0x7ffff6973ab5 
g_main_context_iterate() at gmain.c:3,290 0x7ffff6973de8 
g_main_context_iteration() at gmain.c:3,351 0x7ffff6973ea4 
base::MessagePumpGlib::RunWithDispatcher() at message_pump_glib.cc:199 0x4d6282 
base::MessagePumpGlib::Run() at message_pump_glib.cc:296 0x4d67be 
base::MessageLoop::RunInternal() at message_loop.cc:441 0x47385a 
base::MessageLoop::RunHandler() at message_loop.cc:414 0x473704 
base::RunLoop::Run() at run_loop.cc:45 0x497abc 
content::BrowserMainLoop::MainMessageLoopRun() at browser_main_loop.cc:873 0x81c6d7 
content::BrowserMainLoop::RunMainMessageLoopParts() at browser_main_loop.cc:571 0x81b85e 
content::BrowserMainRunnerImpl::Run() at browser_main_runner.cc:125 0x6012bc 
ShellBrowserMain() at shell_browser_main.cc:180 0x43cfe3 
content::ShellMainDelegate::RunProcess() at shell_main_delegate.cc:155 0x422892 
content::RunNamedProcessTypeMain() at content_main_runner.cc:421 0xf12728 
content::ContentMainRunnerImpl::Run() at content_main_runner.cc:756 0xf13833 
content::ContentMain() at content_main.cc:35 0xf11b2f 
main() at shell_main.cc:36 0x4220cd 

Wednesday, May 29, 2013

useful x utils

Post it to not forget them. Thx alex for sharing.

xrandr - primitive command line interface to RandR extension

use case :

1. query screen, device, and etc

> xrandr

2. change dpi. It is useful when debugging device scale factor on Blink.

> xrandr --dpi 150

xwininfo - window information utility for X

use case :

1. query XID of an application

> xwininfo

2. query XID tree

> xwininfo -tree

xdotool - command-line X11 automation tool

use case :

1. reparent a window. for example, you can see your application (e.g. content_shell) via another application.

> xdotool windowreparent [source_window] destination_window

refer to XReparentWindow(3)


xdpyinfo - display information utility for X

use case :

1. query DPI



> xdpyinfo | grep inch


Tuesday, May 28, 2013

How Gpu process draws contents on the surface of Browser process's window in chromium.

This article explains how Gpu process draws in linux platform.
At the end of article, I'll mention briefly about aura and Android.

What do three processes do?

Gpu process draws contents on the surface of Browser process's window. Briefly, following steps achieve it.
  1. Browser process creates RenderWidgetHostView (GtkWidget)
  2. Browser process sends Window id of backend view (of RenderWidgetHostView)  to Gpu Process  
  3. Gpu Process creates GL context and GLX Surface bound in Window id. (Gpu Process will draw everything on the surface)
  4. Render Process paints GraphicsLayer tree on GraphicsContext3D.
  5. All gl commends that cc calls in Render process are replayed on GLX Surface bound in Window id in Gpu Process.
  6. Browser process draws non-client widgets (e.g. button, url field and tab button).

Initialize: how Gpu process knows render widget

FYI, surface id is just number of GtkWidget so that Browser process tracks surface id and compositing surface  (= GLSurfaceHandle including Window XID in X or EGLNativeWindowType in EGL) pair.

In Browser process, RenderViewHostImpl::CreateRenderView() sends surface_id to Render process

bool RenderViewHostImpl::CreateRenderView(
    const string16& frame_name,
    int opener_route_id,
    int32 max_page_id) {
  ...
  GpuSurfaceTracker::Get()->SetSurfaceHandle(
      surface_id(), GetCompositingSurface());
  ...
  params.surface_id = surface_id();
  ...
  Send(new ViewMsg_New(params));
}

In Render process, when cc is created, notify Browser process with surface id.

int32 RenderThreadImpl::CreateViewCommandBuffer(
      int32 surface_id, const GPUCreateCommandBufferConfig& init_params) {
  ...
  IPC::Message* message = new GpuHostMsg_CreateViewCommandBuffer(
      surface_id,
      init_params,
      &route_id);
  ...
}

In Browser process (IO thread), request GL context creation for render view to Gpu process.

Browser process sends XID of Window to Gpu process.
void GpuProcessHost::CreateViewCommandBuffer(
    const gfx::GLSurfaceHandle& compositing_surface,
    int surface_id,
    int client_id,
    const GPUCreateCommandBufferConfig& init_params,
    const CreateCommandBufferCallback& callback) {
  ...
  if (!compositing_surface.is_null() &&
      Send(new GpuMsg_CreateViewCommandBuffer(
          compositing_surface, surface_id, client_id, init_params))) {
 ...
}
content::GpuProcessHost::CreateViewCommandBuffer() at gpu_process_host.cc:735 0x602fe6 
content::GpuMessageFilter::OnCreateViewCommandBuffer() at gpu_message_filter.cc:222 0x881773 
DispatchToMethod{content::GpuMessageFilter, void () at tuple.h:738 0x883ed5 
IPC::SyncMessageSchema{Tuple2{int, GPUCreateCommandBufferConfig}, Tuple1{int&} }::DispatchDelayReplyWithSendParams{content::GpuMessageFilter, void () at ipc_message_utils.h:834 0x882f4d 
GpuHostMsg_CreateViewCommandBuffer::DispatchDelayReply{content::GpuMessageFilter, void () at gpu_messages.h:310 0x88215b 
content::GpuMessageFilter::OnMessageReceived() at gpu_message_filter.cc:91 0x880b3c 
content::BrowserMessageFilter::DispatchMessage() at browser_message_filter.cc:136 0x5888c6 
content::BrowserMessageFilter::OnMessageReceived() at browser_message_filter.cc:52 0x5883f6 
IPC::ChannelProxy::Context::TryFilters() at ipc_channel_proxy.cc:79 0x1a9555b 
IPC::ChannelProxy::Context::OnMessageReceived() at ipc_channel_proxy.cc:93 0x1a955df

In Gpu process, GLXSurface is created by binding Window XID.

  1. GpuChannelManager::OnCreateViewCommandBuffer() deals with GpuMsg_CreateViewCommandBuffer via GpuChannelManager::OnMessageReceived()
  2. GpuChannel creates and owns GpuCommandBufferStub including Window XID.
  3. Send GpuHostMsg_CommandBufferCreated to Browser process
Via complicated not-important process, Render Process initializes CommandBufferProxyImpl.
  1. WebGraphicsContext3DCommandBufferImpl::InitializeCommandBuffer() calls CommandBufferProxyImpl::Initialize()
  2. CommandBufferProxyImpl::Initialize() send GpuCommandBufferMsg_Initialize to Gpu process.
Time to create GLX surface in Gpu process.
GpuCommandBufferStub::OnInitialize() is called.
  1. CommandBufferService, GLES2Decoder and GpuScheduler are created.
  2. ImageTransportSurface::CreateSurface() creates GLX Surface via binding Window XID.
  3. GL Context is created

How sync between Browser process and Gpu process.

Browser process draws non-client windows and Gpu process draws client windows. How chromium sync? Even more, when you click mouse right button, a context menu floats above client window. of course, Browser process draws a context menu. How it possible?

The secret is behind GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped().

Gpu process draws something directly on X Window's buffer. Window performs double-buffering. It means Gpu process draws on back buffer and swaps. And then Browser process blits front buffer to screen. Chromium must prevent Browser process from bliting when Gpu process is swapping. How do that?

When Gpu process swap buffers, Gpu process sends GpuHostMsg_AcceleratedSurfaceBuffersSwapped to Browser process. When Browser process receives this msg, Browser process sleep a moment to guarantee data race for front buffer of Window.

Gpu process sends GpuHostMsg_AcceleratedSurfaceBuffersSwapped to Browser process.
void ImageTransportHelper::SendAcceleratedSurfaceBuffersSwapped(
    GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params) {
  ...
  manager_->Send(new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params));
}


UI thread of Browser process deals with this msg. Sleep and send ack msg to Gpu process.
void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped(
    const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) {
  ...
  static const base::TimeDelta swap_delay = GetSwapDelay();
  if (swap_delay.ToInternalValue())
    base::PlatformThread::Sleep(swap_delay);

  // View must send ACK message after next composite.
  view->AcceleratedSurfaceBuffersSwapped(params, host_id_);
}
content::RenderWidgetHostViewGtk::AcceleratedSurfaceBuffersSwapped() at render_widget_host_view_gtk.cc:1,073 0x6b8a1b 
content::GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped() at gpu_process_host_ui_shim.cc:343 0x6172ae 
DispatchToMethod{content::GpuProcessHostUIShim, void () at tuple.h:546 0x6192ae 
GpuHostMsg_AcceleratedSurfaceBuffersSwapped::Dispatch{content::GpuProcessHostUIShim, content::GpuProcessHostUIShim, void () at gpu_messages.h:376 0x6184ca 
content::GpuProcessHostUIShim::OnControlMessageReceived() at gpu_process_host_ui_shim.cc:198 0x6166f6 
content::GpuProcessHostUIShim::OnMessageReceived() at gpu_process_host_ui_shim.cc:170 0x616232 
content::RouteToGpuProcessHostUIShimTask() at gpu_process_host_ui_shim.cc:106 0x6159e2

To be honest, I wonder that it really guarantees data race of front buffer. or I perhaps don't find a REAL secret yet. If I know more, I'll update.

When turning on aura, rendering mechanism is quite different.

When turning on aura, GPU process draws almost everything. It means that animation of url field or tab button is also accelerated via GPU.

When it comes to aura, Window term is different on gtk platform.
In Gtk, Window is GtkWindow.
In aura, Window is aura::Window based on XWindow
  1. Browser process creates RootWindowHost
  2. Browser process sends surface id (just number) of RootWindowHost to Gpu Process.
  3. Gpu Process creates GL context and off-screen surface (a.k.a content texture).  (Gpu Process will draw everything on the surface)
  4. Browser process paints some off-client windows (e.g. url field, tab button) on their own backing store.
  5. However, Browser process paints and drawsother off-client windows (e.g. context menu) by itself.
  6. Browser process sends bitmaps (a.k.a backing store of window) to Gpu Process.
    (Or using skia ganesh(opengl backend) directly)
  7. Render Process paints GraphicsLayer tree on GraphicsContext3D.
  8. Gpu Process draws each Render Process's all layers on content texture.
  9. Gpu Process draws some non-client window's textures and content textures on screen.

Glossary

client window means something like web content and dialog
non-client window means something like button, url field and tab button.
paint means skia paints something on bitmap.
draw means compositor composite all layers on screen.

In Android, What Browser process finally draws contents in Window.

In Android, GLSurfaceHandle (a.k.a compositing surface) is different to GLX's. It is because Android does not allow non Activity process change contents of View in Activity process.

In render_widget_host_view_gtk.cc
gfx::GLSurfaceHandle RenderWidgetHostViewGtk::GetCompositingSurface() {
  ..
  return gfx::GLSurfaceHandle(compositing_surface_, gfx::NATIVE_TRANSPORT);
}

In render_widget_host_view_android.cc
gfx::GLSurfaceHandle RenderWidgetHostViewAndroid::GetCompositingSurface() {
  ...
    return gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::TEXTURE_TRANSPORT);
}
  1. Gpu process send GpuHostMsg_AcceleratedSurfaceBuffersSwapped to browser process in ImageTransportHelper::SendAcceleratedSurfaceBuffersSwapped().
  2. GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped() in Browser process blit buffer.

How to draw contents on Window in Software path.

Software path does not need Gpu process. Render process draws contents on root backing store and send it to Browser process. Browser process just blits it on screen. 
  1. Render process send ViewHostMsg_UpdateRect (including bitmap) to Browser process.
  2. IO thread of Browser process dispatchs the event to UI thread in RenderWidgetHelper::DidReceiveBackingStoreMsg()
  3. RenderWidgetHostImpl::OnUpdateRect() is called in UI thread of Browser process.
  4. RenderWidgetHostImpl::OnUpdateRect() updates a backing store and async call DidUpdateBackingStore(). (XSyncHandler::PushPaintCounter() send the event in event queue using XSync)
  5. RenderWidgetHostImpl::DidUpdateBackingStore() is called. At this time, all widgets are updated.