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.
5 #include "content/browser/renderer_host/compositor_impl_android.h"
7 #include <android/bitmap.h>
8 #include <android/native_window_jni.h>
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"
55 // Used for drawing directly to the screen. Bypasses resizing and swaps.
56 class DirectOutputSurface : public cc::OutputSurface {
59 const scoped_refptr<cc::ContextProvider>& context_provider)
60 : cc::OutputSurface(context_provider) {
61 capabilities_.adjust_deadline_for_parent = false;
64 virtual void Reshape(const gfx::Size& size, float scale_factor) OVERRIDE {
67 virtual void SwapBuffers(cc::CompositorFrame*) OVERRIDE {
68 context_provider_->ContextGL()->ShallowFlushCHROMIUM();
72 // Used to override capabilities_.adjust_deadline_for_parent to false
73 class OutputSurfaceWithoutParent : public cc::OutputSurface {
75 OutputSurfaceWithoutParent(const scoped_refptr<
76 content::ContextProviderCommandBuffer>& context_provider)
77 : cc::OutputSurface(context_provider) {
78 capabilities_.adjust_deadline_for_parent = false;
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);
90 OutputSurface::SwapBuffers(frame);
94 class TransientUIResource : public cc::ScopedUIResource {
96 static scoped_ptr<TransientUIResource> Create(
97 cc::LayerTreeHost* host,
98 const cc::UIResourceBitmap& bitmap) {
99 return make_scoped_ptr(new TransientUIResource(host, bitmap));
102 virtual cc::UIResourceBitmap GetBitmap(cc::UIResourceId uid,
103 bool resource_lost) OVERRIDE {
105 cc::UIResourceBitmap old_bitmap(bitmap_);
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();
116 // Release our reference of the true bitmap.
117 bitmap_ = cc::UIResourceBitmap(tiny_bitmap);
126 TransientUIResource(cc::LayerTreeHost* host,
127 const cc::UIResourceBitmap& bitmap)
128 : cc::ScopedUIResource(host, bitmap), retrieved_(false) {}
134 static bool g_initialized = false;
136 } // anonymous namespace
140 typedef std::map<int, base::android::ScopedJavaGlobalRef<jobject> >
142 static base::LazyInstance<SurfaceMap>
143 g_surface_map = LAZY_INSTANCE_INITIALIZER;
144 static base::LazyInstance<base::Lock> g_surface_map_lock;
147 Compositor* Compositor::Create(CompositorClient* client,
148 gfx::NativeWindow root_window) {
149 return client ? new CompositorImpl(client, root_window) : NULL;
153 void Compositor::Initialize() {
154 DCHECK(!CompositorImpl::IsInitialized());
155 g_initialized = true;
159 bool CompositorImpl::IsInitialized() {
160 return g_initialized;
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();
170 LOG_IF(WARNING, !jsurface) << "No surface for surface id " << surface_id;
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),
182 root_window_(root_window) {
185 ImageTransportFactoryAndroid::AddObserver(this);
186 root_window->AttachCompositor(this);
189 CompositorImpl::~CompositorImpl() {
190 root_window_->DetachCompositor();
191 ImageTransportFactoryAndroid::RemoveObserver(this);
192 // Clean-up any surface references.
196 void CompositorImpl::Composite() {
198 host_->Composite(gfx::FrameTime::Now());
201 void CompositorImpl::SetRootLayer(scoped_refptr<cc::Layer> root_layer) {
202 root_layer_->RemoveAllChildren();
203 root_layer_->AddChild(root_layer);
206 void CompositorImpl::SetWindowSurface(ANativeWindow* window) {
207 GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();
210 tracker->RemoveSurface(surface_id_);
211 ANativeWindow_release(window_);
219 ANativeWindow_acquire(window);
220 surface_id_ = tracker->AddSurfaceForNativeWidget(window);
221 tracker->SetSurfaceHandle(
223 gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::NATIVE_DIRECT));
228 void CompositorImpl::SetSurface(jobject surface) {
229 JNIEnv* env = base::android::AttachCurrentThread();
230 base::android::ScopedJavaLocalRef<jobject> j_surface(env, surface);
232 // First, cleanup any existing surface references.
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_);
239 SetWindowSurface(NULL);
241 // Now, set the new surface if we have one.
242 ANativeWindow* window = NULL;
244 window = ANativeWindow_fromSurface(env, surface);
246 SetWindowSurface(window);
247 ANativeWindow_release(window);
249 base::AutoLock lock(g_surface_map_lock.Get());
250 g_surface_map.Get().insert(std::make_pair(surface_id_, j_surface));
255 void CompositorImpl::SetVisible(bool visible) {
257 ui_resource_map_.clear();
259 client_->UIResourcesAreInvalid();
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;
270 CommandLine* command_line = CommandLine::ForCurrentProcess();
271 settings.initial_debug_state.SetRecordRenderingStats(
272 command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking));
274 host_ = cc::LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings);
275 host_->SetRootLayer(root_layer_);
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
284 client_->DidLoseUIResources();
288 void CompositorImpl::setDeviceScaleFactor(float factor) {
289 device_scale_factor_ = factor;
291 host_->SetDeviceScaleFactor(factor);
294 void CompositorImpl::SetWindowBounds(const gfx::Size& size) {
300 host_->SetViewportSize(size);
301 root_layer_->SetBounds(size);
304 void CompositorImpl::SetHasTransparentBackground(bool flag) {
305 has_transparent_background_ = flag;
307 host_->set_has_transparent_background(flag);
310 bool CompositorImpl::CompositeAndReadback(void *pixels, const gfx::Rect& rect) {
312 return host_->CompositeAndReadback(pixels, rect);
317 cc::UIResourceId CompositorImpl::GenerateUIResourceFromUIResourceBitmap(
318 const cc::UIResourceBitmap& bitmap,
323 cc::UIResourceId id = 0;
324 scoped_ptr<cc::UIResourceClient> resource;
326 scoped_ptr<TransientUIResource> transient_resource =
327 TransientUIResource::Create(host_.get(), bitmap);
328 id = transient_resource->id();
329 resource = transient_resource.Pass();
331 scoped_ptr<cc::ScopedUIResource> scoped_resource =
332 cc::ScopedUIResource::Create(host_.get(), bitmap);
333 id = scoped_resource->id();
334 resource = scoped_resource.Pass();
337 ui_resource_map_.set(id, resource.Pass());
341 cc::UIResourceId CompositorImpl::GenerateUIResource(const SkBitmap& bitmap,
343 return GenerateUIResourceFromUIResourceBitmap(cc::UIResourceBitmap(bitmap),
347 cc::UIResourceId CompositorImpl::GenerateCompressedUIResource(
348 const gfx::Size& size,
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);
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);
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);
373 static scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
374 CreateGpuProcessViewContext(
375 const blink::WebGraphicsContext3D::Attributes attributes,
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>();
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() *
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;
403 bool lose_context_when_out_of_memory = true;
404 return make_scoped_ptr(
405 new WebGraphicsContext3DCommandBufferImpl(surface_id,
407 gpu_channel_host.get(),
409 #if !defined(OS_CHROMEOS)
410 bind_generates_resource,
412 lose_context_when_out_of_memory,
417 scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface(
419 blink::WebGraphicsContext3D::Attributes attrs;
420 attrs.shareResources = true;
421 attrs.noAutomaticFlushes = true;
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>();
434 return scoped_ptr<cc::OutputSurface>(
435 new OutputSurfaceWithoutParent(context_provider));
438 void CompositorImpl::OnLostResources() {
439 client_->DidLoseResources();
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.
450 void CompositorImpl::DidCompleteSwapBuffers() {
451 client_->OnSwapBuffersCompleted();
454 void CompositorImpl::ScheduleComposite() {
455 client_->ScheduleComposite();
458 void CompositorImpl::ScheduleAnimation() {
462 void CompositorImpl::DidPostSwapBuffers() {
463 TRACE_EVENT0("compositor", "CompositorImpl::DidPostSwapBuffers");
464 client_->OnSwapBuffersPosted();
467 void CompositorImpl::DidAbortSwapBuffers() {
468 TRACE_EVENT0("compositor", "CompositorImpl::DidAbortSwapBuffers");
469 client_->OnSwapBuffersCompleted();
472 void CompositorImpl::DidCommit() {
473 root_window_->OnCompositingDidCommit();
476 void CompositorImpl::AttachLayerForReadback(scoped_refptr<cc::Layer> layer) {
477 root_layer_->AddChild(layer);
480 } // namespace content