Showing posts with label gpu. Show all posts
Showing posts with label gpu. Show all posts

Friday, November 8, 2013

Clank (a.k.a chrome for android) vs Android Webview based on Chromium vs Aura

original doc : https://github.com/ds-hwang/wiki/wiki/Clank-(a.k.a-chrome-for-android)-vs-Android-Webview-based-on-Chromium-vs-Aura


I was very confused when I read Android chromium code, because there are two path; single process hack and similar to Aura.

In conclusion

  • Clank is very similar to Aura
    • Clank runs GPU thread, not GPU Process. Refer to InProcessGPU switch.
    • ContentViewRenderView in Clank has similar role to RootWindow in Aura. Those own Compositor!!
  • Android Webview has wholly different.
    • It is single process
    • Impl thread for compositor is the same to UI thread.
    • So there is no latency to send touch events to Impl thread.
    • It uses ContextProviderInProcess instead of ContextProviderCommandBuffer. It means that GPU calls are executed in UI thread (= Impl thread).
    • It uses SynchronousBlahBlah terms. e.g. SynchronousRendererCompositor, SynchronousCompositor, etc..
  • This doc has prerequisites

Clank (a.k.a chrome for android)

Which cpp instances does Clank need?

  • remember ContentViewRenderView is needed.
    // in browser_jni_registrar.cc
    base::android::RegistrationMethod kContentRegisteredMethods[] = {
        {"AndroidLocationApiAdapter",
         content::AndroidLocationApiAdapter::RegisterGeolocationService},
        {"BrowserAccessibilityManager",
         content::RegisterBrowserAccessibilityManager},
        {"BrowserStartupController", content::RegisterBrowserStartupController},
        {"ChildProcessLauncher", content::RegisterChildProcessLauncher},
        {"ContentSettings", content::ContentSettings::RegisterContentSettings},
        {"ContentViewRenderView",
         content::ContentViewRenderView::RegisterContentViewRenderView},
        {"ContentVideoView", content::ContentVideoView::RegisterContentVideoView},
        {"ContentViewCore", content::RegisterContentViewCore},
        {"DataFetcherImplAndroid", content::DataFetcherImplAndroid::Register},
        {"DateTimePickerAndroid", content::RegisterDateTimeChooserAndroid},
        {"DownloadControllerAndroidImpl",
         content::DownloadControllerAndroidImpl::RegisterDownloadController},
        {"InterstitialPageDelegateAndroid",
         content::InterstitialPageDelegateAndroid::
             RegisterInterstitialPageDelegateAndroid},
        {"MediaDrmCredentialManager",
         content::MediaDrmCredentialManager::RegisterMediaDrmCredentialManager},
        {"MediaResourceGetterImpl",
         content::MediaResourceGetterImpl::RegisterMediaResourceGetter},
        {"LoadUrlParams", content::RegisterLoadUrlParams},
        {"PowerSaveBlock", content::RegisterPowerSaveBlocker},
        {"RegisterImeAdapter", content::RegisterImeAdapter},
        {"SpeechRecognizerImplAndroid",
         content::SpeechRecognizerImplAndroid::RegisterSpeechRecognizer},
        {"TouchPoint", content::RegisterTouchPoint},
        {"TracingControllerAndroid", content::RegisterTracingControllerAndroid},
        {"VibrationMessageFilter", content::VibrationMessageFilter::Register},
        {"WebContentsObserverAndroid", content::RegisterWebContentsObserverAndroid},
        {"WebViewStatics", content::RegisterWebViewStatics}, };
    

What is ContentViewRenderView?

  • ShellManager.java and Shell.java use ContentViewRenderView.
  • Shell looks like Browser in chrome aura.
  • ContentViewRenderView seems to have similar role to RootWindow that DesktopRootWindowHostX11 owns.
// Callstack how to make DesktopRootWindowHostX11
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 

Anything interesting

  • There is not huge difference. Aura and Clank are very same.

There is some adjustment for resources.

  • GPU resources adjustment.
    static scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
    CreateGpuProcessViewContext(
        const blink::WebGraphicsContext3D::Attributes attributes,
        int surface_id) {
      ...
      static const size_t kBytesPerPixel = 4;
      gfx::DeviceDisplayInfo display_info;
      size_t full_screen_texture_size_in_bytes =
          display_info.GetDisplayHeight() *
          display_info.GetDisplayWidth() *
          kBytesPerPixel;
      WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits;
      limits.command_buffer_size = 64 * 1024;
      limits.start_transfer_buffer_size = 64 * 1024;
      limits.min_transfer_buffer_size = 64 * 1024;
      limits.max_transfer_buffer_size = std::min(
          3 * full_screen_texture_size_in_bytes, kDefaultMaxTransferBufferSize);
      limits.mapped_memory_reclaim_limit = 2 * 1024 * 1024;
      bool use_echo_for_swap_ack = true;
      return make_scoped_ptr(
          new WebGraphicsContext3DCommandBufferImpl(surface_id,
                                                    url,
                                                    gpu_channel_host.get(),
                                                    use_echo_for_swap_ack,
                                                    attributes,
                                                    false,
                                                    limits));
    }
    

Clank don't use threaded-compositor in Browser side.

void CompositorImpl::SetVisible(bool visible) {
  if (!visible) {
    ui_resource_map_.clear();
    host_.reset();
    client_->UIResourcesAreInvalid();
  } else if (!host_) {
    cc::LayerTreeSettings settings;
    settings.refresh_rate = 60.0;
    settings.impl_side_painting = false;
    settings.allow_antialiasing = false;
    settings.calculate_top_controls_position = false;
    settings.top_controls_height = 0.f;
    settings.use_memory_management = false;
    settings.highp_threshold_min = 2048;

    host_ = cc::LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings);
    ...
  }
}

Others

  • Clank runs GPU thread, not GPU Process. Refer to InProcessGPU switch.
  • Clank enables impl-side-painting in renderer side.
  • Browser side HW Surface is gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::NATIVE_DIRECT). same to Aura.

Android Webview

  • It's single process hacking.

Class diagram

// in android_webview_jni_registrar.cc
static base::android::RegistrationMethod kWebViewRegisteredMethods[] = {
  // Register JNI for android_webview classes.
  { "AndroidProtocolHandler", RegisterAndroidProtocolHandler },
  { "AwAutofillManagerDelegate", RegisterAwAutofillManagerDelegate },
  { "AwContents", RegisterAwContents },
  { "AwContentsClientBridge", RegisterAwContentsClientBridge },
  { "AwContentsIoThreadClientImpl", RegisterAwContentsIoThreadClientImpl },
  { "AwDevToolsServer", RegisterAwDevToolsServer },
  { "AwFormDatabase", RegisterAwFormDatabase },
  { "AwPicture", RegisterAwPicture },
  { "AwSettings", RegisterAwSettings },
  { "AwHttpAuthHandler", RegisterAwHttpAuthHandler },
  { "AwQuotaManagerBridge", RegisterAwQuotaManagerBridge },
  { "AwResource", AwResource::RegisterAwResource },
  { "AwWebContentsDelegate", RegisterAwWebContentsDelegate },
  { "CookieManager", RegisterCookieManager },
  { "InterceptedRequestDataImpl", RegisterInterceptedRequestData },
  { "InputStream", RegisterInputStream },
  { "JavaBrowserViewRendererHelper", RegisterJavaBrowserViewRendererHelper },
};

How about Compositor or something.

  • In conclusion, WebView has no browser side compositor.
  • WebView has only one WebContents instance.
  • InProcessViewRenderer can draw by HW and SW. SW is needed for thumbnail (block API backward compatibility).
  • Important class relationship
    • AwContents owns WebContents
    • AwContents -> InProcessViewRenderer -> SynchronousCompositor -> SynchronousCompositorOutputSurface
  • SynchronousCompositorOutputSurface is back door that WebView gets contents image.
    • SynchronousCompositorOutputSurface is created in render thread but mainly used in UI thread.
    • because UI thread is impl thread!!
    • RenderWidget -> RenderWidgetCompositor -> LayerTreeHost -> ThreadProxy
  • In Impl thread,
    • ThreadProxy -> LayerTreeHostImpl -> SynchronousCompositorOutputSurface

Some code

you can feel darn.
AwContents::AwContents(scoped_ptr<WebContents> web_contents)
    : web_contents_(web_contents.Pass()),
      browser_view_renderer_(
          new InProcessViewRenderer(this, java_renderer_helper(),
                                    web_contents_.get())) {
  ...
}

void InProcessViewRenderer::DidInitializeCompositor(
    content::SynchronousCompositor* compositor) {
  TRACE_EVENT0("android_webview",
               "InProcessViewRenderer::DidInitializeCompositor");
  DCHECK(compositor && compositor_ == NULL);
  compositor_ = compositor;
  hardware_initialized_ = false;
  hardware_failed_ = false;
}

scoped_ptr<cc::OutputSurface> RenderWidget::CreateOutputSurface(bool fallback) {
#if defined(OS_ANDROID)
  if (SynchronousCompositorFactory* factory =
      SynchronousCompositorFactory::GetInstance()) {
    return factory->CreateOutputSurface(routing_id());
  }
#endif
  ...
}

scoped_refptr<cc::ContextProvider>
RenderThreadImpl::OffscreenCompositorContextProvider() {
  DCHECK(IsMainThread());

#if defined(OS_ANDROID)
  if (SynchronousCompositorFactory* factory =
      SynchronousCompositorFactory::GetInstance()) {
    if (compositor_message_loop_proxy_)
      return factory->GetOffscreenContextProviderForCompositorThread();
    return factory->GetOffscreenContextProviderForMainThread();
  }
#endif
  ...
}

Renference

Tuesday, November 5, 2013

Compositor of both render and browser process

originated from https://github.com/ds-hwang/wiki/wiki/Compositor-of-both-render-and-browser-process

Which compositor exists?

Aura makes browser process also use compositor. Let's classify which class is used in which case.

In renderer process

  • RenderWidget owns RenderWidgetCompositor that is created by initializeLayerTreeView()
  • RenderWidgetCompositor owns cc::LayerTreeHost

In browser process when Aura is turned on

  • [Desktop]RootWindowHost owns aura::RootWindow
  • aura::RootWindow owns ui::Compositor
  • ui::Compositor owns cc::LayerTreeHost

Overview

  • render process: RenderWidget -> RenderWidgetCompositor : LayerTreeHostClient -> LayerTreeHost
  • browser process: RootWindow -> Compositor : LayerTreeHostClient -> LayerTreeHost
  • important relationship
    • LayerTreeHost -> ThreadProxy : LayerTreeHostImplClient -> LayerTreeHostImpl
    • LayerTreeHost -> ThreadProxy : SchedulerClient -> Scheduler

OutputSurface lifecycle

Make accelerated surface or disable accelerated compositing

  • WebViewImpl try to create compositor or disable accelerated compositing
    void WebViewImpl::setIsAcceleratedCompositingActive(bool active)
    {
      ...
            m_client->initializeLayerTreeView();
            m_layerTreeView = m_client->layerTreeView();
            if (m_layerTreeView) {
                m_layerTreeView->setRootLayer(*m_rootLayer);
                ...
            } else {
                m_isAcceleratedCompositingActive = false;
                m_client->didDeactivateCompositor();
                m_compositorCreationFailed = true;
            }
      ...
    }
    
  • RenderWidget::initializeLayerTreeView() fails if creating OutputSurface fails.
    void RenderWidget::initializeLayerTreeView() {
      compositor_ = RenderWidgetCompositor::Create(
          this, is_threaded_compositing_enabled_);
      if (!compositor_)
        return;
    
      compositor_->setViewportSize(size_, physical_backing_size_);
      if (init_complete_)
        compositor_->setSurfaceReady();
    }
    
    scoped_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create(
        RenderWidget* widget,
        bool threaded) {
      scoped_ptr<RenderWidgetCompositor> compositor(
          new RenderWidgetCompositor(widget, threaded));
    
      CommandLine* cmd = CommandLine::ForCurrentProcess();
      cc::LayerTreeSettings settings;
      settings.throttle_frame_production =
          !cmd->HasSwitch(switches::kDisableGpuVsync);
      // settings...
    
      if (!compositor->initialize(settings))
        return scoped_ptr<RenderWidgetCompositor>();
    
      return compositor.Pass();
    }
    
    bool RenderWidgetCompositor::initialize(cc::LayerTreeSettings settings) {
      scoped_refptr<base::MessageLoopProxy> compositor_message_loop_proxy =
          RenderThreadImpl::current()->compositor_message_loop_proxy();
      layer_tree_host_ = cc::LayerTreeHost::Create(
          this, NULL, settings, compositor_message_loop_proxy);
      return layer_tree_host_;
    }
    
    bool LayerTreeHost::Initialize(
        scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
      if (impl_task_runner.get())
        return InitializeProxy(ThreadProxy::Create(this, impl_task_runner));
      else
        return InitializeProxy(SingleThreadProxy::Create(this));
    }
    
    bool LayerTreeHost::InitializeProxy(scoped_ptr<Proxy> proxy) {
      TRACE_EVENT0("cc", "LayerTreeHost::InitializeForReal");
    
      scoped_ptr<OutputSurface> output_surface(CreateOutputSurface());
      if (!output_surface)
        return false; // HERE!!! CAN FAIL!!!!
    
      proxy_ = proxy.Pass();
      proxy_->Start(output_surface.Pass());
      return true;
    }
    
    void ThreadProxy::Start(scoped_ptr<OutputSurface> first_output_surface) {
      DCHECK(IsMainThread());
      DCHECK(Proxy::HasImplThread());
      DCHECK(first_output_surface);
    
      // Create LayerTreeHostImpl.
      DebugScopedSetMainThreadBlocked main_thread_blocked(this);
      CompletionEvent completion;
      Proxy::ImplThreadTaskRunner()->PostTask(
          FROM_HERE,
          base::Bind(&ThreadProxy::InitializeImplOnImplThread,
                     base::Unretained(this),
                     &completion));
      completion.Wait();
    
      main_thread_weak_ptr_ = weak_factory_.GetWeakPtr();
      first_output_surface_ = first_output_surface.Pass();
    
      started_ = true;
    }
    
    void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) {
      TRACE_EVENT0("cc", "ThreadProxy::InitializeImplOnImplThread");
      DCHECK(IsImplThread());
      layer_tree_host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this);
      const LayerTreeSettings& settings = layer_tree_host_->settings();
      SchedulerSettings scheduler_settings;
      scheduler_settings.deadline_scheduling_enabled =
          settings.deadline_scheduling_enabled;
      scheduler_settings.impl_side_painting = settings.impl_side_painting;
      scheduler_settings.timeout_and_draw_when_animation_checkerboards =
          settings.timeout_and_draw_when_animation_checkerboards;
      scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced_ =
          settings.maximum_number_of_failed_draws_before_draw_is_forced_;
      scheduler_settings.using_synchronous_renderer_compositor =
          settings.using_synchronous_renderer_compositor;
      scheduler_settings.throttle_frame_production =
          settings.throttle_frame_production;
      scheduler_on_impl_thread_ = Scheduler::Create(this, scheduler_settings);
      scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
    
      impl_thread_weak_ptr_ = weak_factory_on_impl_thread_.GetWeakPtr();
      completion->Signal();
    }
    

What's happen when creating OutputSurface

what is OutputSurface

  • It is something like GraphicsContext3D for LayerTreeHost
  • OutputSurface own ContextProvider that owns WebGraphicsContext3D

in render process

  • LayerTreeHost::CreateOutputSurface() -> RenderWidgetCompositor::CreateOutputSurface() -> RenderWidget::CreateOutputSurface()
    scoped_ptr<cc::OutputSurface> RenderWidget::CreateOutputSurface(bool fallback) {
      ...
      // 1. Create ContextProvider
      scoped_refptr<ContextProviderCommandBuffer> context_provider;
        context_provider = ContextProviderCommandBuffer::Create(
            CreateGraphicsContext3D(attributes),
            "RenderCompositor");
    
      uint32 output_surface_id = next_output_surface_id_++;
      if (!context_provider.get()) {
        /// CAN FAIL!!!! ONLY Renderer can fail.
        if (!command_line.HasSwitch(switches::kEnableSoftwareCompositing))
          return scoped_ptr<cc::OutputSurface>();
    
        // 2. Software fallback
        return scoped_ptr<cc::OutputSurface>(new CompositorOutputSurface(...
      }
    
      // 3. Create OutputSurface
      if (command_line.HasSwitch(switches::kEnableDelegatedRenderer) &&
          !command_line.HasSwitch(switches::kDisableDelegatedRenderer)) {
        DCHECK(is_threaded_compositing_enabled_);
        return scoped_ptr<cc::OutputSurface>(
            new DelegatedCompositorOutputSurface(
                routing_id(),
                output_surface_id,
                context_provider,
                scoped_ptr<cc::SoftwareOutputDevice>()));
      }
      if (command_line.HasSwitch(cc::switches::kCompositeToMailbox)) {
        return scoped_ptr<cc::OutputSurface>(
            new MailboxOutputSurface(
                routing_id(),
                output_surface_id,
                context_provider,
                scoped_ptr<cc::SoftwareOutputDevice>(),
                format));
      }
      bool use_swap_compositor_frame_message = false;
      return scoped_ptr<cc::OutputSurface>(
          new CompositorOutputSurface(
              routing_id(),
              output_surface_id,
              context_provider,
              scoped_ptr<cc::SoftwareOutputDevice>(),
              use_swap_compositor_frame_message));
    }
    

In browser process

  • LayerTreeHost::CreateOutputSurface() -> Compositor::CreateOutputSurface() -> GpuProcessTransportFactory::CreateOutputSurface()
    scoped_ptr<cc::OutputSurface> GpuProcessTransportFactory::CreateOutputSurface(
        ui::Compositor* compositor) {
      ...
    
      scoped_refptr<ContextProviderCommandBuffer> context_provider;
      ...
    
      CommandLine* command_line = CommandLine::ForCurrentProcess();
      if (!command_line->HasSwitch(switches::kUIEnableSoftwareCompositing)) {
        context_provider = ContextProviderCommandBuffer::Create(
            GpuProcessTransportFactory::CreateContextCommon(
                swap_client_weak_ptr,
                data->surface_id),
                "Compositor");
      }
    
      // Software surface
      if (!context_provider.get()) {
        scoped_ptr<SoftwareBrowserCompositorOutputSurface> surface =
            SoftwareBrowserCompositorOutputSurface::Create(
                CreateSoftwareOutputDevice(compositor));
        return surface.PassAs<cc::OutputSurface>();
      }
    
      ...
    
      scoped_ptr<BrowserCompositorOutputSurface> surface(
          new BrowserCompositorOutputSurface(
              context_provider,
              per_compositor_data_[compositor]->surface_id,
              &output_surface_map_,
              base::MessageLoopProxy::current().get(),
              compositor->AsWeakPtr()));
      ...
      return surface.PassAs<cc::OutputSurface>();
    }
    

NOTE: Failure of OutputSurface creation.

  • If Browser process fails, it creates SoftwareBrowserCompositorOutputSurface.
  • If Render process fails and !kEnableSoftwareCompositing, it does not create OutputSurface.
    • and Render process does not do accelerated compositing.

What's happen when creating ContextProviderCommandBuffer

  • OutputSurface -> ContextProviderCommandBuffer -> WebGraphicsContext3DCommandBufferImpl -> GLES2Implementation
  • Under WebGraphicsContext3D, refer to How GPU Process work in multi process
scoped_ptr<cc::OutputSurface> RenderWidget::CreateOutputSurface(bool fallback) {
  ...
  scoped_refptr<ContextProviderCommandBuffer> context_provider;
  if (!fallback) {
    context_provider = ContextProviderCommandBuffer::Create(
        CreateGraphicsContext3D(attributes),
        "RenderCompositor");
  }
  ...
}

scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
RenderWidget::CreateGraphicsContext3D(
    const WebKit::WebGraphicsContext3D::Attributes& attributes) {
  ...
  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
      new WebGraphicsContext3DCommandBufferImpl(
          surface_id(),
          GetURLForGraphicsContext3D(),
          gpu_channel_host.get(),
          swap_client,
          attributes,
          false /* bind generates resources */,
          limits));
  return context.Pass();
}

How impl thread get ownership of gl context.

// in impl thread
void Scheduler::ProcessScheduledActions() {
  ...
    action = state_machine_.NextAction();
  ...
    switch (action) {
  ...
      case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
        client_->ScheduledActionBeginOutputSurfaceCreation();
        break;
  ...
}

void ThreadProxy::ScheduledActionBeginOutputSurfaceCreation() {
  ...
  Proxy::MainThreadTaskRunner()->PostTask(
      FROM_HERE,
      base::Bind(&ThreadProxy::CreateAndInitializeOutputSurface,
                 main_thread_weak_ptr_));
}

in main thread
void ThreadProxy::CreateAndInitializeOutputSurface() {
  ...
  layer_tree_host_->DidLoseOutputSurface();
  output_surface_creation_callback_.Reset(base::Bind(
      &ThreadProxy::DoCreateAndInitializeOutputSurface,
      base::Unretained(this)));
  output_surface_creation_callback_.callback().Run();
}

void ThreadProxy::DoCreateAndInitializeOutputSurface() {
  ...
  scoped_ptr<OutputSurface> output_surface = first_output_surface_.Pass();
  if (!output_surface)
    // when reusing compositor
    output_surface = layer_tree_host_->CreateOutputSurface();

  RendererCapabilities capabilities;
  bool success = !!output_surface;
  if (!success) {
    OnOutputSurfaceInitializeAttempted(false, capabilities);
    return;
  }

  scoped_refptr<ContextProvider> offscreen_context_provider;
  // if filter exists,
  if (created_offscreen_context_provider_) {
    offscreen_context_provider =
        layer_tree_host_->client()->OffscreenContextProvider();
    success = !!offscreen_context_provider.get();
    if (!success) {
      OnOutputSurfaceInitializeAttempted(false, capabilities);
      return;
    }
  }

  success = false;
  {
    // Make a blocking call to InitializeOutputSurfaceOnImplThread. The results
    // of that call are pushed into the success and capabilities local
    // variables.
    CompletionEvent completion;
    DebugScopedSetMainThreadBlocked main_thread_blocked(this);

    Proxy::ImplThreadTaskRunner()->PostTask(
        FROM_HERE,
        base::Bind(&ThreadProxy::InitializeOutputSurfaceOnImplThread,
                   impl_thread_weak_ptr_,
                   &completion,
                   base::Passed(&output_surface),
                   offscreen_context_provider,
                   &success,
                   &capabilities));
    // Main thread waits for impl thread done.
    completion.Wait();
  }

  OnOutputSurfaceInitializeAttempted(success, capabilities);
}

in impl thread
void ThreadProxy::InitializeOutputSurfaceOnImplThread(
    CompletionEvent* completion,
    scoped_ptr<OutputSurface> output_surface,
    scoped_refptr<ContextProvider> offscreen_context_provider,
    bool* success,
    RendererCapabilities* capabilities) {
  ...
  *success = layer_tree_host_impl_->InitializeRenderer(output_surface.Pass());
  ...
}

bool LayerTreeHostImpl::InitializeRenderer(
    scoped_ptr<OutputSurface> output_surface) {
  ...
  // Note: order is important here.
  renderer_.reset();
  tile_manager_.reset();
  resource_provider_.reset();
  output_surface_.reset();
  // Create or Own above important instances in reverse order

  if (!output_surface->BindToClient(this))
    return false;

  scoped_ptr<ResourceProvider> resource_provider =
      ResourceProvider::Create(output_surface.get(),
                               shared_bitmap_manager_,
                               settings_.highp_threshold_min,
                               settings_.use_rgba_4444_textures,
                               settings_.texture_id_allocation_chunk_size);
  if (!resource_provider)
    return false;

  if (output_surface->capabilities().deferred_gl_initialization)
    EnforceZeroBudget(true);

  bool skip_gl_renderer = false;
  CreateAndSetRenderer(
      output_surface.get(), resource_provider.get(), skip_gl_renderer);

  if (!renderer_)
    return false;

  if (settings_.impl_side_painting) {
    CreateAndSetTileManager(resource_provider.get(),
                            output_surface->context_provider().get(),
                            GetRendererCapabilities().using_map_image);
  }

  // Setup BeginImplFrameEmulation if it's not supported natively
  if (!settings_.begin_impl_frame_scheduling_enabled) {
    const base::TimeDelta display_refresh_interval =
      base::TimeDelta::FromMicroseconds(
          base::Time::kMicrosecondsPerSecond /
          settings_.refresh_rate);

    output_surface->InitializeBeginImplFrameEmulation(
        proxy_->ImplThreadTaskRunner(),
        settings_.throttle_frame_production,
        display_refresh_interval);
  }

  int max_frames_pending =
      output_surface->capabilities().max_frames_pending;
  if (max_frames_pending <= 0)
    max_frames_pending = OutputSurface::DEFAULT_MAX_FRAMES_PENDING;
  output_surface->SetMaxFramesPending(max_frames_pending);

  resource_provider_ = resource_provider.Pass();
  output_surface_ = output_surface.Pass();

  client_->OnCanDrawStateChanged(CanDraw());

  return true;
}
  • Q: Why this complex ownership transfer of OutputSurface is needed?
    • A: unfortunately, connecting GPU Process IPC is possible in only main thread.
  • Note
    • TileManager in LayerTreeHostImpl is created if impl-side painting.
    • LayerTreeHost owns PrioritizedResourceManager if not impl-side painting.
    • ResourceProvider in LayerTreeHostImpl is null if software rendering mode.
    • Renderer consists of GLRenderer, SoftwareRenderer and DelegatingRenderer
  • Important relationship
    • LayerTreeHostImpl : RendererClient -> Renderer
    • LayerTreeHostImpl : TileManagerClient -> TileManager
    • LayerTreeHostImpl : OutputSurfaceClient -> OutputSurface

Complexity originated by Android SynchronousCompositor

LayerTreeHostImpl, OutputSurface and etc.. has special methods only for Android. Ignore it when reading code.
  • How to go through this fxxx code. When SynchronousCompositorFactory::GetInstance() exists,
    • AwContents -> InProcessViewRenderer -...-> SynchronousCompositor -> SynchronousCompositorOutputSurface
scoped_ptr<cc::OutputSurface> RenderWidget::CreateOutputSurface(bool fallback) {
#if defined(OS_ANDROID)
  if (SynchronousCompositorFactory* factory =
      SynchronousCompositorFactory::GetInstance()) {
    return factory->CreateOutputSurface(routing_id());
  }
#endif
  ...
}

scoped_refptr<cc::ContextProvider>
RenderThreadImpl::SharedMainThreadContextProvider() {
  DCHECK(IsMainThread());
#if defined(OS_ANDROID)
  if (SynchronousCompositorFactory* factory =
      SynchronousCompositorFactory::GetInstance())
    return factory->GetOffscreenContextProviderForMainThread();
#endif
  ...
}
  • What kind of methods exists
// Use ContextProviderInProcess instead of ContextProviderCommandBuffer
// Call OutputSurface::InitializeAndSetContext3d()
bool SynchronousCompositorOutputSurface::InitializeHwDraw(
    scoped_refptr<gfx::GLSurface> surface,
    scoped_refptr<cc::ContextProvider> offscreen_context_provider) {
  DCHECK(CalledOnValidThread());
  DCHECK(HasClient());
  DCHECK(!context_provider_);
  DCHECK(surface);

  scoped_refptr<cc::ContextProvider> onscreen_context_provider =
      webkit::gpu::ContextProviderInProcess::Create(
          CreateWebGraphicsContext3D(surface), "SynchronousCompositor");
  return InitializeAndSetContext3d(onscreen_context_provider,
                                   offscreen_context_provider);
}

// Only here use LayerTreeHostImpl::DeferredInitialize(). Time to blame.
bool OutputSurface::InitializeAndSetContext3d(
  ..
    if (client_->DeferredInitialize(offscreen_context_provider))
  ..
}

// Only here use LayerTreeHostImpl::ReleaseGL(). Time to blame.
void SynchronousCompositorOutputSurface::ReleaseHwDraw() {
  cc::OutputSurface::ReleaseGL();
}