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/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"
31 namespace android_webview
{
35 using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl
;
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
;
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;
54 scoped_ptr
<gpu::GLInProcessContext
> context(
55 gpu::GLInProcessContext::Create(service
,
57 surface
->IsOffscreen(),
58 gfx::kNullAcceleratedWidget
,
61 false /* share_resources */,
64 DCHECK(context
.get());
66 return webkit::gpu::ContextProviderInProcess::Create(
67 WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
68 context
.Pass(), attributes
),
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 root_layer_(cc::Layer::Create()),
80 output_surface_(NULL
) {
81 DCHECK(last_egl_context_
);
83 gl_surface_
= new AwGLSurface
;
85 cc::LayerTreeSettings settings
;
87 // Should be kept in sync with compositor_impl_android.cc.
88 settings
.allow_antialiasing
= false;
89 settings
.highp_threshold_min
= 2048;
91 // Webview does not own the surface so should not clear it.
92 settings
.should_clear_root_render_pass
= false;
95 cc::LayerTreeHost::CreateSingleThreaded(this, this, NULL
, settings
);
96 layer_tree_host_
->SetRootLayer(root_layer_
);
97 layer_tree_host_
->SetLayerTreeHostClientReady();
100 HardwareRenderer::~HardwareRenderer() {
101 // Must reset everything before |resource_collection_| to ensure all
102 // resources are returned before resetting |resource_collection_| client.
103 layer_tree_host_
.reset();
105 delegated_layer_
= NULL
;
106 frame_provider_
= NULL
;
107 if (resource_collection_
.get()) {
109 // Check collection is empty.
110 cc::ReturnedResourceArray returned_resources
;
111 resource_collection_
->TakeUnusedResourcesForChildCompositor(
112 &returned_resources
);
113 DCHECK_EQ(0u, returned_resources
.size());
114 #endif // DCHECK_IS_ON
116 resource_collection_
->SetClient(NULL
);
120 void HardwareRenderer::DidBeginMainFrame() {
121 // This is called after OutputSurface is created, but before the impl frame
122 // starts. We set the draw constraints here.
123 DCHECK(output_surface_
);
124 DCHECK(viewport_clip_valid_for_dcheck_
);
125 output_surface_
->SetExternalStencilTest(stencil_enabled_
);
126 output_surface_
->SetDrawConstraints(viewport_
, clip_
);
129 bool HardwareRenderer::DrawGL(bool stencil_enabled
,
130 int framebuffer_binding_ext
,
131 AwDrawGLInfo
* draw_info
) {
132 TRACE_EVENT0("android_webview", "HardwareRenderer::DrawGL");
134 // We need to watch if the current Android context has changed and enforce
135 // a clean-up in the compositor.
136 EGLContext current_context
= eglGetCurrentContext();
137 if (!current_context
) {
138 DLOG(ERROR
) << "DrawGL called without EGLContext";
142 // TODO(boliu): Handle context loss.
143 if (last_egl_context_
!= current_context
)
144 DLOG(WARNING
) << "EGLContextChanged";
146 scoped_ptr
<DrawGLInput
> input
= shared_renderer_state_
->PassDrawGLInput();
147 if (!resource_collection_
.get()) {
148 resource_collection_
= new cc::DelegatedFrameResourceCollection
;
149 resource_collection_
->SetClient(this);
153 DCHECK(!input
->frame
.gl_frame_data
);
154 DCHECK(!input
->frame
.software_frame_data
);
156 // DelegatedRendererLayerImpl applies the inverse device_scale_factor of the
157 // renderer frame, assuming that the browser compositor will scale
158 // it back up to device scale. But on Android we put our browser layers in
159 // physical pixels and set our browser CC device_scale_factor to 1, so this
160 // suppresses the transform.
161 input
->frame
.delegated_frame_data
->device_scale_factor
= 1.0f
;
163 gfx::Size frame_size
=
164 input
->frame
.delegated_frame_data
->render_pass_list
.back()
165 ->output_rect
.size();
166 bool size_changed
= frame_size
!= frame_size_
;
167 frame_size_
= frame_size
;
168 scroll_offset_
= input
->scroll_offset
;
170 if (!frame_provider_
|| size_changed
) {
171 if (delegated_layer_
) {
172 delegated_layer_
->RemoveFromParent();
175 frame_provider_
= new cc::DelegatedFrameProvider(
176 resource_collection_
.get(), input
->frame
.delegated_frame_data
.Pass());
178 delegated_layer_
= cc::DelegatedRendererLayer::Create(frame_provider_
);
179 delegated_layer_
->SetBounds(gfx::Size(input
->width
, input
->height
));
180 delegated_layer_
->SetIsDrawable(true);
182 root_layer_
->AddChild(delegated_layer_
);
184 frame_provider_
->SetFrameData(input
->frame
.delegated_frame_data
.Pass());
188 viewport_
.SetSize(draw_info
->width
, draw_info
->height
);
189 layer_tree_host_
->SetViewportSize(viewport_
);
190 clip_
.SetRect(draw_info
->clip_left
,
192 draw_info
->clip_right
- draw_info
->clip_left
,
193 draw_info
->clip_bottom
- draw_info
->clip_top
);
194 stencil_enabled_
= stencil_enabled
;
196 gfx::Transform
transform(gfx::Transform::kSkipInitialization
);
197 transform
.matrix().setColMajorf(draw_info
->transform
);
198 transform
.Translate(scroll_offset_
.x(), scroll_offset_
.y());
199 delegated_layer_
->SetTransform(transform
);
201 gl_surface_
->SetBackingFrameBufferObject(framebuffer_binding_ext
);
203 base::AutoReset
<bool> frame_resetter(&viewport_clip_valid_for_dcheck_
,
205 layer_tree_host_
->SetNeedsRedrawRect(clip_
);
206 layer_tree_host_
->Composite(gfx::FrameTime::Now());
208 gl_surface_
->ResetBackingFrameBufferObject();
213 scoped_ptr
<cc::OutputSurface
> HardwareRenderer::CreateOutputSurface(
215 // Android webview does not support losing output surface.
217 scoped_refptr
<cc::ContextProvider
> context_provider
=
218 CreateContext(gl_surface_
,
219 DeferredGpuCommandService::GetInstance(),
220 shared_renderer_state_
->GetSharedContext());
221 scoped_ptr
<ParentOutputSurface
> output_surface_holder(
222 new ParentOutputSurface(context_provider
));
223 output_surface_
= output_surface_holder
.get();
224 return output_surface_holder
.PassAs
<cc::OutputSurface
>();
227 void HardwareRenderer::UnusedResourcesAreAvailable() {
228 cc::ReturnedResourceArray returned_resources
;
229 resource_collection_
->TakeUnusedResourcesForChildCompositor(
230 &returned_resources
);
231 shared_renderer_state_
->InsertReturnedResources(returned_resources
);
234 } // namespace android_webview