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