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.
5 #include "android_webview/browser/hardware_renderer.h"
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/strings/string_number_conversions.h"
14 #include "base/trace_event/trace_event.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/scheduler/begin_frame_source.h"
21 #include "cc/trees/layer_tree_host.h"
22 #include "cc/trees/layer_tree_settings.h"
23 #include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h"
24 #include "gpu/command_buffer/client/gl_in_process_context.h"
25 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
26 #include "ui/gfx/frame_time.h"
27 #include "ui/gfx/geometry/rect_conversions.h"
28 #include "ui/gfx/geometry/rect_f.h"
29 #include "ui/gfx/transform.h"
30 #include "ui/gl/gl_bindings.h"
31 #include "webkit/common/gpu/context_provider_in_process.h"
33 namespace android_webview
{
37 using gpu_blink::WebGraphicsContext3DImpl
;
38 using gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl
;
40 scoped_refptr
<cc::ContextProvider
> CreateContext(
41 scoped_refptr
<gfx::GLSurface
> surface
,
42 scoped_refptr
<gpu::InProcessCommandBuffer::Service
> service
) {
43 const gfx::GpuPreference gpu_preference
= gfx::PreferDiscreteGpu
;
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;
56 scoped_ptr
<gpu::GLInProcessContext
> context(gpu::GLInProcessContext::Create(
59 surface
->IsOffscreen(),
60 gfx::kNullAcceleratedWidget
,
62 NULL
/* share_context */,
63 false /* share_resources */,
66 gpu::GLInProcessContextSharedMemoryLimits(),
69 DCHECK(context
.get());
71 return webkit::gpu::ContextProviderInProcess::Create(
72 WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
73 context
.Pass(), attributes
),
79 HardwareRenderer::HardwareRenderer(SharedRendererState
* state
)
80 : shared_renderer_state_(state
),
81 last_egl_context_(eglGetCurrentContext()),
82 stencil_enabled_(false),
83 viewport_clip_valid_for_dcheck_(false),
84 gl_surface_(new AwGLSurface
),
85 root_layer_(cc::Layer::Create()),
86 resource_collection_(new cc::DelegatedFrameResourceCollection
),
87 output_surface_(NULL
) {
88 DCHECK(last_egl_context_
);
90 resource_collection_
->SetClient(this);
92 cc::LayerTreeSettings settings
;
94 // Should be kept in sync with compositor_impl_android.cc.
95 settings
.renderer_settings
.allow_antialiasing
= false;
96 settings
.renderer_settings
.highp_threshold_min
= 2048;
98 // Webview does not own the surface so should not clear it.
99 settings
.renderer_settings
.should_clear_root_render_pass
= false;
101 // TODO(enne): Update this this compositor to use a synchronous scheduler.
102 settings
.single_thread_proxy_scheduler
= false;
104 layer_tree_host_
= cc::LayerTreeHost::CreateSingleThreaded(
105 this, this, nullptr, nullptr, settings
, nullptr, nullptr);
106 layer_tree_host_
->SetRootLayer(root_layer_
);
107 layer_tree_host_
->SetLayerTreeHostClientReady();
108 layer_tree_host_
->set_has_transparent_background(true);
111 HardwareRenderer::~HardwareRenderer() {
114 // Must reset everything before |resource_collection_| to ensure all
115 // resources are returned before resetting |resource_collection_| client.
116 layer_tree_host_
.reset();
118 delegated_layer_
= NULL
;
119 frame_provider_
= NULL
;
121 // Check collection is empty.
122 cc::ReturnedResourceArray returned_resources
;
123 resource_collection_
->TakeUnusedResourcesForChildCompositor(
124 &returned_resources
);
125 DCHECK_EQ(0u, returned_resources
.size());
126 #endif // DCHECK_IS_ON()
128 resource_collection_
->SetClient(NULL
);
130 // Reset draw constraints.
131 shared_renderer_state_
->UpdateDrawConstraintsOnRT(
132 ParentCompositorDrawConstraints());
135 void HardwareRenderer::DidBeginMainFrame() {
136 // This is called after OutputSurface is created, but before the impl frame
137 // starts. We set the draw constraints here.
138 DCHECK(output_surface_
);
139 DCHECK(viewport_clip_valid_for_dcheck_
);
140 output_surface_
->SetExternalStencilTest(stencil_enabled_
);
141 output_surface_
->SetDrawConstraints(viewport_
, clip_
);
144 void HardwareRenderer::CommitFrame() {
145 TRACE_EVENT0("android_webview", "CommitFrame");
146 scroll_offset_
= shared_renderer_state_
->GetScrollOffsetOnRT();
147 if (committed_frame_
.get()) {
148 TRACE_EVENT_INSTANT0("android_webview",
149 "EarlyOut_PreviousFrameUnconsumed",
150 TRACE_EVENT_SCOPE_THREAD
);
151 shared_renderer_state_
->DidSkipCommitFrameOnRT();
155 committed_frame_
= shared_renderer_state_
->PassCompositorFrameOnRT();
156 // Happens with empty global visible rect.
157 if (!committed_frame_
.get())
160 DCHECK(!committed_frame_
->gl_frame_data
);
161 DCHECK(!committed_frame_
->software_frame_data
);
163 // DelegatedRendererLayerImpl applies the inverse device_scale_factor of the
164 // renderer frame, assuming that the browser compositor will scale
165 // it back up to device scale. But on Android we put our browser layers in
166 // physical pixels and set our browser CC device_scale_factor to 1, so this
167 // suppresses the transform.
168 committed_frame_
->delegated_frame_data
->device_scale_factor
= 1.0f
;
171 void HardwareRenderer::SetFrameData() {
172 if (!committed_frame_
.get())
175 scoped_ptr
<cc::CompositorFrame
> frame
= committed_frame_
.Pass();
176 gfx::Size frame_size
=
177 frame
->delegated_frame_data
->render_pass_list
.back()->output_rect
.size();
178 bool size_changed
= frame_size
!= frame_size_
;
179 frame_size_
= frame_size
;
181 if (!frame_provider_
.get() || size_changed
) {
182 if (delegated_layer_
.get()) {
183 delegated_layer_
->RemoveFromParent();
186 frame_provider_
= new cc::DelegatedFrameProvider(
187 resource_collection_
.get(), frame
->delegated_frame_data
.Pass());
189 delegated_layer_
= cc::DelegatedRendererLayer::Create(frame_provider_
);
190 delegated_layer_
->SetBounds(frame_size_
);
191 delegated_layer_
->SetIsDrawable(true);
193 root_layer_
->AddChild(delegated_layer_
);
195 frame_provider_
->SetFrameData(frame
->delegated_frame_data
.Pass());
199 void HardwareRenderer::DrawGL(bool stencil_enabled
,
200 int framebuffer_binding_ext
,
201 AwDrawGLInfo
* draw_info
) {
202 TRACE_EVENT0("android_webview", "HardwareRenderer::DrawGL");
204 // We need to watch if the current Android context has changed and enforce
205 // a clean-up in the compositor.
206 EGLContext current_context
= eglGetCurrentContext();
207 DCHECK(current_context
) << "DrawGL called without EGLContext";
209 // TODO(boliu): Handle context loss.
210 if (last_egl_context_
!= current_context
)
211 DLOG(WARNING
) << "EGLContextChanged";
214 if (shared_renderer_state_
->ForceCommitOnRT()) {
219 gfx::Transform
transform(gfx::Transform::kSkipInitialization
);
220 transform
.matrix().setColMajorf(draw_info
->transform
);
221 transform
.Translate(scroll_offset_
.x(), scroll_offset_
.y());
223 // Need to post the new transform matrix back to child compositor
224 // because there is no onDraw during a Render Thread animation, and child
225 // compositor might not have the tiles rasterized as the animation goes on.
226 ParentCompositorDrawConstraints
draw_constraints(
227 draw_info
->is_layer
, transform
, gfx::Rect(viewport_
));
229 draw_constraints_
= draw_constraints
;
230 shared_renderer_state_
->PostExternalDrawConstraintsToChildCompositorOnRT(
233 if (!delegated_layer_
.get())
236 viewport_
.SetSize(draw_info
->width
, draw_info
->height
);
237 layer_tree_host_
->SetViewportSize(viewport_
);
238 clip_
.SetRect(draw_info
->clip_left
,
240 draw_info
->clip_right
- draw_info
->clip_left
,
241 draw_info
->clip_bottom
- draw_info
->clip_top
);
242 stencil_enabled_
= stencil_enabled
;
244 delegated_layer_
->SetTransform(transform
);
246 gl_surface_
->SetBackingFrameBufferObject(framebuffer_binding_ext
);
248 base::AutoReset
<bool> frame_resetter(&viewport_clip_valid_for_dcheck_
,
250 layer_tree_host_
->SetNeedsRedrawRect(clip_
);
251 layer_tree_host_
->Composite(gfx::FrameTime::Now());
253 gl_surface_
->ResetBackingFrameBufferObject();
256 void HardwareRenderer::RequestNewOutputSurface() {
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(output_surface_holder
.Pass());
266 void HardwareRenderer::DidFailToInitializeOutputSurface() {
267 RequestNewOutputSurface();
270 void HardwareRenderer::UnusedResourcesAreAvailable() {
271 cc::ReturnedResourceArray returned_resources
;
272 resource_collection_
->TakeUnusedResourcesForChildCompositor(
273 &returned_resources
);
274 shared_renderer_state_
->InsertReturnedResourcesOnRT(returned_resources
);
277 } // namespace android_webview