blob: 5f45469d306618a2df29ed37a42309ced6f7e839 [file] [log] [blame]
// 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