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 "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" 30 31namespace android_webview { 32 33namespace { 34 35using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl; 36 37scoped_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; 42 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; 53 54 scoped_ptr<gpu::GLInProcessContext> context( 55 gpu::GLInProcessContext::Create(service, 56 surface, 57 surface->IsOffscreen(), 58 gfx::kNullAcceleratedWidget, 59 surface->GetSize(), 60 share_context, 61 false /* share_resources */, 62 in_process_attribs, 63 gpu_preference)); 64 DCHECK(context.get()); 65 66 return webkit::gpu::ContextProviderInProcess::Create( 67 WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext( 68 context.Pass(), attributes), 69 "Parent-Compositor"); 70} 71 72} // namespace 73 74HardwareRenderer::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_); 84 85 resource_collection_->SetClient(this); 86 87 cc::LayerTreeSettings settings; 88 89 // Should be kept in sync with compositor_impl_android.cc. 90 settings.allow_antialiasing = false; 91 settings.highp_threshold_min = 2048; 92 93 // Webview does not own the surface so should not clear it. 94 settings.should_clear_root_render_pass = false; 95 96 layer_tree_host_ = 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); 101} 102 103HardwareRenderer::~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(); 107 root_layer_ = NULL; 108 delegated_layer_ = NULL; 109 frame_provider_ = NULL; 110#if DCHECK_IS_ON 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 117 118 resource_collection_->SetClient(NULL); 119 120 // Reset draw constraints. 121 shared_renderer_state_->UpdateDrawConstraints( 122 ParentCompositorDrawConstraints()); 123} 124 125void HardwareRenderer::DidBeginMainFrame() { 126 // This is called after OutputSurface is created, but before the impl frame 127 // starts. We set the draw constraints here. 128 DCHECK(output_surface_); 129 DCHECK(viewport_clip_valid_for_dcheck_); 130 output_surface_->SetExternalStencilTest(stencil_enabled_); 131 output_surface_->SetDrawConstraints(viewport_, clip_); 132} 133 134void HardwareRenderer::CommitFrame() { 135 scoped_ptr<DrawGLInput> input = shared_renderer_state_->PassDrawGLInput(); 136 // Happens with empty global visible rect. 137 if (!input.get()) 138 return; 139 140 DCHECK(!input->frame.gl_frame_data); 141 DCHECK(!input->frame.software_frame_data); 142 143 // DelegatedRendererLayerImpl applies the inverse device_scale_factor of the 144 // renderer frame, assuming that the browser compositor will scale 145 // it back up to device scale. But on Android we put our browser layers in 146 // physical pixels and set our browser CC device_scale_factor to 1, so this 147 // suppresses the transform. 148 input->frame.delegated_frame_data->device_scale_factor = 1.0f; 149 150 gfx::Size frame_size = 151 input->frame.delegated_frame_data->render_pass_list.back() 152 ->output_rect.size(); 153 bool size_changed = frame_size != frame_size_; 154 frame_size_ = frame_size; 155 scroll_offset_ = input->scroll_offset; 156 157 if (!frame_provider_ || size_changed) { 158 if (delegated_layer_) { 159 delegated_layer_->RemoveFromParent(); 160 } 161 162 frame_provider_ = new cc::DelegatedFrameProvider( 163 resource_collection_.get(), input->frame.delegated_frame_data.Pass()); 164 165 delegated_layer_ = cc::DelegatedRendererLayer::Create(frame_provider_); 166 delegated_layer_->SetBounds(gfx::Size(input->width, input->height)); 167 delegated_layer_->SetIsDrawable(true); 168 169 root_layer_->AddChild(delegated_layer_); 170 } else { 171 frame_provider_->SetFrameData(input->frame.delegated_frame_data.Pass()); 172 } 173} 174 175void HardwareRenderer::DrawGL(bool stencil_enabled, 176 int framebuffer_binding_ext, 177 AwDrawGLInfo* draw_info) { 178 TRACE_EVENT0("android_webview", "HardwareRenderer::DrawGL"); 179 180 // We need to watch if the current Android context has changed and enforce 181 // a clean-up in the compositor. 182 EGLContext current_context = eglGetCurrentContext(); 183 if (!current_context) { 184 DLOG(ERROR) << "DrawGL called without EGLContext"; 185 return; 186 } 187 188 // TODO(boliu): Handle context loss. 189 if (last_egl_context_ != current_context) 190 DLOG(WARNING) << "EGLContextChanged"; 191 192 gfx::Transform transform(gfx::Transform::kSkipInitialization); 193 transform.matrix().setColMajorf(draw_info->transform); 194 transform.Translate(scroll_offset_.x(), scroll_offset_.y()); 195 196 // Need to post the new transform matrix back to child compositor 197 // because there is no onDraw during a Render Thread animation, and child 198 // compositor might not have the tiles rasterized as the animation goes on. 199 ParentCompositorDrawConstraints draw_constraints( 200 draw_info->is_layer, transform, gfx::Rect(viewport_)); 201 202 draw_constraints_ = draw_constraints; 203 shared_renderer_state_->PostExternalDrawConstraintsToChildCompositor( 204 draw_constraints); 205 206 if (!delegated_layer_.get()) 207 return; 208 209 viewport_.SetSize(draw_info->width, draw_info->height); 210 layer_tree_host_->SetViewportSize(viewport_); 211 clip_.SetRect(draw_info->clip_left, 212 draw_info->clip_top, 213 draw_info->clip_right - draw_info->clip_left, 214 draw_info->clip_bottom - draw_info->clip_top); 215 stencil_enabled_ = stencil_enabled; 216 217 delegated_layer_->SetTransform(transform); 218 219 gl_surface_->SetBackingFrameBufferObject(framebuffer_binding_ext); 220 { 221 base::AutoReset<bool> frame_resetter(&viewport_clip_valid_for_dcheck_, 222 true); 223 layer_tree_host_->SetNeedsRedrawRect(clip_); 224 layer_tree_host_->Composite(gfx::FrameTime::Now()); 225 } 226 gl_surface_->ResetBackingFrameBufferObject(); 227} 228 229scoped_ptr<cc::OutputSurface> HardwareRenderer::CreateOutputSurface( 230 bool fallback) { 231 // Android webview does not support losing output surface. 232 DCHECK(!fallback); 233 scoped_refptr<cc::ContextProvider> context_provider = 234 CreateContext(gl_surface_, 235 DeferredGpuCommandService::GetInstance(), 236 shared_renderer_state_->GetSharedContext()); 237 scoped_ptr<ParentOutputSurface> output_surface_holder( 238 new ParentOutputSurface(context_provider)); 239 output_surface_ = output_surface_holder.get(); 240 return output_surface_holder.PassAs<cc::OutputSurface>(); 241} 242 243void HardwareRenderer::UnusedResourcesAreAvailable() { 244 cc::ReturnedResourceArray returned_resources; 245 resource_collection_->TakeUnusedResourcesForChildCompositor( 246 &returned_resources); 247 shared_renderer_state_->InsertReturnedResources(returned_resources); 248} 249 250} // namespace android_webview 251