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