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
- in browser process, creating RenderWidgetHost
- demonstrate how RenderWidget is created.
 - How content shell start
 - How render process is created
 - How GLXSurface is created with GTK_TOOLKIT option
 
 
// 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);
  ...
}
- More detail for GPU process
 
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.
No comments:
Post a Comment