blob: bc0d365d2491af6449dc0f386b6af209145d4637 [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/browser/renderer_host/image_transport_factory_android.h"
#include "base/lazy_instance.h"
#include "base/memory/singleton.h"
#include "base/strings/stringprintf.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "content/browser/renderer_host/compositor_impl_android.h"
#include "content/common/gpu/client/gl_helper.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/common/gpu/gpu_process_launch_causes.h"
#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "ui/gfx/android/device_display_info.h"
#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
namespace content {
base::LazyInstance<ObserverList<ImageTransportFactoryAndroidObserver> >::Leaky
g_factory_observers = LAZY_INSTANCE_INITIALIZER;
class GLContextLostListener
: public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback {
public:
// WebGraphicsContextLostCallback implementation.
virtual void onContextLost() OVERRIDE;
private:
static void DidLoseContext();
};
namespace {
using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
static ImageTransportFactoryAndroid* g_factory = NULL;
class DirectGLImageTransportFactory : public ImageTransportFactoryAndroid {
public:
DirectGLImageTransportFactory();
virtual ~DirectGLImageTransportFactory();
virtual uint32_t InsertSyncPoint() OVERRIDE { return 0; }
virtual void WaitSyncPoint(uint32_t sync_point) OVERRIDE {}
virtual uint32_t CreateTexture() OVERRIDE {
return context_->createTexture();
}
virtual void DeleteTexture(uint32_t id) OVERRIDE {
context_->deleteTexture(id);
}
virtual void AcquireTexture(
uint32 texture_id, const signed char* mailbox_name) OVERRIDE {}
virtual WebKit::WebGraphicsContext3D* GetContext3D() OVERRIDE {
return context_.get();
}
virtual GLHelper* GetGLHelper() OVERRIDE { return NULL; }
private:
scoped_ptr<WebKit::WebGraphicsContext3D> context_;
DISALLOW_COPY_AND_ASSIGN(DirectGLImageTransportFactory);
};
DirectGLImageTransportFactory::DirectGLImageTransportFactory() {
WebKit::WebGraphicsContext3D::Attributes attrs;
attrs.shareResources = true;
attrs.noAutomaticFlushes = true;
context_ = webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl::
CreateViewContext(attrs, NULL);
context_->setContextLostCallback(context_lost_listener_.get());
if (context_->makeContextCurrent())
context_->pushGroupMarkerEXT(
base::StringPrintf("DirectGLImageTransportFactory-%p",
context_.get()).c_str());
}
DirectGLImageTransportFactory::~DirectGLImageTransportFactory() {
context_->setContextLostCallback(NULL);
}
class CmdBufferImageTransportFactory : public ImageTransportFactoryAndroid {
public:
CmdBufferImageTransportFactory();
virtual ~CmdBufferImageTransportFactory();
virtual uint32_t InsertSyncPoint() OVERRIDE;
virtual void WaitSyncPoint(uint32_t sync_point) OVERRIDE;
virtual uint32_t CreateTexture() OVERRIDE;
virtual void DeleteTexture(uint32_t id) OVERRIDE;
virtual void AcquireTexture(
uint32 texture_id, const signed char* mailbox_name) OVERRIDE;
virtual WebKit::WebGraphicsContext3D* GetContext3D() OVERRIDE {
return context_.get();
}
virtual GLHelper* GetGLHelper() OVERRIDE;
private:
scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context_;
scoped_ptr<GLHelper> gl_helper_;
DISALLOW_COPY_AND_ASSIGN(CmdBufferImageTransportFactory);
};
CmdBufferImageTransportFactory::CmdBufferImageTransportFactory() {
WebKit::WebGraphicsContext3D::Attributes attrs;
attrs.shareResources = true;
GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
GURL url("chrome://gpu/ImageTransportFactoryAndroid");
base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client;
context_.reset(new WebGraphicsContext3DCommandBufferImpl(0, // offscreen
url,
factory,
swap_client));
static const size_t kBytesPerPixel = 4;
gfx::DeviceDisplayInfo display_info;
size_t full_screen_texture_size_in_bytes =
display_info.GetDisplayHeight() *
display_info.GetDisplayWidth() *
kBytesPerPixel;
context_->setContextLostCallback(context_lost_listener_.get());
context_->Initialize(
attrs,
false,
CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
64 * 1024, // command buffer size
64 * 1024, // starting buffer size
64 * 1024, // min buffer size
std::min(3 * full_screen_texture_size_in_bytes,
kDefaultMaxTransferBufferSize),
WebGraphicsContext3DCommandBufferImpl::kNoLimit
);
if (context_->makeContextCurrent())
context_->pushGroupMarkerEXT(
base::StringPrintf("CmdBufferImageTransportFactory-%p",
context_.get()).c_str());
}
CmdBufferImageTransportFactory::~CmdBufferImageTransportFactory() {
context_->setContextLostCallback(NULL);
}
uint32_t CmdBufferImageTransportFactory::InsertSyncPoint() {
if (!context_->makeContextCurrent()) {
LOG(ERROR) << "Failed to make helper context current.";
return 0;
}
return context_->insertSyncPoint();
}
void CmdBufferImageTransportFactory::WaitSyncPoint(uint32_t sync_point) {
if (!context_->makeContextCurrent()) {
LOG(ERROR) << "Failed to make helper context current.";
return;
}
context_->waitSyncPoint(sync_point);
}
uint32_t CmdBufferImageTransportFactory::CreateTexture() {
if (!context_->makeContextCurrent()) {
LOG(ERROR) << "Failed to make helper context current.";
return false;
}
return context_->createTexture();
}
void CmdBufferImageTransportFactory::DeleteTexture(uint32_t id) {
if (!context_->makeContextCurrent()) {
LOG(ERROR) << "Failed to make helper context current.";
return;
}
context_->deleteTexture(id);
}
void CmdBufferImageTransportFactory::AcquireTexture(
uint32 texture_id, const signed char* mailbox_name) {
if (!context_->makeContextCurrent()) {
LOG(ERROR) << "Failed to make helper context current.";
return;
}
context_->bindTexture(GL_TEXTURE_2D, texture_id);
context_->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox_name);
context_->flush();
}
GLHelper* CmdBufferImageTransportFactory::GetGLHelper() {
if (!gl_helper_)
gl_helper_.reset(new GLHelper(context_.get()));
return gl_helper_.get();
}
} // anonymous namespace
// static
ImageTransportFactoryAndroid* ImageTransportFactoryAndroid::GetInstance() {
if (!g_factory) {
if (CompositorImpl::UsesDirectGL())
g_factory = new DirectGLImageTransportFactory();
else
g_factory = new CmdBufferImageTransportFactory();
}
return g_factory;
}
ImageTransportFactoryAndroid::ImageTransportFactoryAndroid()
: context_lost_listener_(new GLContextLostListener()) {}
ImageTransportFactoryAndroid::~ImageTransportFactoryAndroid() {}
void ImageTransportFactoryAndroid::AddObserver(
ImageTransportFactoryAndroidObserver* observer) {
g_factory_observers.Get().AddObserver(observer);
}
void ImageTransportFactoryAndroid::RemoveObserver(
ImageTransportFactoryAndroidObserver* observer) {
g_factory_observers.Get().RemoveObserver(observer);
}
void GLContextLostListener::onContextLost() {
// Need to post a task because the command buffer client cannot be deleted
// from within this callback.
LOG(ERROR) << "Context lost.";
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&GLContextLostListener::DidLoseContext));
}
void GLContextLostListener::DidLoseContext() {
delete g_factory;
g_factory = NULL;
FOR_EACH_OBSERVER(ImageTransportFactoryAndroidObserver,
g_factory_observers.Get(),
OnLostResources());
}
} // namespace content