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.

Friday, May 24, 2013

chromium Render process

Let's look at some important call stack.

#1 Create Render process

1. Render process creation on render thread.

- zygote forks Render process
- RendererMain() is entry point of Render process.

base::MessageLoop::Run() at message_loop.cc:321 0x970ee6 
content::RendererMain() at renderer_main.cc:235 0x118362d 
content::RunZygote() at content_main_runner.cc:385 0xe0aa08 
content::RunNamedProcessTypeMain() at content_main_runner.cc:441 0xe0ac4e 
content::ContentMainRunnerImpl::Run() at content_main_runner.cc:756 0xe0bcc3 
content::ContentMain() at content_main.cc:35 0xe09fbf 
main() at shell_main.cc:36 0x42a43d 

highlight in content::RendererMain()

- create MessangeLoop, PowerMonitor, StaticsRecoder, WebRTC and etc.
- create RenderProcessImpl on stack. FYI, RenderProcessImpl extends RenderProcess that extends ChildProcess.
- create RenderThreadImpl
- call MessageLoop::Run()

highlight in RenderThreadImpl::Init()

- ChildProcess::current()->set_main_thread(this);
- create AppCache, DB, Stroage and etc.
- install varios filters: video, audio, db, WebRTC
- callback embeder via ContentRendererClient::RenderThreadStarted()

how to create SyncChannel

- RenderThreadImpl extends ChildThread
- ChildThread::Init() can be called

  • create SyncChannel
  • create various dispatcher and filters.

2. Receive ViewMsg_New on ipc thread

ChannelProxy::Context::OnMessageReceivedNoFilter() send OnDispatchMessage closure to render thread.
listener_task_runner_->PostTask(FROM_HERE, base::Bind(&Context::OnDispatchMessage, this, message));

IPC::ChannelProxy::Context::OnMessageReceivedNoFilter() at ipc_channel_proxy.cc:104 0x1abfd7c 
IPC::SyncChannel::SyncContext::OnMessageReceived() at ipc_sync_channel.cc:346 0x1acf589 
IPC::internal::ChannelReader::DispatchInputData() at ipc_channel_reader.cc:90 0x1ac44a8 
IPC::internal::ChannelReader::ProcessIncomingMessages() at ipc_channel_reader.cc:32 0x1ac4031 
IPC::Channel::ChannelImpl::OnFileCanReadWithoutBlocking() at ipc_channel_posix.cc:641 0x1abd047 
base::MessagePumpLibevent::FileDescriptorWatcher::OnFileCanReadWithoutBlocking() at message_pump_libevent.cc:102 0x924f10 
base::MessagePumpLibevent::OnLibeventNotification() at message_pump_libevent.cc:359 0x926966 
event_process_active() at event.c:385 0x1c53385 
event_base_loop() at event.c:525 0x1c536a8 
base::MessagePumpLibevent::Run() at message_pump_libevent.cc:262 0x925ee9 
base::MessageLoop::RunInternal() at message_loop.cc:441 0x97179e 
base::MessageLoop::RunHandler() at message_loop.cc:414 0x971648 
base::RunLoop::Run() at run_loop.cc:45 0x9a2020 
base::MessageLoop::Run() at message_loop.cc:321 0x970ee6 
base::Thread::Run() at thread.cc:159 0x9d6092 
base::Thread::ThreadMain() at thread.cc:204 0x9d621f 
base::() at platform_thread_posix.cc:76 0x9ca40a 
start_thread() at pthread_create.c:308 0x7ffff3b67e9a 
clone() at clone.S:112 0x7ffff2c49ccd 
0x0 

3. Create RenderView on render thread

-  Send(new ViewMsg_New(params)) called by RenderViewHostImpl::CreateRenderView() in Browser process
- ipc thread send ViewMsg_New msg to render thread.
- RenderThreadImpl receives ViewMsg_New msg.

content::RenderThreadImpl::OnCreateNewView(const ViewMsg_New_Params& params) at render_thread_impl.cc:1185
content::RenderThreadImpl::OnControlMessageReceived(const IPC::Message& msg) at render_thread_impl.cc:1154
content::ChildThread::OnMessageReceived() at child_thread.cc:271 0xcb2809 
IPC::ChannelProxy::Context::OnDispatchMessage() at ipc_channel_proxy.cc:261 0x1ac0867 
base::internal::RunnableAdapter{void () at bind_internal.h:190 0x1ac3635 
base::internal::InvokeHelper{false, void, base::internal::RunnableAdapter{void () at bind_internal.h:899 0x1ac32af 
base::internal::Invoker{2, base::internal::BindState{base::internal::RunnableAdapter{void () at bind_internal.h:1,257 0x1ac2db6 
base::Callback{void () at callback.h:396 0x44840a 
base::MessageLoop::RunTask() at message_loop.cc:484 0x971c03 
base::MessageLoop::DeferOrRunPendingTask() at message_loop.cc:496 0x971d32 
base::MessageLoop::DoWork() at message_loop.cc:688 0x972673 
base::MessagePumpDefault::Run() at message_pump_default.cc:29 0x979fc9 
base::MessageLoop::RunInternal() at message_loop.cc:441 0x97179e 
base::MessageLoop::RunHandler() at message_loop.cc:414 0x971648 
base::RunLoop::Run() at run_loop.cc:45 0x9a2020 
base::MessageLoop::Run() at message_loop.cc:321 0x970ee6 
content::RendererMain() at renderer_main.cc:235 0x118362d 
content::RunZygote() at content_main_runner.cc:385 0xe0aa08 
content::RunNamedProcessTypeMain() at content_main_runner.cc:441 0xe0ac4e 
content::ContentMainRunnerImpl::Run() at content_main_runner.cc:756 0xe0bcc3 
content::ContentMain() at content_main.cc:35 0xe09fbf 
main() at shell_main.cc:36 0x42a43d 


highlight of RenderThreadImpl::OnCreateNewView()

- call EnsureWebKitInitialized()

  •  WebKit::initialize() 
  •  Init Compositor thread 

 - create RenderViewImpl that extends WebViewClient

  •  create WebViewImpl 
  •  deal with compositor surface, settings, and etc.

#2 send msg

1. send on render thread

IPC::ChannelProxy::Send(Message* message) at ipc_channel_proxy.cc
IPC::SyncChannel::SendWithTimeout() at ipc_sync_channel.cc:452 0x1acfed7 
IPC::SyncChannel::Send() at ipc_sync_channel.cc:437 0x1acfdb2 
content::ChildThread::Send() at child_thread.cc:177 0xcb1d18 
content::RenderThreadImpl::Send() at render_thread_impl.cc:530 0x112a21f 
content::RenderWidget::Send() at render_widget.cc:366 0x11711dc 
content::RenderViewImpl::Send() at render_view_impl.cc:4,404 0x114cfdf 
content::RenderViewImpl::UpdateTargetURL() at render_view_impl.cc:2,376 0x11420b4 
content::RenderViewImpl::setMouseOverURL() at render_view_impl.cc:2,417 0x1142328 

2. send on ipc thread

IPC::Channel::ChannelImpl::Send() at ipc_channel_posix.cc:495 0x1abbeda 
IPC::Channel::Send() at ipc_channel_posix.cc:976 0x1abe95d 
IPC::ChannelProxy::Context::OnSendMessage() at ipc_channel_proxy.cc:186 0x1ac02e6 
base::internal::RunnableAdapter{void () at bind_internal.h:190 0x1ac398a 
base::internal::InvokeHelper{false, void, base::internal::RunnableAdapter{void () at bind_internal.h:899 0x1ac34c6 
base::internal::Invoker{2, base::internal::BindState{base::internal::RunnableAdapter{void () at bind_internal.h:1,257 0x1ac3187 
base::Callback{void () at callback.h:396 0x44840a 
base::MessageLoop::RunTask() at message_loop.cc:484 0x971c03 
base::MessageLoop::DeferOrRunPendingTask() at message_loop.cc:496 0x971d32 
base::MessageLoop::DoWork() at message_loop.cc:688 0x972673 
base::MessagePumpLibevent::Run() at message_pump_libevent.cc:235 0x925d98 
base::MessageLoop::RunInternal() at message_loop.cc:441 0x97179e 
base::MessageLoop::RunHandler() at message_loop.cc:414 0x971648 
base::RunLoop::Run() at run_loop.cc:45 0x9a2020 
base::MessageLoop::Run() at message_loop.cc:321 0x970ee6 
base::Thread::Run() at thread.cc:159 0x9d6092 
base::Thread::ThreadMain() at thread.cc:204 0x9d621f 
base::() at platform_thread_posix.cc:76 0x9ca40a 
start_thread() at pthread_create.c:308 0x7ffff3b67e9a 
clone() at clone.S:112 0x7ffff2c49ccd 
0x0 



Thursday, May 23, 2013

chromium ipc channel on Browser process

Let's look around how to create and use Channel.
* before going on, must read http://www.chromium.org/developers/design-documents/inter-process-communication

I demonstrate how Browser process receives "OnRequestResource" request from Render process.

1. ChannelProxy and Channel creation on ui thread

- when loading url, RenderProcessHost is created.
- at that time, ChannelProxy and Channel are craeted.
- after creating Channel in ChannelProxy::Init(), post OnChannelOpened task to io thread.

context_->ipc_task_runner()->PostTask(FROM_HERE, base::Bind(&Context::OnChannelOpened, context_.get()));

FYI, RenderProcessHostImpl::Init() installs many(~30) filters into ChannelProxy via RenderProcessHostImpl::CreateMessageFilters() after creating ChannelProxy.

IPC::Channel::Channel() at ipc_channel_posix.cc:955 0x1abe7f0 
IPC::ChannelProxy::Context::CreateChannel() at ipc_channel_proxy.cc:68 0x1abfbc3 
IPC::ChannelProxy::Init() at ipc_channel_proxy.cc:329 0x1ac0d8d 
IPC::ChannelProxy::ChannelProxy() at ipc_channel_proxy.cc:294 0x1ac0a07 
content::RenderProcessHostImpl::Init() at render_process_host_impl.cc:495 0x5bd1b3 
content::RenderViewHostImpl::CreateRenderView() at render_view_host_impl.cc:236 0x5d03fb 
content::WebContentsImpl::CreateRenderViewForRenderManager() at web_contents_impl.cc:3,494 0x666e55 
content::RenderViewHostManager::InitRenderView() at render_view_host_manager.cc:663 0x89f0cc 
content::RenderViewHostManager::CreateRenderView() at render_view_host_manager.cc:639 0x89ef95 
content::RenderViewHostManager::UpdateRendererStateForNavigate() at render_view_host_manager.cc:814 0x89fc7d 
content::RenderViewHostManager::Navigate() at render_view_host_manager.cc:122 0x89d35a 
content::WebContentsImpl::NavigateToEntry() at web_contents_impl.cc:1,713 0x65f469 
content::WebContentsImpl::NavigateToPendingEntry() at web_contents_impl.cc:1,680 0x65f126 
content::NavigationControllerImpl::NavigateToPendingEntry() at navigation_controller_impl.cc:1,537 0x898edb 
content::NavigationControllerImpl::LoadEntry() at navigation_controller_impl.cc:398 0x893c0e 
content::NavigationControllerImpl::LoadURLWithParams() at navigation_controller_impl.cc:685 0x894f73 
content::Shell::LoadURLForFrame() at shell.cc:180 0x458723 
content::Shell::LoadURL() at shell.cc:172 0x45866d 
content::Shell::OnURLEntryActivate() at shell_gtk.cc:284 0x45bc41 
content::Shell::OnURLEntryActivateThunk() at shell.h:207 0x45bf12 
g_closure_invoke() at gclosure.c:777 0x7ffff7048140 

2. Channel connection established on io thread

For example, register OnLibeventNotification callback.
 - register callback on fd
event_set(evt.get(), fd, event_mask, OnLibeventNotification, controller);
 - set Watcher (ChannelImpl extends) that is stored in Closure.
controller->set_watcher(delegate);
Back trace

base::MessagePumpLibevent::WatchFileDescriptor() at message_pump_libevent.cc:186 0x925adf 
base::MessageLoopForIO::WatchFileDescriptor() at message_loop.cc:829 0x972a2a 
IPC::Channel::ChannelImpl::AcceptConnection() at ipc_channel_posix.cc:671 0x1abd265 
IPC::Channel::ChannelImpl::Connect() at ipc_channel_posix.cc:345 0x1abb2b4 
IPC::Channel::Connect() at ipc_channel_posix.cc:963 0x1abe8ea 
IPC::ChannelProxy::Context::OnChannelOpened() at ipc_channel_proxy.cc:145 0x1ac00bb 
base::internal::RunnableAdapter{void () at bind_internal.h:134 0x1ac36a1 
base::internal::InvokeHelper{false, void, base::internal::RunnableAdapter{void () at bind_internal.h:871 0x1ac32fc 
base::internal::Invoker{1, base::internal::BindState{base::internal::RunnableAdapter{void () at bind_internal.h:1,173 0x1ac2e37 
base::Callback{void () at callback.h:396 0x44840a 
base::MessageLoop::RunTask() at message_loop.cc:484 0x971c03 

3. Receive "OnRequestResource" request on io thread.

- MessagePumpLibevent::FileDescriptorWatcher::OnFileCanReadWithoutBlocking dispatches the event to Watcher(ChannelImpl)
- ChannelImpl dispatches the event to Channel::Context
- BrowserMessageFilter intercepts the event
- BrowserMessageFilter dispatches the event to ResourceMessageFilter
It is very consistent with chromium's doc: http://dev.chromium.org/developers/design-documents/multi-process-resource-loading

content::ResourceDispatcherHostImpl::OnRequestResource() at resource_dispatcher_host_impl.cc:884 0x585dcd 
ResourceHostMsg_RequestResource::Dispatch{content::ResourceDispatcherHostImpl, content::ResourceDispatcherHostImpl, int, ResourceHostMsg_Request const&}() at resource_messages.h:269 0x58efe2 
content::ResourceDispatcherHostImpl::OnMessageReceived() at resource_dispatcher_host_impl.cc:841 0x58565f 
content::ResourceMessageFilter::OnMessageReceived() at resource_message_filter.cc:49 0x5a8029 
content::BrowserMessageFilter::DispatchMessage() at browser_message_filter.cc:136 0x4daafa 
content::BrowserMessageFilter::OnMessageReceived() at browser_message_filter.cc:52 0x4da62a 
IPC::ChannelProxy::Context::TryFilters() at ipc_channel_proxy.cc:79 0x1abfc63 
IPC::ChannelProxy::Context::OnMessageReceived() at ipc_channel_proxy.cc:93 0x1abfce7 
IPC::internal::ChannelReader::DispatchInputData() at ipc_channel_reader.cc:90 0x1ac44a8 
IPC::internal::ChannelReader::ProcessIncomingMessages() at ipc_channel_reader.cc:32 0x1ac4031 
IPC::Channel::ChannelImpl::OnFileCanReadWithoutBlocking() at ipc_channel_posix.cc:641 0x1abd047 
base::MessagePumpLibevent::FileDescriptorWatcher::OnFileCanReadWithoutBlocking() at message_pump_libevent.cc:102 0x924f10 
base::MessagePumpLibevent::OnLibeventNotification() at message_pump_libevent.cc:359 0x926966 
event_process_active() at event.c:385 0x1c53385 
event_base_loop() at event.c:525 0x1c536a8 
base::MessagePumpLibevent::Run() at message_pump_libevent.cc:262 0x925ee9 
base::MessageLoop::RunInternal() at message_loop.cc:441 0x97179e 
base::MessageLoop::RunHandler() at message_loop.cc:414 0x971648 
base::RunLoop::Run() at run_loop.cc:45 0x9a2020 
base::MessageLoop::Run() at message_loop.cc:321 0x970ee6 
base::Thread::Run() at thread.cc:159 0x9d6092 

Wednesday, May 22, 2013

Understading Chromium Content shell

Let's see seq. diagrams.

1. launching process

edit : http://www.diagrammr.com/edit?key=d6tP4hX5mnk

2. load url


edit : http://www.diagrammr.com/edit?key=dEgiHPcOC4C

back trace : "MessageLoop" NotifyRendererUnresponsive() via timer impl* "RenderViewHostImpl"
content::RenderViewHostImpl::SetNavigationsSuspended() at render_view_host_impl.cc:363 0x5d0b32 
content::RenderViewHostManager::ShouldCloseTabOnUnresponsiveRenderer() at render_view_host_manager.cc:201 0x89d200 
content::WebContentsImpl::RendererUnresponsive() at web_contents_impl.cc:3,278 0x665b18 
content::RenderViewHostImpl::NotifyRendererUnresponsive() at render_view_host_impl.cc:1,598 0x5d7ca8 
content::RenderWidgetHostImpl::CheckRendererIsUnresponsive() at render_widget_host_impl.cc:1,562 0x5f88e5 
base::internal::RunnableAdapter{void () at bind_internal.h:134 0x609d8b 
base::internal::InvokeHelper{false, void, base::internal::RunnableAdapter{void () at bind_internal.h:871 0x609307 
base::internal::Invoker{1, base::internal::BindState{base::internal::RunnableAdapter{void () at bind_internal.h:1,173 0x607dbb 
base::Callback{void () at callback.h:396 0x44831e 
base::Timer::RunScheduledTask() at timer.cc:181 0x9dcc4b 
base::BaseTimerTaskInternal::Run() at timer.cc:46 0x9dcd35 
base::internal::RunnableAdapter{void () at bind_internal.h:134 0x9dd093 
base::internal::InvokeHelper{false, void, base::internal::RunnableAdapter{void () at bind_internal.h:871 0x9dd00b 
base::internal::Invoker{1, base::internal::BindState{base::internal::RunnableAdapter{void () at bind_internal.h:1,173 0x9dcfb7 
base::Callback{void () at callback.h:396 0x44831e 
base::MessageLoop::RunTask() at message_loop.cc:484 0x9716bf 
base::MessageLoop::DeferOrRunPendingTask() at message_loop.cc:496 0x9717ee 
base::MessageLoop::DoDelayedWork() at message_loop.cc:726 0x97231b 
base::MessagePumpGlib::RunWithDispatcher() at message_pump_glib.cc:208 0x9f6bfe 
base::MessagePumpGlib::Run() at message_pump_glib.cc:296 0x9f7086 
base::MessageLoop::RunInternal() at message_loop.cc:441 0x97125a 
base::MessageLoop::RunHandler() at message_loop.cc:414 0x971104 
base::RunLoop::Run() at run_loop.cc:45 0x9a1ac8 
content::BrowserMainLoop::MainMessageLoopRun() at browser_main_loop.cc:871 0x6b9be3 
content::BrowserMainLoop::RunMainMessageLoopParts() at browser_main_loop.cc:558 0x6b8d5e 
content::BrowserMainRunnerImpl::Run() at browser_main_runner.cc:125 0x4e2b40 
ShellBrowserMain() at shell_browser_main.cc:180 0x444fff 
content::ShellMainDelegate::RunProcess() at shell_main_delegate.cc:144 0x42aa88 
content::RunNamedProcessTypeMain() at content_main_runner.cc:421 0xe0ba50 
content::ContentMainRunnerImpl::Run() at content_main_runner.cc:756 0xe0cb73 
content::ContentMain() at content_main.cc:35 0xe0ae57 
main() at shell_main.cc:36 0x42a43d