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>
10 #include "base/android/jni_android.h"
11 #include "base/android/scoped_java_ref.h"
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/containers/hash_tables.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 "base/threading/thread_checker.h"
21 #include "cc/base/switches.h"
22 #include "cc/input/input_handler.h"
23 #include "cc/layers/layer.h"
24 #include "cc/output/compositor_frame.h"
25 #include "cc/output/context_provider.h"
26 #include "cc/output/output_surface.h"
27 #include "cc/resources/scoped_ui_resource.h"
28 #include "cc/resources/ui_resource_bitmap.h"
29 #include "cc/trees/layer_tree_host.h"
30 #include "content/browser/android/child_process_launcher_android.h"
31 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
32 #include "content/browser/gpu/gpu_surface_tracker.h"
33 #include "content/common/gpu/client/command_buffer_proxy_impl.h"
34 #include "content/common/gpu/client/context_provider_command_buffer.h"
35 #include "content/common/gpu/client/gl_helper.h"
36 #include "content/common/gpu/client/gpu_channel_host.h"
37 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
38 #include "content/common/gpu/gpu_process_launch_causes.h"
39 #include "content/common/host_shared_bitmap_manager.h"
40 #include "content/public/browser/android/compositor_client.h"
41 #include "gpu/command_buffer/client/gles2_interface.h"
42 #include "third_party/khronos/GLES2/gl2.h"
43 #include "third_party/khronos/GLES2/gl2ext.h"
44 #include "third_party/skia/include/core/SkMallocPixelRef.h"
45 #include "ui/base/android/window_android.h"
46 #include "ui/gfx/android/device_display_info.h"
47 #include "ui/gfx/android/java_bitmap.h"
48 #include "ui/gfx/frame_time.h"
49 #include "ui/gl/android/surface_texture.h"
50 #include "ui/gl/android/surface_texture_tracker.h"
51 #include "webkit/common/gpu/context_provider_in_process.h"
52 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
60 // Used to override capabilities_.adjust_deadline_for_parent to false
61 class OutputSurfaceWithoutParent
: public cc::OutputSurface
{
63 OutputSurfaceWithoutParent(const scoped_refptr
<
64 content::ContextProviderCommandBuffer
>& context_provider
)
65 : cc::OutputSurface(context_provider
) {
66 capabilities_
.adjust_deadline_for_parent
= false;
69 virtual void SwapBuffers(cc::CompositorFrame
* frame
) OVERRIDE
{
70 content::ContextProviderCommandBuffer
* provider_command_buffer
=
71 static_cast<content::ContextProviderCommandBuffer
*>(
72 context_provider_
.get());
73 content::CommandBufferProxyImpl
* command_buffer_proxy
=
74 provider_command_buffer
->GetCommandBufferProxy();
75 DCHECK(command_buffer_proxy
);
76 command_buffer_proxy
->SetLatencyInfo(frame
->metadata
.latency_info
);
78 OutputSurface::SwapBuffers(frame
);
82 class TransientUIResource
: public cc::ScopedUIResource
{
84 static scoped_ptr
<TransientUIResource
> Create(
85 cc::LayerTreeHost
* host
,
86 const cc::UIResourceBitmap
& bitmap
) {
87 return make_scoped_ptr(new TransientUIResource(host
, bitmap
));
90 virtual cc::UIResourceBitmap
GetBitmap(cc::UIResourceId uid
,
91 bool resource_lost
) OVERRIDE
{
93 cc::UIResourceBitmap
old_bitmap(bitmap_
);
95 // Return a place holder for all following calls to GetBitmap.
97 SkCanvas
canvas(tiny_bitmap
);
98 tiny_bitmap
.setConfig(
99 SkBitmap::kARGB_8888_Config
, 1, 1, 0, kOpaque_SkAlphaType
);
100 tiny_bitmap
.allocPixels();
101 canvas
.drawColor(SK_ColorWHITE
);
102 tiny_bitmap
.setImmutable();
104 // Release our reference of the true bitmap.
105 bitmap_
= cc::UIResourceBitmap(tiny_bitmap
);
114 TransientUIResource(cc::LayerTreeHost
* host
,
115 const cc::UIResourceBitmap
& bitmap
)
116 : cc::ScopedUIResource(host
, bitmap
), retrieved_(false) {}
122 class SurfaceTextureTrackerImpl
: public gfx::SurfaceTextureTracker
{
124 SurfaceTextureTrackerImpl() : next_surface_texture_id_(1) {
125 thread_checker_
.DetachFromThread();
128 // Overridden from gfx::SurfaceTextureTracker:
129 virtual scoped_refptr
<gfx::SurfaceTexture
> AcquireSurfaceTexture(
131 int secondary_id
) OVERRIDE
{
132 base::AutoLock
lock(surface_textures_lock_
);
133 SurfaceTextureMapKey
key(primary_id
, secondary_id
);
134 SurfaceTextureMap::iterator it
= surface_textures_
.find(key
);
135 if (it
== surface_textures_
.end())
136 return scoped_refptr
<gfx::SurfaceTexture
>();
137 scoped_refptr
<gfx::SurfaceTexture
> surface_texture
= it
->second
;
138 surface_textures_
.erase(it
);
139 return surface_texture
;
142 int AddSurfaceTexture(gfx::SurfaceTexture
* surface_texture
,
143 int child_process_id
) {
144 DCHECK(thread_checker_
.CalledOnValidThread());
145 int surface_texture_id
= next_surface_texture_id_
++;
146 if (next_surface_texture_id_
== INT_MAX
)
147 next_surface_texture_id_
= 1;
149 base::AutoLock
lock(surface_textures_lock_
);
150 SurfaceTextureMapKey
key(surface_texture_id
, child_process_id
);
151 DCHECK(surface_textures_
.find(key
) == surface_textures_
.end());
152 surface_textures_
[key
] = surface_texture
;
153 content::RegisterChildProcessSurfaceTexture(
156 surface_texture
->j_surface_texture().obj());
157 return surface_texture_id
;
160 void RemoveAllSurfaceTextures(int child_process_id
) {
161 DCHECK(thread_checker_
.CalledOnValidThread());
162 base::AutoLock
lock(surface_textures_lock_
);
163 SurfaceTextureMap::iterator it
= surface_textures_
.begin();
164 while (it
!= surface_textures_
.end()) {
165 if (it
->first
.second
== child_process_id
) {
166 content::UnregisterChildProcessSurfaceTexture(it
->first
.first
,
168 surface_textures_
.erase(it
++);
176 typedef std::pair
<int, int> SurfaceTextureMapKey
;
177 typedef base::hash_map
<SurfaceTextureMapKey
,
178 scoped_refptr
<gfx::SurfaceTexture
> >
180 SurfaceTextureMap surface_textures_
;
181 mutable base::Lock surface_textures_lock_
;
182 int next_surface_texture_id_
;
183 base::ThreadChecker thread_checker_
;
185 base::LazyInstance
<SurfaceTextureTrackerImpl
> g_surface_texture_tracker
=
186 LAZY_INSTANCE_INITIALIZER
;
188 static bool g_initialized
= false;
190 } // anonymous namespace
195 Compositor
* Compositor::Create(CompositorClient
* client
,
196 gfx::NativeWindow root_window
) {
197 return client
? new CompositorImpl(client
, root_window
) : NULL
;
201 void Compositor::Initialize() {
202 DCHECK(!CompositorImpl::IsInitialized());
203 // SurfaceTextureTracker instance must be set before we create a GPU thread
204 // that could be using it to initialize GLImage instances.
205 gfx::SurfaceTextureTracker::InitInstance(g_surface_texture_tracker
.Pointer());
206 g_initialized
= true;
210 bool CompositorImpl::IsInitialized() {
211 return g_initialized
;
215 int CompositorImpl::CreateSurfaceTexture(int child_process_id
) {
216 // Note: this needs to be 0 as the surface texture implemenation will take
217 // ownership of the texture and call glDeleteTextures when the GPU service
218 // attaches the surface texture to a real texture id. glDeleteTextures
219 // silently ignores 0.
220 const int kDummyTextureId
= 0;
221 scoped_refptr
<gfx::SurfaceTexture
> surface_texture
=
222 gfx::SurfaceTexture::Create(kDummyTextureId
);
223 return g_surface_texture_tracker
.Pointer()->AddSurfaceTexture(
224 surface_texture
.get(), child_process_id
);
228 void CompositorImpl::DestroyAllSurfaceTextures(int child_process_id
) {
229 g_surface_texture_tracker
.Pointer()->RemoveAllSurfaceTextures(
233 CompositorImpl::CompositorImpl(CompositorClient
* client
,
234 gfx::NativeWindow root_window
)
235 : root_layer_(cc::Layer::Create()),
236 has_transparent_background_(false),
237 device_scale_factor_(1),
241 root_window_(root_window
) {
244 ImageTransportFactoryAndroid::AddObserver(this);
245 root_window
->AttachCompositor(this);
248 CompositorImpl::~CompositorImpl() {
249 root_window_
->DetachCompositor();
250 ImageTransportFactoryAndroid::RemoveObserver(this);
251 // Clean-up any surface references.
255 void CompositorImpl::Composite() {
257 host_
->Composite(gfx::FrameTime::Now());
260 void CompositorImpl::SetRootLayer(scoped_refptr
<cc::Layer
> root_layer
) {
261 root_layer_
->RemoveAllChildren();
263 root_layer_
->AddChild(root_layer
);
266 void CompositorImpl::SetWindowSurface(ANativeWindow
* window
) {
267 GpuSurfaceTracker
* tracker
= GpuSurfaceTracker::Get();
270 tracker
->RemoveSurface(surface_id_
);
271 ANativeWindow_release(window_
);
279 ANativeWindow_acquire(window
);
280 surface_id_
= tracker
->AddSurfaceForNativeWidget(window
);
281 tracker
->SetSurfaceHandle(
283 gfx::GLSurfaceHandle(gfx::kNullPluginWindow
, gfx::NATIVE_DIRECT
));
288 void CompositorImpl::SetSurface(jobject surface
) {
289 JNIEnv
* env
= base::android::AttachCurrentThread();
290 base::android::ScopedJavaLocalRef
<jobject
> j_surface(env
, surface
);
292 // First, cleanup any existing surface references.
294 content::UnregisterViewSurface(surface_id_
);
295 SetWindowSurface(NULL
);
297 // Now, set the new surface if we have one.
298 ANativeWindow
* window
= NULL
;
300 // Note: This ensures that any local references used by
301 // ANativeWindow_fromSurface are released immediately. This is needed as a
302 // workaround for https://code.google.com/p/android/issues/detail?id=68174
303 base::android::ScopedJavaLocalFrame
scoped_local_reference_frame(env
);
304 window
= ANativeWindow_fromSurface(env
, surface
);
307 SetWindowSurface(window
);
308 ANativeWindow_release(window
);
309 content::RegisterViewSurface(surface_id_
, j_surface
.obj());
313 void CompositorImpl::SetVisible(bool visible
) {
315 ui_resource_map_
.clear();
317 client_
->UIResourcesAreInvalid();
319 cc::LayerTreeSettings settings
;
320 settings
.refresh_rate
= 60.0;
321 settings
.impl_side_painting
= false;
322 settings
.allow_antialiasing
= false;
323 settings
.calculate_top_controls_position
= false;
324 settings
.top_controls_height
= 0.f
;
325 settings
.highp_threshold_min
= 2048;
327 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
328 settings
.initial_debug_state
.SetRecordRenderingStats(
329 command_line
->HasSwitch(cc::switches::kEnableGpuBenchmarking
));
330 settings
.initial_debug_state
.show_fps_counter
=
331 command_line
->HasSwitch(cc::switches::kUIShowFPSCounter
);
333 host_
= cc::LayerTreeHost::CreateSingleThreaded(
334 this, this, HostSharedBitmapManager::current(), settings
);
335 host_
->SetRootLayer(root_layer_
);
337 host_
->SetVisible(true);
338 host_
->SetLayerTreeHostClientReady();
339 host_
->SetViewportSize(size_
);
340 host_
->set_has_transparent_background(has_transparent_background_
);
341 host_
->SetDeviceScaleFactor(device_scale_factor_
);
342 // Need to recreate the UI resources because a new LayerTreeHost has been
344 client_
->DidLoseUIResources();
348 void CompositorImpl::setDeviceScaleFactor(float factor
) {
349 device_scale_factor_
= factor
;
351 host_
->SetDeviceScaleFactor(factor
);
354 void CompositorImpl::SetWindowBounds(const gfx::Size
& size
) {
360 host_
->SetViewportSize(size
);
361 root_layer_
->SetBounds(size
);
364 void CompositorImpl::SetHasTransparentBackground(bool flag
) {
365 has_transparent_background_
= flag
;
367 host_
->set_has_transparent_background(flag
);
370 bool CompositorImpl::CompositeAndReadback(void *pixels
, const gfx::Rect
& rect
) {
372 return host_
->CompositeAndReadback(pixels
, rect
);
377 cc::UIResourceId
CompositorImpl::GenerateUIResourceFromUIResourceBitmap(
378 const cc::UIResourceBitmap
& bitmap
,
383 cc::UIResourceId id
= 0;
384 scoped_ptr
<cc::UIResourceClient
> resource
;
386 scoped_ptr
<TransientUIResource
> transient_resource
=
387 TransientUIResource::Create(host_
.get(), bitmap
);
388 id
= transient_resource
->id();
389 resource
= transient_resource
.Pass();
391 scoped_ptr
<cc::ScopedUIResource
> scoped_resource
=
392 cc::ScopedUIResource::Create(host_
.get(), bitmap
);
393 id
= scoped_resource
->id();
394 resource
= scoped_resource
.Pass();
397 ui_resource_map_
.set(id
, resource
.Pass());
401 cc::UIResourceId
CompositorImpl::GenerateUIResource(const SkBitmap
& bitmap
,
403 return GenerateUIResourceFromUIResourceBitmap(cc::UIResourceBitmap(bitmap
),
407 cc::UIResourceId
CompositorImpl::GenerateCompressedUIResource(
408 const gfx::Size
& size
,
411 DCHECK_LT(0, size
.width());
412 DCHECK_LT(0, size
.height());
413 DCHECK_EQ(0, size
.width() % 4);
414 DCHECK_EQ(0, size
.height() % 4);
416 size_t data_size
= size
.width() * size
.height() / 2;
417 SkImageInfo info
= {size
.width(), size
.height() / 2, kAlpha_8_SkColorType
,
418 kPremul_SkAlphaType
};
419 skia::RefPtr
<SkMallocPixelRef
> etc1_pixel_ref
=
420 skia::AdoptRef(SkMallocPixelRef::NewAllocate(info
, 0, 0));
421 memcpy(etc1_pixel_ref
->getAddr(), pixels
, data_size
);
422 etc1_pixel_ref
->setImmutable();
423 return GenerateUIResourceFromUIResourceBitmap(
424 cc::UIResourceBitmap(etc1_pixel_ref
, size
), is_transient
);
427 void CompositorImpl::DeleteUIResource(cc::UIResourceId resource_id
) {
428 UIResourceMap::iterator it
= ui_resource_map_
.find(resource_id
);
429 if (it
!= ui_resource_map_
.end())
430 ui_resource_map_
.erase(it
);
433 static scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>
434 CreateGpuProcessViewContext(
435 const blink::WebGraphicsContext3D::Attributes attributes
,
437 BrowserGpuChannelHostFactory
* factory
=
438 BrowserGpuChannelHostFactory::instance();
439 CauseForGpuLaunch cause
=
440 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE
;
441 scoped_refptr
<GpuChannelHost
> gpu_channel_host(
442 factory
->EstablishGpuChannelSync(cause
));
443 if (!gpu_channel_host
)
444 return scoped_ptr
<WebGraphicsContext3DCommandBufferImpl
>();
446 GURL
url("chrome://gpu/Compositor::createContext3D");
447 static const size_t kBytesPerPixel
= 4;
448 gfx::DeviceDisplayInfo display_info
;
449 size_t full_screen_texture_size_in_bytes
=
450 display_info
.GetDisplayHeight() *
451 display_info
.GetDisplayWidth() *
453 WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits
;
454 limits
.command_buffer_size
= 64 * 1024;
455 limits
.start_transfer_buffer_size
= 64 * 1024;
456 limits
.min_transfer_buffer_size
= 64 * 1024;
457 limits
.max_transfer_buffer_size
= std::min(
458 3 * full_screen_texture_size_in_bytes
, kDefaultMaxTransferBufferSize
);
459 limits
.mapped_memory_reclaim_limit
= 2 * 1024 * 1024;
460 bool lose_context_when_out_of_memory
= true;
461 return make_scoped_ptr(
462 new WebGraphicsContext3DCommandBufferImpl(surface_id
,
464 gpu_channel_host
.get(),
466 lose_context_when_out_of_memory
,
471 scoped_ptr
<cc::OutputSurface
> CompositorImpl::CreateOutputSurface(
473 blink::WebGraphicsContext3D::Attributes attrs
;
474 attrs
.shareResources
= true;
475 attrs
.noAutomaticFlushes
= true;
480 scoped_refptr
<ContextProviderCommandBuffer
> context_provider
=
481 ContextProviderCommandBuffer::Create(
482 CreateGpuProcessViewContext(attrs
, surface_id_
), "BrowserCompositor");
483 if (!context_provider
.get()) {
484 LOG(ERROR
) << "Failed to create 3D context for compositor.";
485 return scoped_ptr
<cc::OutputSurface
>();
488 return scoped_ptr
<cc::OutputSurface
>(
489 new OutputSurfaceWithoutParent(context_provider
));
492 void CompositorImpl::OnLostResources() {
493 client_
->DidLoseResources();
496 void CompositorImpl::DidCompleteSwapBuffers() {
497 client_
->OnSwapBuffersCompleted();
500 void CompositorImpl::ScheduleComposite() {
501 client_
->ScheduleComposite();
504 void CompositorImpl::ScheduleAnimation() {
508 void CompositorImpl::DidPostSwapBuffers() {
509 TRACE_EVENT0("compositor", "CompositorImpl::DidPostSwapBuffers");
510 client_
->OnSwapBuffersPosted();
513 void CompositorImpl::DidAbortSwapBuffers() {
514 TRACE_EVENT0("compositor", "CompositorImpl::DidAbortSwapBuffers");
515 client_
->OnSwapBuffersCompleted();
518 void CompositorImpl::DidCommit() {
519 root_window_
->OnCompositingDidCommit();
522 void CompositorImpl::AttachLayerForReadback(scoped_refptr
<cc::Layer
> layer
) {
523 root_layer_
->AddChild(layer
);
526 } // namespace content