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