1 // Copyright (c) 2012 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 "content/browser/renderer_host/compositor_impl_android.h" 6 7 #include <android/bitmap.h> 8 #include <android/native_window_jni.h> 9 #include <map> 10 11 #include "base/android/jni_android.h" 12 #include "base/android/scoped_java_ref.h" 13 #include "base/bind.h" 14 #include "base/command_line.h" 15 #include "base/lazy_instance.h" 16 #include "base/logging.h" 17 #include "base/single_thread_task_runner.h" 18 #include "base/synchronization/lock.h" 19 #include "base/threading/thread.h" 20 #include "cc/input/input_handler.h" 21 #include "cc/layers/layer.h" 22 #include "cc/output/compositor_frame.h" 23 #include "cc/output/context_provider.h" 24 #include "cc/output/output_surface.h" 25 #include "cc/resources/scoped_ui_resource.h" 26 #include "cc/resources/ui_resource_bitmap.h" 27 #include "cc/trees/layer_tree_host.h" 28 #include "content/browser/gpu/browser_gpu_channel_host_factory.h" 29 #include "content/browser/gpu/gpu_surface_tracker.h" 30 #include "content/common/gpu/client/command_buffer_proxy_impl.h" 31 #include "content/common/gpu/client/context_provider_command_buffer.h" 32 #include "content/common/gpu/client/gl_helper.h" 33 #include "content/common/gpu/client/gpu_channel_host.h" 34 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" 35 #include "content/common/gpu/gpu_process_launch_causes.h" 36 #include "content/public/browser/android/compositor_client.h" 37 #include "content/public/common/content_switches.h" 38 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" 39 #include "third_party/khronos/GLES2/gl2.h" 40 #include "third_party/khronos/GLES2/gl2ext.h" 41 #include "ui/base/android/window_android.h" 42 #include "ui/gfx/android/device_display_info.h" 43 #include "ui/gfx/android/java_bitmap.h" 44 #include "ui/gfx/frame_time.h" 45 #include "webkit/common/gpu/context_provider_in_process.h" 46 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h" 47 48 namespace gfx { 49 class JavaBitmap; 50 } 51 52 namespace { 53 54 // Used for drawing directly to the screen. Bypasses resizing and swaps. 55 class DirectOutputSurface : public cc::OutputSurface { 56 public: 57 DirectOutputSurface( 58 const scoped_refptr<cc::ContextProvider>& context_provider) 59 : cc::OutputSurface(context_provider) { 60 capabilities_.adjust_deadline_for_parent = false; 61 } 62 63 virtual void Reshape(gfx::Size size, float scale_factor) OVERRIDE { 64 surface_size_ = size; 65 } 66 virtual void SwapBuffers(cc::CompositorFrame*) OVERRIDE { 67 context_provider_->Context3d()->shallowFlushCHROMIUM(); 68 } 69 }; 70 71 // Used to override capabilities_.adjust_deadline_for_parent to false 72 class OutputSurfaceWithoutParent : public cc::OutputSurface { 73 public: 74 OutputSurfaceWithoutParent( 75 const scoped_refptr< 76 content::ContextProviderCommandBuffer>& context_provider) 77 : cc::OutputSurface(context_provider) { 78 capabilities_.adjust_deadline_for_parent = false; 79 } 80 81 virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE { 82 content::WebGraphicsContext3DCommandBufferImpl* command_buffer_context = 83 static_cast<content::WebGraphicsContext3DCommandBufferImpl*>( 84 context_provider_->Context3d()); 85 content::CommandBufferProxyImpl* command_buffer_proxy = 86 command_buffer_context->GetCommandBufferProxy(); 87 DCHECK(command_buffer_proxy); 88 command_buffer_proxy->SetLatencyInfo(frame->metadata.latency_info); 89 90 OutputSurface::SwapBuffers(frame); 91 } 92 }; 93 94 static bool g_initialized = false; 95 96 } // anonymous namespace 97 98 namespace content { 99 100 typedef std::map<int, base::android::ScopedJavaGlobalRef<jobject> > 101 SurfaceMap; 102 static base::LazyInstance<SurfaceMap> 103 g_surface_map = LAZY_INSTANCE_INITIALIZER; 104 static base::LazyInstance<base::Lock> g_surface_map_lock; 105 106 // static 107 Compositor* Compositor::Create(CompositorClient* client, 108 gfx::NativeWindow root_window) { 109 return client ? new CompositorImpl(client, root_window) : NULL; 110 } 111 112 // static 113 void Compositor::Initialize() { 114 DCHECK(!CompositorImpl::IsInitialized()); 115 g_initialized = true; 116 } 117 118 // static 119 bool CompositorImpl::IsInitialized() { 120 return g_initialized; 121 } 122 123 // static 124 jobject CompositorImpl::GetSurface(int surface_id) { 125 base::AutoLock lock(g_surface_map_lock.Get()); 126 SurfaceMap* surfaces = g_surface_map.Pointer(); 127 SurfaceMap::iterator it = surfaces->find(surface_id); 128 jobject jsurface = it == surfaces->end() ? NULL : it->second.obj(); 129 130 LOG_IF(WARNING, !jsurface) << "No surface for surface id " << surface_id; 131 return jsurface; 132 } 133 134 CompositorImpl::CompositorImpl(CompositorClient* client, 135 gfx::NativeWindow root_window) 136 : root_layer_(cc::Layer::Create()), 137 has_transparent_background_(false), 138 window_(NULL), 139 surface_id_(0), 140 client_(client), 141 root_window_(root_window) { 142 DCHECK(client); 143 DCHECK(root_window); 144 ImageTransportFactoryAndroid::AddObserver(this); 145 root_window->AttachCompositor(); 146 } 147 148 CompositorImpl::~CompositorImpl() { 149 root_window_->DetachCompositor(); 150 ImageTransportFactoryAndroid::RemoveObserver(this); 151 // Clean-up any surface references. 152 SetSurface(NULL); 153 } 154 155 void CompositorImpl::Composite() { 156 if (host_) 157 host_->Composite(gfx::FrameTime::Now()); 158 } 159 160 void CompositorImpl::SetRootLayer(scoped_refptr<cc::Layer> root_layer) { 161 root_layer_->RemoveAllChildren(); 162 root_layer_->AddChild(root_layer); 163 } 164 165 void CompositorImpl::SetWindowSurface(ANativeWindow* window) { 166 GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get(); 167 168 if (window_) { 169 tracker->RemoveSurface(surface_id_); 170 ANativeWindow_release(window_); 171 window_ = NULL; 172 surface_id_ = 0; 173 SetVisible(false); 174 } 175 176 if (window) { 177 window_ = window; 178 ANativeWindow_acquire(window); 179 surface_id_ = tracker->AddSurfaceForNativeWidget(window); 180 tracker->SetSurfaceHandle( 181 surface_id_, 182 gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::NATIVE_DIRECT)); 183 SetVisible(true); 184 } 185 } 186 187 void CompositorImpl::SetSurface(jobject surface) { 188 JNIEnv* env = base::android::AttachCurrentThread(); 189 base::android::ScopedJavaLocalRef<jobject> j_surface(env, surface); 190 191 // First, cleanup any existing surface references. 192 if (surface_id_) { 193 DCHECK(g_surface_map.Get().find(surface_id_) != 194 g_surface_map.Get().end()); 195 base::AutoLock lock(g_surface_map_lock.Get()); 196 g_surface_map.Get().erase(surface_id_); 197 } 198 SetWindowSurface(NULL); 199 200 // Now, set the new surface if we have one. 201 ANativeWindow* window = NULL; 202 if (surface) 203 window = ANativeWindow_fromSurface(env, surface); 204 if (window) { 205 SetWindowSurface(window); 206 ANativeWindow_release(window); 207 { 208 base::AutoLock lock(g_surface_map_lock.Get()); 209 g_surface_map.Get().insert(std::make_pair(surface_id_, j_surface)); 210 } 211 } 212 } 213 214 void CompositorImpl::SetVisible(bool visible) { 215 if (!visible) { 216 ui_resource_map_.clear(); 217 host_.reset(); 218 client_->UIResourcesAreInvalid(); 219 } else if (!host_) { 220 cc::LayerTreeSettings settings; 221 settings.refresh_rate = 60.0; 222 settings.impl_side_painting = false; 223 settings.allow_antialiasing = false; 224 settings.calculate_top_controls_position = false; 225 settings.top_controls_height = 0.f; 226 settings.use_memory_management = false; 227 settings.highp_threshold_min = 2048; 228 229 host_ = cc::LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings); 230 host_->SetRootLayer(root_layer_); 231 232 host_->SetVisible(true); 233 host_->SetLayerTreeHostClientReady(); 234 host_->SetViewportSize(size_); 235 host_->set_has_transparent_background(has_transparent_background_); 236 // Need to recreate the UI resources because a new LayerTreeHost has been 237 // created. 238 client_->DidLoseUIResources(); 239 } 240 } 241 242 void CompositorImpl::setDeviceScaleFactor(float factor) { 243 if (host_) 244 host_->SetDeviceScaleFactor(factor); 245 } 246 247 void CompositorImpl::SetWindowBounds(const gfx::Size& size) { 248 if (size_ == size) 249 return; 250 251 size_ = size; 252 if (host_) 253 host_->SetViewportSize(size); 254 root_layer_->SetBounds(size); 255 } 256 257 bool CompositorImpl::CompositeAndReadback(void *pixels, const gfx::Rect& rect) { 258 if (host_) 259 return host_->CompositeAndReadback(pixels, rect); 260 else 261 return false; 262 } 263 264 cc::UIResourceId CompositorImpl::GenerateUIResource( 265 const cc::UIResourceBitmap& bitmap) { 266 if (!host_) 267 return 0; 268 scoped_ptr<cc::ScopedUIResource> ui_resource = 269 cc::ScopedUIResource::Create(host_.get(), bitmap); 270 cc::UIResourceId id = ui_resource->id(); 271 ui_resource_map_.set(id, ui_resource.Pass()); 272 return id; 273 } 274 275 void CompositorImpl::DeleteUIResource(cc::UIResourceId resource_id) { 276 UIResourceMap::iterator it = ui_resource_map_.find(resource_id); 277 if (it != ui_resource_map_.end()) 278 ui_resource_map_.erase(it); 279 } 280 281 blink::WebGLId CompositorImpl::GenerateTexture(gfx::JavaBitmap& bitmap) { 282 unsigned int texture_id = BuildBasicTexture(); 283 blink::WebGraphicsContext3D* context = 284 ImageTransportFactoryAndroid::GetInstance()->GetContext3D(); 285 if (texture_id == 0 || context->isContextLost() || 286 !context->makeContextCurrent()) 287 return 0; 288 blink::WebGLId format = GetGLFormatForBitmap(bitmap); 289 blink::WebGLId type = GetGLTypeForBitmap(bitmap); 290 291 context->texImage2D(GL_TEXTURE_2D, 292 0, 293 format, 294 bitmap.size().width(), 295 bitmap.size().height(), 296 0, 297 format, 298 type, 299 bitmap.pixels()); 300 context->shallowFlushCHROMIUM(); 301 return texture_id; 302 } 303 304 blink::WebGLId CompositorImpl::GenerateCompressedTexture(gfx::Size& size, 305 int data_size, 306 void* data) { 307 unsigned int texture_id = BuildBasicTexture(); 308 blink::WebGraphicsContext3D* context = 309 ImageTransportFactoryAndroid::GetInstance()->GetContext3D(); 310 if (texture_id == 0 || context->isContextLost() || 311 !context->makeContextCurrent()) 312 return 0; 313 context->compressedTexImage2D(GL_TEXTURE_2D, 314 0, 315 GL_ETC1_RGB8_OES, 316 size.width(), 317 size.height(), 318 0, 319 data_size, 320 data); 321 context->shallowFlushCHROMIUM(); 322 return texture_id; 323 } 324 325 void CompositorImpl::DeleteTexture(blink::WebGLId texture_id) { 326 blink::WebGraphicsContext3D* context = 327 ImageTransportFactoryAndroid::GetInstance()->GetContext3D(); 328 if (context->isContextLost() || !context->makeContextCurrent()) 329 return; 330 context->deleteTexture(texture_id); 331 context->shallowFlushCHROMIUM(); 332 } 333 334 bool CompositorImpl::CopyTextureToBitmap(blink::WebGLId texture_id, 335 gfx::JavaBitmap& bitmap) { 336 return CopyTextureToBitmap(texture_id, gfx::Rect(bitmap.size()), bitmap); 337 } 338 339 bool CompositorImpl::CopyTextureToBitmap(blink::WebGLId texture_id, 340 const gfx::Rect& sub_rect, 341 gfx::JavaBitmap& bitmap) { 342 // The sub_rect should match the bitmap size. 343 DCHECK(bitmap.size() == sub_rect.size()); 344 if (bitmap.size() != sub_rect.size() || texture_id == 0) return false; 345 346 GLHelper* helper = ImageTransportFactoryAndroid::GetInstance()->GetGLHelper(); 347 helper->ReadbackTextureSync(texture_id, 348 sub_rect, 349 static_cast<unsigned char*> (bitmap.pixels())); 350 return true; 351 } 352 353 static scoped_ptr<WebGraphicsContext3DCommandBufferImpl> 354 CreateGpuProcessViewContext( 355 const blink::WebGraphicsContext3D::Attributes attributes, 356 int surface_id) { 357 BrowserGpuChannelHostFactory* factory = 358 BrowserGpuChannelHostFactory::instance(); 359 CauseForGpuLaunch cause = 360 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE; 361 scoped_refptr<GpuChannelHost> gpu_channel_host( 362 factory->EstablishGpuChannelSync(cause)); 363 if (!gpu_channel_host) 364 return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>(); 365 366 GURL url("chrome://gpu/Compositor::createContext3D"); 367 static const size_t kBytesPerPixel = 4; 368 gfx::DeviceDisplayInfo display_info; 369 size_t full_screen_texture_size_in_bytes = 370 display_info.GetDisplayHeight() * 371 display_info.GetDisplayWidth() * 372 kBytesPerPixel; 373 WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits; 374 limits.command_buffer_size = 64 * 1024; 375 limits.start_transfer_buffer_size = 64 * 1024; 376 limits.min_transfer_buffer_size = 64 * 1024; 377 limits.max_transfer_buffer_size = std::min( 378 3 * full_screen_texture_size_in_bytes, kDefaultMaxTransferBufferSize); 379 limits.mapped_memory_reclaim_limit = 2 * 1024 * 1024; 380 return make_scoped_ptr( 381 new WebGraphicsContext3DCommandBufferImpl(surface_id, 382 url, 383 gpu_channel_host.get(), 384 attributes, 385 false, 386 limits)); 387 } 388 389 scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface( 390 bool fallback) { 391 blink::WebGraphicsContext3D::Attributes attrs; 392 attrs.shareResources = true; 393 attrs.noAutomaticFlushes = true; 394 395 DCHECK(window_); 396 DCHECK(surface_id_); 397 398 scoped_refptr<ContextProviderCommandBuffer> context_provider = 399 ContextProviderCommandBuffer::Create( 400 CreateGpuProcessViewContext(attrs, surface_id_), "BrowserCompositor"); 401 if (!context_provider.get()) { 402 LOG(ERROR) << "Failed to create 3D context for compositor."; 403 return scoped_ptr<cc::OutputSurface>(); 404 } 405 406 return scoped_ptr<cc::OutputSurface>( 407 new OutputSurfaceWithoutParent(context_provider)); 408 } 409 410 void CompositorImpl::OnLostResources() { 411 client_->DidLoseResources(); 412 } 413 414 scoped_refptr<cc::ContextProvider> CompositorImpl::OffscreenContextProvider() { 415 // There is no support for offscreen contexts, or compositor filters that 416 // would require them in this compositor instance. If they are needed, 417 // then implement a context provider that provides contexts from 418 // ImageTransportSurfaceAndroid. 419 return NULL; 420 } 421 422 void CompositorImpl::DidCompleteSwapBuffers() { 423 client_->OnSwapBuffersCompleted(); 424 } 425 426 void CompositorImpl::ScheduleComposite() { 427 client_->ScheduleComposite(); 428 } 429 430 void CompositorImpl::ScheduleAnimation() { 431 ScheduleComposite(); 432 } 433 434 void CompositorImpl::DidPostSwapBuffers() { 435 TRACE_EVENT0("compositor", "CompositorImpl::DidPostSwapBuffers"); 436 client_->OnSwapBuffersPosted(); 437 } 438 439 void CompositorImpl::DidAbortSwapBuffers() { 440 TRACE_EVENT0("compositor", "CompositorImpl::DidAbortSwapBuffers"); 441 client_->OnSwapBuffersCompleted(); 442 } 443 444 blink::WebGLId CompositorImpl::BuildBasicTexture() { 445 blink::WebGraphicsContext3D* context = 446 ImageTransportFactoryAndroid::GetInstance()->GetContext3D(); 447 if (context->isContextLost() || !context->makeContextCurrent()) 448 return 0; 449 blink::WebGLId texture_id = context->createTexture(); 450 context->bindTexture(GL_TEXTURE_2D, texture_id); 451 context->texParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 452 context->texParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 453 context->texParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 454 context->texParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 455 return texture_id; 456 } 457 458 blink::WGC3Denum CompositorImpl::GetGLFormatForBitmap( 459 gfx::JavaBitmap& bitmap) { 460 switch (bitmap.format()) { 461 case ANDROID_BITMAP_FORMAT_A_8: 462 return GL_ALPHA; 463 break; 464 case ANDROID_BITMAP_FORMAT_RGBA_4444: 465 return GL_RGBA; 466 break; 467 case ANDROID_BITMAP_FORMAT_RGBA_8888: 468 return GL_RGBA; 469 break; 470 case ANDROID_BITMAP_FORMAT_RGB_565: 471 default: 472 return GL_RGB; 473 } 474 } 475 476 blink::WGC3Denum CompositorImpl::GetGLTypeForBitmap(gfx::JavaBitmap& bitmap) { 477 switch (bitmap.format()) { 478 case ANDROID_BITMAP_FORMAT_A_8: 479 return GL_UNSIGNED_BYTE; 480 break; 481 case ANDROID_BITMAP_FORMAT_RGBA_4444: 482 return GL_UNSIGNED_SHORT_4_4_4_4; 483 break; 484 case ANDROID_BITMAP_FORMAT_RGBA_8888: 485 return GL_UNSIGNED_BYTE; 486 break; 487 case ANDROID_BITMAP_FORMAT_RGB_565: 488 default: 489 return GL_UNSIGNED_SHORT_5_6_5; 490 } 491 } 492 493 void CompositorImpl::DidCommit() { 494 root_window_->OnCompositingDidCommit(); 495 } 496 497 } // namespace content 498