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/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 "gpu/command_buffer/client/gles2_interface.h"
39 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
40 #include "third_party/khronos/GLES2/gl2.h"
41 #include "third_party/khronos/GLES2/gl2ext.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(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 static bool g_initialized
= false;
96 } // anonymous namespace
100 typedef std::map
<int, base::android::ScopedJavaGlobalRef
<jobject
> >
102 static base::LazyInstance
<SurfaceMap
>
103 g_surface_map
= LAZY_INSTANCE_INITIALIZER
;
104 static base::LazyInstance
<base::Lock
> g_surface_map_lock
;
107 Compositor
* Compositor::Create(CompositorClient
* client
,
108 gfx::NativeWindow root_window
) {
109 return client
? new CompositorImpl(client
, root_window
) : NULL
;
113 void Compositor::Initialize() {
114 DCHECK(!CompositorImpl::IsInitialized());
115 g_initialized
= true;
119 bool CompositorImpl::IsInitialized() {
120 return g_initialized
;
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();
130 LOG_IF(WARNING
, !jsurface
) << "No surface for surface id " << surface_id
;
134 CompositorImpl::CompositorImpl(CompositorClient
* client
,
135 gfx::NativeWindow root_window
)
136 : root_layer_(cc::Layer::Create()),
137 has_transparent_background_(false),
141 root_window_(root_window
) {
144 ImageTransportFactoryAndroid::AddObserver(this);
145 root_window
->AttachCompositor();
148 CompositorImpl::~CompositorImpl() {
149 root_window_
->DetachCompositor();
150 ImageTransportFactoryAndroid::RemoveObserver(this);
151 // Clean-up any surface references.
155 void CompositorImpl::Composite() {
157 host_
->Composite(gfx::FrameTime::Now());
160 void CompositorImpl::SetRootLayer(scoped_refptr
<cc::Layer
> root_layer
) {
161 root_layer_
->RemoveAllChildren();
162 root_layer_
->AddChild(root_layer
);
165 void CompositorImpl::SetWindowSurface(ANativeWindow
* window
) {
166 GpuSurfaceTracker
* tracker
= GpuSurfaceTracker::Get();
169 tracker
->RemoveSurface(surface_id_
);
170 ANativeWindow_release(window_
);
178 ANativeWindow_acquire(window
);
179 surface_id_
= tracker
->AddSurfaceForNativeWidget(window
);
180 tracker
->SetSurfaceHandle(
182 gfx::GLSurfaceHandle(gfx::kNullPluginWindow
, gfx::NATIVE_DIRECT
));
187 void CompositorImpl::SetSurface(jobject surface
) {
188 JNIEnv
* env
= base::android::AttachCurrentThread();
189 base::android::ScopedJavaLocalRef
<jobject
> j_surface(env
, surface
);
191 // First, cleanup any existing surface references.
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_
);
198 SetWindowSurface(NULL
);
200 // Now, set the new surface if we have one.
201 ANativeWindow
* window
= NULL
;
203 window
= ANativeWindow_fromSurface(env
, surface
);
205 SetWindowSurface(window
);
206 ANativeWindow_release(window
);
208 base::AutoLock
lock(g_surface_map_lock
.Get());
209 g_surface_map
.Get().insert(std::make_pair(surface_id_
, j_surface
));
214 void CompositorImpl::SetVisible(bool visible
) {
216 ui_resource_map_
.clear();
218 client_
->UIResourcesAreInvalid();
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;
229 host_
= cc::LayerTreeHost::CreateSingleThreaded(this, this, NULL
, settings
);
230 host_
->SetRootLayer(root_layer_
);
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
238 client_
->DidLoseUIResources();
242 void CompositorImpl::setDeviceScaleFactor(float factor
) {
244 host_
->SetDeviceScaleFactor(factor
);
247 void CompositorImpl::SetWindowBounds(const gfx::Size
& size
) {
253 host_
->SetViewportSize(size
);
254 root_layer_
->SetBounds(size
);
257 void CompositorImpl::SetHasTransparentBackground(bool flag
) {
258 has_transparent_background_
= flag
;
260 host_
->set_has_transparent_background(flag
);
263 bool CompositorImpl::CompositeAndReadback(void *pixels
, const gfx::Rect
& rect
) {
265 return host_
->CompositeAndReadback(pixels
, rect
);
270 cc::UIResourceId
CompositorImpl::GenerateUIResource(
271 const cc::UIResourceBitmap
& bitmap
) {
274 scoped_ptr
<cc::ScopedUIResource
> ui_resource
=
275 cc::ScopedUIResource::Create(host_
.get(), bitmap
);
276 cc::UIResourceId id
= ui_resource
->id();
277 ui_resource_map_
.set(id
, ui_resource
.Pass());
281 void CompositorImpl::DeleteUIResource(cc::UIResourceId resource_id
) {
282 UIResourceMap::iterator it
= ui_resource_map_
.find(resource_id
);
283 if (it
!= ui_resource_map_
.end())
284 ui_resource_map_
.erase(it
);
287 blink::WebGLId
CompositorImpl::GenerateTexture(gfx::JavaBitmap
& bitmap
) {
288 unsigned int texture_id
= BuildBasicTexture();
289 blink::WebGraphicsContext3D
* context
=
290 ImageTransportFactoryAndroid::GetInstance()->GetContext3D();
291 if (texture_id
== 0 || context
->isContextLost() ||
292 !context
->makeContextCurrent())
294 blink::WebGLId format
= GetGLFormatForBitmap(bitmap
);
295 blink::WebGLId type
= GetGLTypeForBitmap(bitmap
);
297 context
->texImage2D(GL_TEXTURE_2D
,
300 bitmap
.size().width(),
301 bitmap
.size().height(),
306 context
->shallowFlushCHROMIUM();
310 blink::WebGLId
CompositorImpl::GenerateCompressedTexture(gfx::Size
& size
,
313 unsigned int texture_id
= BuildBasicTexture();
314 blink::WebGraphicsContext3D
* context
=
315 ImageTransportFactoryAndroid::GetInstance()->GetContext3D();
316 if (texture_id
== 0 || context
->isContextLost() ||
317 !context
->makeContextCurrent())
319 context
->compressedTexImage2D(GL_TEXTURE_2D
,
327 context
->shallowFlushCHROMIUM();
331 void CompositorImpl::DeleteTexture(blink::WebGLId texture_id
) {
332 blink::WebGraphicsContext3D
* context
=
333 ImageTransportFactoryAndroid::GetInstance()->GetContext3D();
334 if (context
->isContextLost() || !context
->makeContextCurrent())
336 context
->deleteTexture(texture_id
);
337 context
->shallowFlushCHROMIUM();
340 bool CompositorImpl::CopyTextureToBitmap(blink::WebGLId texture_id
,
341 gfx::JavaBitmap
& bitmap
) {
342 return CopyTextureToBitmap(texture_id
, gfx::Rect(bitmap
.size()), bitmap
);
345 bool CompositorImpl::CopyTextureToBitmap(blink::WebGLId texture_id
,
346 const gfx::Rect
& sub_rect
,
347 gfx::JavaBitmap
& bitmap
) {
348 // The sub_rect should match the bitmap size.
349 DCHECK(bitmap
.size() == sub_rect
.size());
350 if (bitmap
.size() != sub_rect
.size() || texture_id
== 0) return false;
352 GLHelper
* helper
= ImageTransportFactoryAndroid::GetInstance()->GetGLHelper();
353 helper
->ReadbackTextureSync(texture_id
,
355 static_cast<unsigned char*> (bitmap
.pixels()));
359 static scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>
360 CreateGpuProcessViewContext(
361 const blink::WebGraphicsContext3D::Attributes attributes
,
363 BrowserGpuChannelHostFactory
* factory
=
364 BrowserGpuChannelHostFactory::instance();
365 CauseForGpuLaunch cause
=
366 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE
;
367 scoped_refptr
<GpuChannelHost
> gpu_channel_host(
368 factory
->EstablishGpuChannelSync(cause
));
369 if (!gpu_channel_host
)
370 return scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>();
372 GURL
url("chrome://gpu/Compositor::createContext3D");
373 static const size_t kBytesPerPixel
= 4;
374 gfx::DeviceDisplayInfo display_info
;
375 size_t full_screen_texture_size_in_bytes
=
376 display_info
.GetDisplayHeight() *
377 display_info
.GetDisplayWidth() *
379 WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits
;
380 limits
.command_buffer_size
= 64 * 1024;
381 limits
.start_transfer_buffer_size
= 64 * 1024;
382 limits
.min_transfer_buffer_size
= 64 * 1024;
383 limits
.max_transfer_buffer_size
= std::min(
384 3 * full_screen_texture_size_in_bytes
, kDefaultMaxTransferBufferSize
);
385 limits
.mapped_memory_reclaim_limit
= 2 * 1024 * 1024;
386 return make_scoped_ptr(
387 new WebGraphicsContext3DCommandBufferImpl(surface_id
,
389 gpu_channel_host
.get(),
395 scoped_ptr
<cc::OutputSurface
> CompositorImpl::CreateOutputSurface(
397 blink::WebGraphicsContext3D::Attributes attrs
;
398 attrs
.shareResources
= true;
399 attrs
.noAutomaticFlushes
= true;
404 scoped_refptr
<ContextProviderCommandBuffer
> context_provider
=
405 ContextProviderCommandBuffer::Create(
406 CreateGpuProcessViewContext(attrs
, surface_id_
), "BrowserCompositor");
407 if (!context_provider
.get()) {
408 LOG(ERROR
) << "Failed to create 3D context for compositor.";
409 return scoped_ptr
<cc::OutputSurface
>();
412 return scoped_ptr
<cc::OutputSurface
>(
413 new OutputSurfaceWithoutParent(context_provider
));
416 void CompositorImpl::OnLostResources() {
417 client_
->DidLoseResources();
420 scoped_refptr
<cc::ContextProvider
> CompositorImpl::OffscreenContextProvider() {
421 // There is no support for offscreen contexts, or compositor filters that
422 // would require them in this compositor instance. If they are needed,
423 // then implement a context provider that provides contexts from
424 // ImageTransportSurfaceAndroid.
428 void CompositorImpl::DidCompleteSwapBuffers() {
429 client_
->OnSwapBuffersCompleted();
432 void CompositorImpl::ScheduleComposite() {
433 client_
->ScheduleComposite();
436 void CompositorImpl::ScheduleAnimation() {
440 void CompositorImpl::DidPostSwapBuffers() {
441 TRACE_EVENT0("compositor", "CompositorImpl::DidPostSwapBuffers");
442 client_
->OnSwapBuffersPosted();
445 void CompositorImpl::DidAbortSwapBuffers() {
446 TRACE_EVENT0("compositor", "CompositorImpl::DidAbortSwapBuffers");
447 client_
->OnSwapBuffersCompleted();
450 blink::WebGLId
CompositorImpl::BuildBasicTexture() {
451 blink::WebGraphicsContext3D
* context
=
452 ImageTransportFactoryAndroid::GetInstance()->GetContext3D();
453 if (context
->isContextLost() || !context
->makeContextCurrent())
455 blink::WebGLId texture_id
= context
->createTexture();
456 context
->bindTexture(GL_TEXTURE_2D
, texture_id
);
457 context
->texParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
458 context
->texParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
459 context
->texParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
460 context
->texParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
464 blink::WGC3Denum
CompositorImpl::GetGLFormatForBitmap(
465 gfx::JavaBitmap
& bitmap
) {
466 switch (bitmap
.format()) {
467 case ANDROID_BITMAP_FORMAT_A_8
:
470 case ANDROID_BITMAP_FORMAT_RGBA_4444
:
473 case ANDROID_BITMAP_FORMAT_RGBA_8888
:
476 case ANDROID_BITMAP_FORMAT_RGB_565
:
482 blink::WGC3Denum
CompositorImpl::GetGLTypeForBitmap(gfx::JavaBitmap
& bitmap
) {
483 switch (bitmap
.format()) {
484 case ANDROID_BITMAP_FORMAT_A_8
:
485 return GL_UNSIGNED_BYTE
;
487 case ANDROID_BITMAP_FORMAT_RGBA_4444
:
488 return GL_UNSIGNED_SHORT_4_4_4_4
;
490 case ANDROID_BITMAP_FORMAT_RGBA_8888
:
491 return GL_UNSIGNED_BYTE
;
493 case ANDROID_BITMAP_FORMAT_RGB_565
:
495 return GL_UNSIGNED_SHORT_5_6_5
;
499 void CompositorImpl::DidCommit() {
500 root_window_
->OnCompositingDidCommit();
503 } // namespace content