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();
}

1 comment:

  1. TINN GOLD LLC - ITALIAN Art | TINN GOLD LLC
    TINN ford edge titanium GOLD LLC. $2.00 CAD (tax) ion titanium hair color / 0.10%. FREE titanium curling iron shipping babyliss nano titanium at TINN GOLD LLC. TINN GOLD LLC. titanium block

    ReplyDelete