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 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_);
85 resource_collection_->SetClient(this);
87 cc::LayerTreeSettings settings;
89 // Should be kept in sync with compositor_impl_android.cc.
90 settings.allow_antialiasing = false;
91 settings.highp_threshold_min = 2048;
93 // Webview does not own the surface so should not clear it.
94 settings.should_clear_root_render_pass = false;
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);
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();
108 delegated_layer_ = NULL;
109 frame_provider_ = NULL;
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
118 resource_collection_->SetClient(NULL);
121 void HardwareRenderer::DidBeginMainFrame() {
122 // This is called after OutputSurface is created, but before the impl frame
123 // starts. We set the draw constraints here.
124 DCHECK(output_surface_);
125 DCHECK(viewport_clip_valid_for_dcheck_);
126 output_surface_->SetExternalStencilTest(stencil_enabled_);
127 output_surface_->SetDrawConstraints(viewport_, clip_);
130 void HardwareRenderer::CommitFrame() {
131 scoped_ptr<DrawGLInput> input = shared_renderer_state_->PassDrawGLInput();
133 DLOG(WARNING) << "No frame to commit";
137 DCHECK(!input->frame.gl_frame_data);
138 DCHECK(!input->frame.software_frame_data);
140 // DelegatedRendererLayerImpl applies the inverse device_scale_factor of the
141 // renderer frame, assuming that the browser compositor will scale
142 // it back up to device scale. But on Android we put our browser layers in
143 // physical pixels and set our browser CC device_scale_factor to 1, so this
144 // suppresses the transform.
145 input->frame.delegated_frame_data->device_scale_factor = 1.0f;
147 gfx::Size frame_size =
148 input->frame.delegated_frame_data->render_pass_list.back()
149 ->output_rect.size();
150 bool size_changed = frame_size != frame_size_;
151 frame_size_ = frame_size;
152 scroll_offset_ = input->scroll_offset;
154 if (!frame_provider_ || size_changed) {
155 if (delegated_layer_) {
156 delegated_layer_->RemoveFromParent();
159 frame_provider_ = new cc::DelegatedFrameProvider(
160 resource_collection_.get(), input->frame.delegated_frame_data.Pass());
162 delegated_layer_ = cc::DelegatedRendererLayer::Create(frame_provider_);
163 delegated_layer_->SetBounds(gfx::Size(input->width, input->height));
164 delegated_layer_->SetIsDrawable(true);
166 root_layer_->AddChild(delegated_layer_);
168 frame_provider_->SetFrameData(input->frame.delegated_frame_data.Pass());
172 void HardwareRenderer::DrawGL(bool stencil_enabled,
173 int framebuffer_binding_ext,
174 AwDrawGLInfo* draw_info) {
175 TRACE_EVENT0("android_webview", "HardwareRenderer::DrawGL");
177 // We need to watch if the current Android context has changed and enforce
178 // a clean-up in the compositor.
179 EGLContext current_context = eglGetCurrentContext();
180 if (!current_context) {
181 DLOG(ERROR) << "DrawGL called without EGLContext";
185 if (!delegated_layer_.get()) {
186 DLOG(ERROR) << "No frame committed";
190 // TODO(boliu): Handle context loss.
191 if (last_egl_context_ != current_context)
192 DLOG(WARNING) << "EGLContextChanged";
194 viewport_.SetSize(draw_info->width, draw_info->height);
195 layer_tree_host_->SetViewportSize(viewport_);
196 clip_.SetRect(draw_info->clip_left,
198 draw_info->clip_right - draw_info->clip_left,
199 draw_info->clip_bottom - draw_info->clip_top);
200 stencil_enabled_ = stencil_enabled;
202 gfx::Transform transform(gfx::Transform::kSkipInitialization);
203 transform.matrix().setColMajorf(draw_info->transform);
204 transform.Translate(scroll_offset_.x(), scroll_offset_.y());
205 delegated_layer_->SetTransform(transform);
207 gl_surface_->SetBackingFrameBufferObject(framebuffer_binding_ext);
209 base::AutoReset<bool> frame_resetter(&viewport_clip_valid_for_dcheck_,
211 layer_tree_host_->SetNeedsRedrawRect(clip_);
212 layer_tree_host_->Composite(gfx::FrameTime::Now());
214 gl_surface_->ResetBackingFrameBufferObject();
217 scoped_ptr<cc::OutputSurface> HardwareRenderer::CreateOutputSurface(
219 // Android webview does not support losing output surface.
221 scoped_refptr<cc::ContextProvider> context_provider =
222 CreateContext(gl_surface_,
223 DeferredGpuCommandService::GetInstance(),
224 shared_renderer_state_->GetSharedContext());
225 scoped_ptr<ParentOutputSurface> output_surface_holder(
226 new ParentOutputSurface(context_provider));
227 output_surface_ = output_surface_holder.get();
228 return output_surface_holder.PassAs<cc::OutputSurface>();
231 void HardwareRenderer::UnusedResourcesAreAvailable() {
232 cc::ReturnedResourceArray returned_resources;
233 resource_collection_->TakeUnusedResourcesForChildCompositor(
234 &returned_resources);
235 shared_renderer_state_->InsertReturnedResources(returned_resources);
238 } // namespace android_webview