Home | History | Annotate | Download | only in renderer_host
      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