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