| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/common/gpu/image_transport_surface.h" |
| |
| #include "base/command_line.h" |
| #include "base/logging.h" |
| #include "content/common/gpu/gpu_channel.h" |
| #include "content/common/gpu/gpu_channel_manager.h" |
| #include "content/common/gpu/gpu_command_buffer_stub.h" |
| #include "content/common/gpu/gpu_surface_lookup.h" |
| #include "content/common/gpu/image_transport_surface.h" |
| #include "content/public/common/content_switches.h" |
| #include "ui/gl/gl_surface_egl.h" |
| |
| namespace content { |
| namespace { |
| |
| // Amount of time the GPU is allowed to idle before it powers down. |
| const int kMaxGpuIdleTimeMs = 40; |
| // Maximum amount of time we keep pinging the GPU waiting for the client to |
| // draw. |
| const int kMaxKeepAliveTimeMs = 200; |
| // Last time we know the GPU was powered on. Global for tracking across all |
| // transport surfaces. |
| int64 g_last_gpu_access_ticks; |
| |
| void DidAccessGpu() { |
| g_last_gpu_access_ticks = base::TimeTicks::Now().ToInternalValue(); |
| } |
| |
| class ImageTransportSurfaceAndroid |
| : public PassThroughImageTransportSurface, |
| public base::SupportsWeakPtr<ImageTransportSurfaceAndroid> { |
| public: |
| ImageTransportSurfaceAndroid(GpuChannelManager* manager, |
| GpuCommandBufferStub* stub, |
| gfx::GLSurface* surface, |
| uint32 parent_client_id); |
| |
| // gfx::GLSurface implementation. |
| virtual bool Initialize() OVERRIDE; |
| virtual bool SwapBuffers() OVERRIDE; |
| virtual std::string GetExtensions() OVERRIDE; |
| virtual bool OnMakeCurrent(gfx::GLContext* context) OVERRIDE; |
| virtual void SetFrontbufferAllocation(bool allocated) OVERRIDE; |
| virtual void WakeUpGpu() OVERRIDE; |
| |
| protected: |
| virtual ~ImageTransportSurfaceAndroid(); |
| |
| private: |
| void ScheduleWakeUp(); |
| void DoWakeUpGpu(); |
| |
| uint32 parent_client_id_; |
| bool frontbuffer_suggested_allocation_; |
| base::TimeTicks begin_wake_up_time_; |
| }; |
| |
| class DirectSurfaceAndroid : public PassThroughImageTransportSurface { |
| public: |
| DirectSurfaceAndroid(GpuChannelManager* manager, |
| GpuCommandBufferStub* stub, |
| gfx::GLSurface* surface, |
| bool transport); |
| |
| // gfx::GLSurface implementation. |
| virtual bool SwapBuffers() OVERRIDE; |
| |
| protected: |
| virtual ~DirectSurfaceAndroid(); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(DirectSurfaceAndroid); |
| }; |
| |
| ImageTransportSurfaceAndroid::ImageTransportSurfaceAndroid( |
| GpuChannelManager* manager, |
| GpuCommandBufferStub* stub, |
| gfx::GLSurface* surface, |
| uint32 parent_client_id) |
| : PassThroughImageTransportSurface(manager, stub, surface, true), |
| parent_client_id_(parent_client_id), |
| frontbuffer_suggested_allocation_(true) {} |
| |
| ImageTransportSurfaceAndroid::~ImageTransportSurfaceAndroid() {} |
| |
| bool ImageTransportSurfaceAndroid::Initialize() { |
| if (!surface()) |
| return false; |
| |
| if (!PassThroughImageTransportSurface::Initialize()) |
| return false; |
| |
| GpuChannel* parent_channel = |
| GetHelper()->manager()->LookupChannel(parent_client_id_); |
| if (parent_channel) { |
| const CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| if (command_line->HasSwitch(switches::kUIPrioritizeInGpuProcess)) |
| GetHelper()->SetPreemptByFlag(parent_channel->GetPreemptionFlag()); |
| } |
| |
| return true; |
| } |
| |
| std::string ImageTransportSurfaceAndroid::GetExtensions() { |
| std::string extensions = gfx::GLSurface::GetExtensions(); |
| extensions += extensions.empty() ? "" : " "; |
| extensions += "GL_CHROMIUM_front_buffer_cached "; |
| return extensions; |
| } |
| |
| void ImageTransportSurfaceAndroid::SetFrontbufferAllocation(bool allocation) { |
| if (frontbuffer_suggested_allocation_ == allocation) |
| return; |
| frontbuffer_suggested_allocation_ = allocation; |
| // TODO(sievers): This races with CompositorFrame messages. |
| if (!allocation) |
| GetHelper()->SendAcceleratedSurfaceRelease(); |
| } |
| |
| bool ImageTransportSurfaceAndroid::OnMakeCurrent(gfx::GLContext* context) { |
| DidAccessGpu(); |
| return PassThroughImageTransportSurface::OnMakeCurrent(context); |
| } |
| |
| bool ImageTransportSurfaceAndroid::SwapBuffers() { |
| NOTREACHED(); |
| return false; |
| } |
| |
| void ImageTransportSurfaceAndroid::WakeUpGpu() { |
| begin_wake_up_time_ = base::TimeTicks::Now(); |
| ScheduleWakeUp(); |
| } |
| |
| void ImageTransportSurfaceAndroid::ScheduleWakeUp() { |
| base::TimeTicks now = base::TimeTicks::Now(); |
| base::TimeTicks last_access_time = |
| base::TimeTicks::FromInternalValue(g_last_gpu_access_ticks); |
| TRACE_EVENT2("gpu", "ImageTransportSurfaceAndroid::ScheduleWakeUp", |
| "idle_time", (now - last_access_time).InMilliseconds(), |
| "keep_awake_time", (now - begin_wake_up_time_).InMilliseconds()); |
| if (now - last_access_time < |
| base::TimeDelta::FromMilliseconds(kMaxGpuIdleTimeMs)) |
| return; |
| if (now - begin_wake_up_time_ > |
| base::TimeDelta::FromMilliseconds(kMaxKeepAliveTimeMs)) |
| return; |
| |
| DoWakeUpGpu(); |
| |
| base::MessageLoop::current()->PostDelayedTask( |
| FROM_HERE, |
| base::Bind(&ImageTransportSurfaceAndroid::ScheduleWakeUp, AsWeakPtr()), |
| base::TimeDelta::FromMilliseconds(kMaxGpuIdleTimeMs)); |
| } |
| |
| void ImageTransportSurfaceAndroid::DoWakeUpGpu() { |
| if (!GetHelper()->stub()->decoder() || |
| !GetHelper()->stub()->decoder()->MakeCurrent()) |
| return; |
| glFinish(); |
| DidAccessGpu(); |
| } |
| |
| DirectSurfaceAndroid::DirectSurfaceAndroid(GpuChannelManager* manager, |
| GpuCommandBufferStub* stub, |
| gfx::GLSurface* surface, |
| bool transport) |
| : PassThroughImageTransportSurface(manager, stub, surface, transport) {} |
| |
| DirectSurfaceAndroid::~DirectSurfaceAndroid() {} |
| |
| bool DirectSurfaceAndroid::SwapBuffers() { |
| DidAccessGpu(); |
| return PassThroughImageTransportSurface::SwapBuffers(); |
| } |
| |
| } // anonymous namespace |
| |
| // static |
| scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface( |
| GpuChannelManager* manager, |
| GpuCommandBufferStub* stub, |
| const gfx::GLSurfaceHandle& handle) { |
| if (handle.transport_type == gfx::NATIVE_TRANSPORT) { |
| return scoped_refptr<gfx::GLSurface>( |
| new ImageTransportSurfaceAndroid(manager, |
| stub, |
| manager->GetDefaultOffscreenSurface(), |
| handle.parent_client_id)); |
| } |
| |
| DCHECK(GpuSurfaceLookup::GetInstance()); |
| DCHECK_EQ(handle.transport_type, gfx::NATIVE_DIRECT); |
| ANativeWindow* window = |
| GpuSurfaceLookup::GetInstance()->AcquireNativeWidget( |
| stub->surface_id()); |
| scoped_refptr<gfx::GLSurface> surface = |
| new gfx::NativeViewGLSurfaceEGL(window); |
| bool initialize_success = surface->Initialize(); |
| if (window) |
| ANativeWindow_release(window); |
| if (!initialize_success) |
| return scoped_refptr<gfx::GLSurface>(); |
| |
| return scoped_refptr<gfx::GLSurface>( |
| new DirectSurfaceAndroid(manager, stub, surface.get(), false)); |
| } |
| |
| } // namespace content |