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

Thursday, November 7, 2013

GLSurface for both render and browser process

original doc : https://github.com/ds-hwang/wiki/wiki/GLSurface-for-both-render-and-browser-process#who-why-how-create-hw-surface

Who, why, how create HW Surface

Where to create HW Surface and How to use it.

Where need it

Render process

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

Browser process

  • Where create data->surface_id?
    scoped_ptr<cc::OutputSurface> GpuProcessTransportFactory::CreateOutputSurface(
        ui::Compositor* compositor) {
      PerCompositorData* data = per_compositor_data_[compositor];
      ...
      if (!command_line->HasSwitch(switches::kUIEnableSoftwareCompositing)) {
        context_provider = ContextProviderCommandBuffer::Create(
            GpuProcessTransportFactory::CreateContextCommon(
                swap_client_weak_ptr,
                data->surface_id), // <- HERE
                "Compositor");
      }
      ...
    }
    

Where create surface_id?

render process

// surface_id and routing_id are just seq.
RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
                                           RenderProcessHost* process,
                                           int routing_id,
                                           bool hidden)
    : view_(NULL),
      ...
      last_input_number_(0) {
  if (routing_id_ == MSG_ROUTING_NONE) {
    routing_id_ = process_->GetNextRoutingID();
    surface_id_ = GpuSurfaceTracker::Get()->AddSurfaceForRenderer(
        process_->GetID(),
        routing_id_);
  } else {
  ...
}

// Create HW surface and map to surface_id
void RenderWidgetHostImpl::Init() {
  ...
  GpuSurfaceTracker::Get()->SetSurfaceHandle(
      surface_id_, GetCompositingSurface());
  ...
}

gfx::GLSurfaceHandle RenderWidgetHostImpl::GetCompositingSurface() {
  if (view_)
    return view_->GetCompositingSurface();
  return gfx::GLSurfaceHandle();
}

with Aura
gfx::GLSurfaceHandle RenderWidgetHostViewAura::GetCompositingSurface() {
  if (shared_surface_handle_.is_null()) {
    ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
    shared_surface_handle_ = factory->CreateSharedSurfaceHandle();
    if (!shared_surface_handle_.is_null())
      factory->AddObserver(this);
  }
  return shared_surface_handle_;
}

// Make GLSurfaceHandle with gfx::kNullPluginWindow & gfx::TEXTURE_TRANSPORT
gfx::GLSurfaceHandle GpuProcessTransportFactory::CreateSharedSurfaceHandle() {
  scoped_refptr<cc::ContextProvider> provider =
      SharedMainThreadContextProvider();
  if (!provider.get())
    return gfx::GLSurfaceHandle();
  typedef WebGraphicsContext3DCommandBufferImpl WGC3DCBI;
  WGC3DCBI* context = static_cast<WGC3DCBI*>(provider->Context3d());
  gfx::GLSurfaceHandle handle = gfx::GLSurfaceHandle(
      gfx::kNullPluginWindow, gfx::TEXTURE_TRANSPORT);
  handle.parent_gpu_process_id = context->GetGPUProcessID();
  handle.parent_client_id = context->GetChannelID();
  return handle;
}

With GTK_TOOLKIT
gfx::GLSurfaceHandle RenderWidgetHostViewGtk::GetCompositingSurface() {
  if (compositing_surface_ == gfx::kNullPluginWindow) {
    GtkNativeViewManager* manager = GtkNativeViewManager::GetInstance();
    gfx::NativeViewId view_id = GetNativeViewId();

    if (!manager->GetPermanentXIDForId(&compositing_surface_, view_id)) {
      DLOG(ERROR) << "Can't find XID for view id " << view_id;
    }
  }
  return gfx::GLSurfaceHandle(compositing_surface_, gfx::NATIVE_TRANSPORT);
}

// Time to create RenderView in render process
bool RenderViewHostImpl::CreateRenderView(
    const string16& frame_name,
    int opener_route_id,
    int32 max_page_id) {
  ...

  ViewMsg_New_Params params;
  ...
  params.view_id = GetRoutingID();
  params.surface_id = surface_id();
  ...
  Send(new ViewMsg_New(params));
  ...
  return true;
}

In render process. Now RenderViewImpl : RenderWidget knows surface_id.
void RenderThreadImpl::OnCreateNewView(const ViewMsg_New_Params& params) {
  EnsureWebKitInitialized();
  // When bringing in render_view, also bring in webkit's glue and jsbindings.
  RenderViewImpl::Create(
      params.opener_route_id,
      params.renderer_preferences,
      params.web_preferences,
      params.view_id,
      params.main_frame_routing_id,
      params.surface_id,
      ...
      params.allow_partial_swap);
}
  • NOTE
    • AURA : HW surface of RenderWidget is just texture
    • GTK : HW surface of RenderWidget is XWindow
  • QUESTION: How Render process create GLSurface by just sequence surface_id
    • A: It is because Render process always create CommandBufferProxyImpl via render process -> browser process -> gpu process.
    • A: In more detail, see below How WebGraphicsContext3DCommandBufferImpl connects GPU Process.

Browser process

  • Only Aura makes HW surface for browser process
    // if aura content_shell, (don't explain how chromium work because it's more complex)
    void DesktopNativeWidgetAura::InitNativeWidget(
        const Widget::InitParams& params) {
      ...
      aura::RootWindow::CreateParams rw_params(params.bounds);
      desktop_root_window_host_->Init(content_window_, params, &rw_params);
    
      root_window_.reset(new aura::RootWindow(rw_params));
      ...
    }
    
    RootWindow::RootWindow(const CreateParams& params)
        : Window(NULL),
          host_(CreateHost(this, params)),
          ...
          held_event_factory_(this) {
      compositor_.reset(new ui::Compositor(host_->GetAcceleratedWidget()));
      ...
    }
    
    // if aura chrome
    gfx::AcceleratedWidget RootWindowHostX11::GetAcceleratedWidget() {
      return xwindow_;
    }
    //or if aura content_shell
    gfx::AcceleratedWidget DesktopRootWindowHostX11::GetAcceleratedWidget() {
      return xwindow_;
    }
    
    Compositor::Compositor(gfx::AcceleratedWidget widget)
        : root_layer_(NULL),
          widget_(widget),
          ...
          schedule_draw_factory_(this) {
      ...
    }
    
    // Time to create OutputSurface
    scoped_ptr<cc::OutputSurface> GpuProcessTransportFactory::CreateOutputSurface(
        ui::Compositor* compositor) {
      PerCompositorData* data = per_compositor_data_[compositor];
      if (!data)
        data = CreatePerCompositorData(compositor);
      ...
      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");
      }
      ..
    }
    
    GpuProcessTransportFactory::PerCompositorData*
    GpuProcessTransportFactory::CreatePerCompositorData(
        ui::Compositor* compositor) {
      ...
      gfx::AcceleratedWidget widget = compositor->widget();
      GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
    
      PerCompositorData* data = new PerCompositorData;
      data->surface_id = tracker->AddSurfaceForNativeWidget(widget);
      ...
      tracker->SetSurfaceHandle(
          data->surface_id,
          gfx::GLSurfaceHandle(widget, gfx::NATIVE_DIRECT));
    
      per_compositor_data_[compositor] = data;
    
      return data;
    }
    
  • NOTE: HW Surface of aura browser process is XWindow

Summary

  • GTK Render Process : XWindow with gfx::NATIVE_TRANSPORT
  • Aura Render Process : nothing with gfx::TEXTURE_TRANSPORT
  • Aura Browser Process: XWindow with gfx::NATIVE_DIRECT

What's happen near GPU side

How WebGraphicsContext3DCommandBufferImpl connects GPU Process

  • Where/How to create GLSurface from HW Surface.
  • As a results
    • Browser process send the HW Surface handle to GPU process
    • GPU process creates GLSurface from HW Surface.

Common part

bool WebGraphicsContext3DCommandBufferImpl::InitializeCommandBuffer(
    bool onscreen) {
  ...
  // Create a proxy to a command buffer in the GPU process.
  if (onscreen) {
    command_buffer_.reset(host_->CreateViewCommandBuffer(
        surface_id_,
        share_group,
        attribs,
        active_url_,
        gpu_preference_));
  } else {
    command_buffer_.reset(host_->CreateOffscreenCommandBuffer(
        gfx::Size(1, 1),
        share_group,
        attribs,
        active_url_,
        gpu_preference_));
  }
  ...
  // Initialize the command buffer.
  return command_buffer_->Initialize();
}

CommandBufferProxyImpl* GpuChannelHost::CreateViewCommandBuffer(
    int32 surface_id,
    CommandBufferProxyImpl* share_group,
    const std::vector<int32>& attribs,
    const GURL& active_url,
    gfx::GpuPreference gpu_preference) {
  ...
  // connect gpu process and get route_id. This impl is different between browser and render process
  int32 route_id = factory_->CreateViewCommandBuffer(surface_id, init_params);
  if (route_id == MSG_ROUTING_NONE)
    return NULL;

  // make CommandBufferProxyImpl using route_id
  CommandBufferProxyImpl* command_buffer =
      new CommandBufferProxyImpl(this, route_id);
  ...
}

// Offscreen logic is the same between browser and render process.
CommandBufferProxyImpl* GpuChannelHost::CreateOffscreenCommandBuffer(
    const gfx::Size& size,
    CommandBufferProxyImpl* share_group,
    const std::vector<int32>& attribs,
    const GURL& active_url,
    gfx::GpuPreference gpu_preference) {
  ...
  int32 route_id;
  if (!Send(new GpuChannelMsg_CreateOffscreenCommandBuffer(size,
                                                           init_params,
                                                           &route_id))) {
    return NULL;
  }
  ...
  CommandBufferProxyImpl* command_buffer =
      new CommandBufferProxyImpl(this, route_id);
  ...
}

in GPU process for offscreen
void GpuChannel::OnCreateOffscreenCommandBuffer(
    const gfx::Size& size,
    const GPUCreateCommandBufferConfig& init_params,
    int32* route_id) {
  ...
  *route_id = GenerateRouteID();

  scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub(
      this,
      share_group,
      gfx::GLSurfaceHandle(),
      ...
      *route_id,
      ...
      init_params.active_url));
  ...
  router_.AddRoute(*route_id, stub.get());
  stubs_.AddWithID(stub.release(), *route_id);
  ...
}

Render process

Render process need to pass through browser process because render process does not know HW Surface handle.
// in render process
int32 RenderThreadImpl::CreateViewCommandBuffer(
      int32 surface_id, const GPUCreateCommandBufferConfig& init_params) {
  ...
  int32 route_id = MSG_ROUTING_NONE;
  IPC::Message* message = new GpuHostMsg_CreateViewCommandBuffer(
      surface_id,
      init_params,
      &route_id);

  // Allow calling this from the compositor thread.
  thread_safe_sender()->Send(message);

  return route_id;
}

// in io thread in browser process
void GpuMessageFilter::OnCreateViewCommandBuffer(
    int32 surface_id,
    const GPUCreateCommandBufferConfig& init_params,
    IPC::Message* reply) {
  ...
  gfx::GLSurfaceHandle compositing_surface;

  int renderer_id = 0;
  int render_widget_id = 0;
  bool result = surface_tracker->GetRenderWidgetIDForSurface(
      surface_id, &renderer_id, &render_widget_id);
  ...
  // Get HW Surface via surface_id
    compositing_surface = surface_tracker->GetSurfaceHandle(surface_id);

  ... // error handling for gpu process die

  host->CreateViewCommandBuffer(
      compositing_surface,
      surface_id,
      render_process_id_,
      init_params,
      base::Bind(&GpuMessageFilter::CreateCommandBufferCallback,
                 weak_ptr_factory_.GetWeakPtr(),
                 reply));
}

void GpuProcessHost::CreateViewCommandBuffer(
    const gfx::GLSurfaceHandle& compositing_surface,
    int surface_id,
    int client_id,
    const GPUCreateCommandBufferConfig& init_params,
    const CreateCommandBufferCallback& callback) {
  ..
  // Request GPU process to make route_id for GPUChannel. send surface_id and HW Surface handle!!
  // NOTE!! How to receive? this is on io thread. io thread MUST not be blocked. GPU process will send ACK msg.
  // At that time, callback will run to notify render process.
      Send(new GpuMsg_CreateViewCommandBuffer(
          compositing_surface, surface_id, client_id, init_params))) {
    create_command_buffer_requests_.push(callback);
    surface_refs_.insert(std::make_pair(surface_id,
        GpuSurfaceTracker::GetInstance()->GetSurfaceRefForSurface(surface_id)));
  ..
}

// in GPU process
void GpuChannelManager::OnCreateViewCommandBuffer(
    const gfx::GLSurfaceHandle& window,
    int32 surface_id,
    int32 client_id,
    const GPUCreateCommandBufferConfig& init_params) {
  DCHECK(surface_id);
  int32 route_id = MSG_ROUTING_NONE;

  // NOTE!!: get gpu_channel using render_process_id. render process uses only one gpu_channel_host.
  GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id);
  if (iter != gpu_channels_.end()) {
    iter->second->CreateViewCommandBuffer(
        window, surface_id, init_params, &route_id);
  }

  // NOTE!!: and Send route_id to browser process. remember browser process is waiting for it.
  Send(new GpuHostMsg_CommandBufferCreated(route_id));
}

void GpuChannel::CreateViewCommandBuffer(
    const gfx::GLSurfaceHandle& window,
    int32 surface_id,
    const GPUCreateCommandBufferConfig& init_params,
    int32* route_id) {
  ...
  // Similar to GpuChannel::OnCreateOffscreenCommandBuffer()
  *route_id = GenerateRouteID();
  scoped_ptr<GpuCommandBufferStub> stub(
      new GpuCommandBufferStub(this,
                               share_group,
                               window,
                               ...
                               *route_id,
                               surface_id,
                               ...
                               init_params.active_url));
  ...
  router_.AddRoute(*route_id, stub.get());
  stubs_.AddWithID(stub.release(), *route_id);
}

// in io thread in browser process
void GpuProcessHost::OnCommandBufferCreated(const int32 route_id) {
  ...
  CreateCommandBufferCallback callback =
      create_command_buffer_requests_.front();
  create_command_buffer_requests_.pop();
  callback.Run(route_id);
}

void GpuMessageFilter::CreateCommandBufferCallback(
    IPC::Message* reply, int32 route_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  GpuHostMsg_CreateViewCommandBuffer::WriteReplyParams(reply, route_id);
  Send(reply);
}

// in render process
int32 RenderThreadImpl::CreateViewCommandBuffer(
      int32 surface_id, const GPUCreateCommandBufferConfig& init_params) {
  // NOTE!!: sync GpuHostMsg_CreateViewCommandBuffer msg return!!
  int32 route_id = MSG_ROUTING_NONE;
  IPC::Message* message = new GpuHostMsg_CreateViewCommandBuffer(
      surface_id,
      init_params,
      &route_id);

  // Allow calling this from the compositor thread.
  thread_safe_sender()->Send(message);

  return route_id;
}

Browser process

// in main thread of browser process
int32 BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
      int32 surface_id,
      const GPUCreateCommandBufferConfig& init_params) {
  CreateRequest request;
  // Request IO thread and wait.
  GetIOLoopProxy()->PostTask(FROM_HERE, base::Bind(
        &BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO,
        base::Unretained(this),
        &request,
        surface_id,
        init_params));
  ...
  request.event.Wait();
  return request.route_id;
}

// in io thread
void BrowserGpuChannelHostFactory::CreateViewCommandBufferOnIO(
    CreateRequest* request,
    int32 surface_id,
    const GPUCreateCommandBufferConfig& init_params) {
  GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
  ...
  gfx::GLSurfaceHandle surface =
      GpuSurfaceTracker::Get()->GetSurfaceHandle(surface_id);
  // gpu_client_id_ is browser process id (seq.)
  host->CreateViewCommandBuffer(
      surface,
      surface_id,
      gpu_client_id_,
      init_params,
      base::Bind(&BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO,
                 request));  // wow. partial binding!!
}

/*
 * Same to render process 
 * from GpuProcessHost::CreateViewCommandBuffer() to gpu process to receive ACK msg
 */

// in io thread in browser process
void GpuProcessHost::OnCommandBufferCreated(const int32 route_id) {
  ...
  CreateCommandBufferCallback callback =
      create_command_buffer_requests_.front();
  create_command_buffer_requests_.pop();
  callback.Run(route_id);
}

void BrowserGpuChannelHostFactory::CommandBufferCreatedOnIO(
    CreateRequest* request, int32 route_id) {
  request->route_id = route_id;
  request->event.Signal();
}

GpuCommandBufferStub

  • represent GraphicsContext3D in gpu process
  • See How Gpu process draws contents on the surface of Browser process's window in chromium.
  • See GPU Command Buffer
    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()
    ...
    

How to create GLSurface

void GpuCommandBufferStub::OnInitialize(
    base::SharedMemoryHandle shared_state_handle,
    IPC::Message* reply_message) {
  ...
  if (!handle_.is_null()) {
    ...
    surface_ = ImageTransportSurface::CreateSurface(  // CreateViewCommandBuffer!!!
        channel_->gpu_channel_manager(),
        this,
        handle_);
  } else {
    GpuChannelManager* manager = channel_->gpu_channel_manager();
    surface_ = manager->GetDefaultOffscreenSurface();  // CreateOffscreenCommandBuffer!!!
  }
  ...
}

scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateSurface(
    GpuChannelManager* manager,
    GpuCommandBufferStub* stub,
    const gfx::GLSurfaceHandle& handle) {
  scoped_refptr<gfx::GLSurface> surface;
  if (handle.transport_type == gfx::TEXTURE_TRANSPORT)
    surface = new TextureImageTransportSurface(manager, stub, handle); // AURA RENDER PROCESS!!!!! do you remember?
  else
    surface = CreateNativeSurface(manager, stub, handle);  // Aura browser process, GTK Render process!!!

  if (!surface.get() || !surface->Initialize())
    return NULL;
  return surface;
}

scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface(
    GpuChannelManager* manager,
    GpuCommandBufferStub* stub,
    const gfx::GLSurfaceHandle& handle) {
  DCHECK(handle.handle);
  DCHECK(handle.transport_type == gfx::NATIVE_DIRECT ||   // Aura browser process!!!
         handle.transport_type == gfx::NATIVE_TRANSPORT);  // GTK render process!!!
  scoped_refptr<gfx::GLSurface> surface =
      gfx::GLSurface::CreateViewGLSurface(handle.handle);
  if (!surface.get())
    return surface;
  return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface(
      manager, stub, surface.get(), handle.is_transport()));
}
FIN.