Home | History | Annotate | Download | only in browser
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "android_webview/browser/hardware_renderer.h"
      6 
      7 #include "android_webview/browser/aw_gl_surface.h"
      8 #include "android_webview/browser/deferred_gpu_command_service.h"
      9 #include "android_webview/browser/parent_output_surface.h"
     10 #include "android_webview/browser/shared_renderer_state.h"
     11 #include "android_webview/public/browser/draw_gl.h"
     12 #include "base/auto_reset.h"
     13 #include "base/debug/trace_event.h"
     14 #include "base/strings/string_number_conversions.h"
     15 #include "cc/layers/delegated_frame_provider.h"
     16 #include "cc/layers/delegated_renderer_layer.h"
     17 #include "cc/layers/layer.h"
     18 #include "cc/output/compositor_frame.h"
     19 #include "cc/output/output_surface.h"
     20 #include "cc/trees/layer_tree_host.h"
     21 #include "cc/trees/layer_tree_settings.h"
     22 #include "gpu/command_buffer/client/gl_in_process_context.h"
     23 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
     24 #include "ui/gfx/frame_time.h"
     25 #include "ui/gfx/geometry/rect_conversions.h"
     26 #include "ui/gfx/geometry/rect_f.h"
     27 #include "ui/gfx/transform.h"
     28 #include "ui/gl/gl_bindings.h"
     29 #include "webkit/common/gpu/context_provider_in_process.h"
     30 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
     31 
     32 namespace android_webview {
     33 
     34 namespace {
     35 
     36 using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
     37 using webkit::gpu::WebGraphicsContext3DImpl;
     38 
     39 scoped_refptr<cc::ContextProvider> CreateContext(
     40     scoped_refptr<gfx::GLSurface> surface,
     41     scoped_refptr<gpu::InProcessCommandBuffer::Service> service) {
     42   const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
     43 
     44   blink::WebGraphicsContext3D::Attributes attributes;
     45   attributes.antialias = false;
     46   attributes.depth = false;
     47   attributes.stencil = false;
     48   attributes.shareResources = true;
     49   attributes.noAutomaticFlushes = true;
     50   gpu::gles2::ContextCreationAttribHelper attribs_for_gles2;
     51   WebGraphicsContext3DImpl::ConvertAttributes(
     52       attributes, &attribs_for_gles2);
     53   attribs_for_gles2.lose_context_when_out_of_memory = true;
     54 
     55   scoped_ptr<gpu::GLInProcessContext> context(gpu::GLInProcessContext::Create(
     56       service,
     57       surface,
     58       surface->IsOffscreen(),
     59       gfx::kNullAcceleratedWidget,
     60       surface->GetSize(),
     61       NULL /* share_context */,
     62       false /* share_resources */,
     63       attribs_for_gles2,
     64       gpu_preference,
     65       gpu::GLInProcessContextSharedMemoryLimits()));
     66   DCHECK(context.get());
     67 
     68   return webkit::gpu::ContextProviderInProcess::Create(
     69       WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
     70           context.Pass(), attributes),
     71       "Parent-Compositor");
     72 }
     73 
     74 }  // namespace
     75 
     76 HardwareRenderer::HardwareRenderer(SharedRendererState* state)
     77     : shared_renderer_state_(state),
     78       last_egl_context_(eglGetCurrentContext()),
     79       width_(0),
     80       height_(0),
     81       stencil_enabled_(false),
     82       viewport_clip_valid_for_dcheck_(false),
     83       gl_surface_(new AwGLSurface),
     84       root_layer_(cc::Layer::Create()),
     85       resource_collection_(new cc::DelegatedFrameResourceCollection),
     86       output_surface_(NULL) {
     87   DCHECK(last_egl_context_);
     88 
     89   resource_collection_->SetClient(this);
     90 
     91   cc::LayerTreeSettings settings;
     92 
     93   // Should be kept in sync with compositor_impl_android.cc.
     94   settings.allow_antialiasing = false;
     95   settings.highp_threshold_min = 2048;
     96 
     97   // Webview does not own the surface so should not clear it.
     98   settings.should_clear_root_render_pass = false;
     99 
    100   // TODO(enne): Update this this compositor to use a synchronous scheduler.
    101   settings.single_thread_proxy_scheduler = false;
    102 
    103   layer_tree_host_ =
    104       cc::LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings, NULL);
    105   layer_tree_host_->SetRootLayer(root_layer_);
    106   layer_tree_host_->SetLayerTreeHostClientReady();
    107   layer_tree_host_->set_has_transparent_background(true);
    108 }
    109 
    110 HardwareRenderer::~HardwareRenderer() {
    111   SetFrameData();
    112 
    113   // Must reset everything before |resource_collection_| to ensure all
    114   // resources are returned before resetting |resource_collection_| client.
    115   layer_tree_host_.reset();
    116   root_layer_ = NULL;
    117   delegated_layer_ = NULL;
    118   frame_provider_ = NULL;
    119 #if DCHECK_IS_ON
    120   // Check collection is empty.
    121   cc::ReturnedResourceArray returned_resources;
    122   resource_collection_->TakeUnusedResourcesForChildCompositor(
    123       &returned_resources);
    124   DCHECK_EQ(0u, returned_resources.size());
    125 #endif  // DCHECK_IS_ON
    126 
    127   resource_collection_->SetClient(NULL);
    128 
    129   // Reset draw constraints.
    130   shared_renderer_state_->UpdateDrawConstraints(
    131       ParentCompositorDrawConstraints());
    132 }
    133 
    134 void HardwareRenderer::DidBeginMainFrame() {
    135   // This is called after OutputSurface is created, but before the impl frame
    136   // starts. We set the draw constraints here.
    137   DCHECK(output_surface_);
    138   DCHECK(viewport_clip_valid_for_dcheck_);
    139   output_surface_->SetExternalStencilTest(stencil_enabled_);
    140   output_surface_->SetDrawConstraints(viewport_, clip_);
    141 }
    142 
    143 void HardwareRenderer::CommitFrame() {
    144   scroll_offset_ = shared_renderer_state_->GetScrollOffset();
    145   if (committed_frame_.get()) {
    146     TRACE_EVENT_INSTANT0("android_webview",
    147                          "EarlyOut_PreviousFrameUnconsumed",
    148                          TRACE_EVENT_SCOPE_THREAD);
    149     shared_renderer_state_->DidSkipCommitFrame();
    150     return;
    151   }
    152 
    153   committed_frame_ = shared_renderer_state_->PassCompositorFrame();
    154   // Happens with empty global visible rect.
    155   if (!committed_frame_.get())
    156     return;
    157 
    158   DCHECK(!committed_frame_->gl_frame_data);
    159   DCHECK(!committed_frame_->software_frame_data);
    160 
    161   // DelegatedRendererLayerImpl applies the inverse device_scale_factor of the
    162   // renderer frame, assuming that the browser compositor will scale
    163   // it back up to device scale.  But on Android we put our browser layers in
    164   // physical pixels and set our browser CC device_scale_factor to 1, so this
    165   // suppresses the transform.
    166   committed_frame_->delegated_frame_data->device_scale_factor = 1.0f;
    167 }
    168 
    169 void HardwareRenderer::SetFrameData() {
    170   if (!committed_frame_.get())
    171     return;
    172 
    173   scoped_ptr<cc::CompositorFrame> frame = committed_frame_.Pass();
    174   gfx::Size frame_size =
    175       frame->delegated_frame_data->render_pass_list.back()->output_rect.size();
    176   bool size_changed = frame_size != frame_size_;
    177   frame_size_ = frame_size;
    178 
    179   if (!frame_provider_ || size_changed) {
    180     if (delegated_layer_) {
    181       delegated_layer_->RemoveFromParent();
    182     }
    183 
    184     frame_provider_ = new cc::DelegatedFrameProvider(
    185         resource_collection_.get(), frame->delegated_frame_data.Pass());
    186 
    187     delegated_layer_ = cc::DelegatedRendererLayer::Create(frame_provider_);
    188     delegated_layer_->SetBounds(frame_size_);
    189     delegated_layer_->SetIsDrawable(true);
    190 
    191     root_layer_->AddChild(delegated_layer_);
    192   } else {
    193     frame_provider_->SetFrameData(frame->delegated_frame_data.Pass());
    194   }
    195 }
    196 
    197 void HardwareRenderer::DrawGL(bool stencil_enabled,
    198                               int framebuffer_binding_ext,
    199                               AwDrawGLInfo* draw_info) {
    200   TRACE_EVENT0("android_webview", "HardwareRenderer::DrawGL");
    201 
    202   // We need to watch if the current Android context has changed and enforce
    203   // a clean-up in the compositor.
    204   EGLContext current_context = eglGetCurrentContext();
    205   DCHECK(current_context) << "DrawGL called without EGLContext";
    206 
    207   // TODO(boliu): Handle context loss.
    208   if (last_egl_context_ != current_context)
    209     DLOG(WARNING) << "EGLContextChanged";
    210 
    211   SetFrameData();
    212   if (shared_renderer_state_->ForceCommit()) {
    213     CommitFrame();
    214     SetFrameData();
    215   }
    216 
    217   gfx::Transform transform(gfx::Transform::kSkipInitialization);
    218   transform.matrix().setColMajorf(draw_info->transform);
    219   transform.Translate(scroll_offset_.x(), scroll_offset_.y());
    220 
    221   // Need to post the new transform matrix back to child compositor
    222   // because there is no onDraw during a Render Thread animation, and child
    223   // compositor might not have the tiles rasterized as the animation goes on.
    224   ParentCompositorDrawConstraints draw_constraints(
    225       draw_info->is_layer, transform, gfx::Rect(viewport_));
    226 
    227   draw_constraints_ = draw_constraints;
    228   shared_renderer_state_->PostExternalDrawConstraintsToChildCompositor(
    229       draw_constraints);
    230 
    231   if (!delegated_layer_.get())
    232     return;
    233 
    234   viewport_.SetSize(draw_info->width, draw_info->height);
    235   layer_tree_host_->SetViewportSize(viewport_);
    236   clip_.SetRect(draw_info->clip_left,
    237                 draw_info->clip_top,
    238                 draw_info->clip_right - draw_info->clip_left,
    239                 draw_info->clip_bottom - draw_info->clip_top);
    240   stencil_enabled_ = stencil_enabled;
    241 
    242   delegated_layer_->SetTransform(transform);
    243 
    244   gl_surface_->SetBackingFrameBufferObject(framebuffer_binding_ext);
    245   {
    246     base::AutoReset<bool> frame_resetter(&viewport_clip_valid_for_dcheck_,
    247                                          true);
    248     layer_tree_host_->SetNeedsRedrawRect(clip_);
    249     layer_tree_host_->Composite(gfx::FrameTime::Now());
    250   }
    251   gl_surface_->ResetBackingFrameBufferObject();
    252 }
    253 
    254 void HardwareRenderer::RequestNewOutputSurface(bool fallback) {
    255   // Android webview does not support losing output surface.
    256   DCHECK(!fallback);
    257   scoped_refptr<cc::ContextProvider> context_provider =
    258       CreateContext(gl_surface_,
    259                     DeferredGpuCommandService::GetInstance());
    260   scoped_ptr<ParentOutputSurface> output_surface_holder(
    261       new ParentOutputSurface(context_provider));
    262   output_surface_ = output_surface_holder.get();
    263   layer_tree_host_->SetOutputSurface(
    264       output_surface_holder.PassAs<cc::OutputSurface>());
    265 }
    266 
    267 void HardwareRenderer::UnusedResourcesAreAvailable() {
    268   cc::ReturnedResourceArray returned_resources;
    269   resource_collection_->TakeUnusedResourcesForChildCompositor(
    270       &returned_resources);
    271   shared_renderer_state_->InsertReturnedResources(returned_resources);
    272 }
    273 
    274 }  // namespace android_webview
    275