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