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/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