// 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/gpu/gpu_surface_tracker.h"
#if defined(OS_ANDROID)
#include <android/native_window_jni.h>
#endif // defined(OS_ANDROID)
#include "base/logging.h"
#if defined(TOOLKIT_GTK)
#include "base/bind.h"
#include "content/public/browser/browser_thread.h"
#include "ui/gfx/gtk_native_view_id_manager.h"
#endif // defined(TOOLKIT_GTK)
namespace content {
namespace {
#if defined(TOOLKIT_GTK)
void ReleasePermanentXIDDispatcher(
const gfx::PluginWindowHandle& surface) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
GtkNativeViewManager* manager = GtkNativeViewManager::GetInstance();
manager->ReleasePermanentXID(surface);
}
// Implementation of SurfaceRef that allows GTK to ref and unref the
// surface with the GtkNativeViewManager.
class SurfaceRefPluginWindow : public GpuSurfaceTracker::SurfaceRef {
public:
SurfaceRefPluginWindow(const gfx::PluginWindowHandle& surface_ref);
private:
virtual ~SurfaceRefPluginWindow();
gfx::PluginWindowHandle surface_;
};
SurfaceRefPluginWindow::SurfaceRefPluginWindow(
const gfx::PluginWindowHandle& surface)
: surface_(surface) {
if (surface_ != gfx::kNullPluginWindow) {
GtkNativeViewManager* manager = GtkNativeViewManager::GetInstance();
if (!manager->AddRefPermanentXID(surface_)) {
LOG(ERROR) << "Surface " << surface << " cannot be referenced.";
}
}
}
SurfaceRefPluginWindow::~SurfaceRefPluginWindow() {
if (surface_ != gfx::kNullPluginWindow) {
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
base::Bind(&ReleasePermanentXIDDispatcher,
surface_));
}
}
#endif // defined(TOOLKIT_GTK)
} // anonymous
GpuSurfaceTracker::GpuSurfaceTracker()
: next_surface_id_(1) {
GpuSurfaceLookup::InitInstance(this);
}
GpuSurfaceTracker::~GpuSurfaceTracker() {
GpuSurfaceLookup::InitInstance(NULL);
}
GpuSurfaceTracker* GpuSurfaceTracker::GetInstance() {
return Singleton<GpuSurfaceTracker>::get();
}
int GpuSurfaceTracker::AddSurfaceForRenderer(int renderer_id,
int render_widget_id) {
base::AutoLock lock(lock_);
int surface_id = next_surface_id_++;
surface_map_[surface_id] =
SurfaceInfo(renderer_id, render_widget_id, gfx::kNullAcceleratedWidget,
gfx::GLSurfaceHandle(), NULL);
return surface_id;
}
int GpuSurfaceTracker::LookupSurfaceForRenderer(int renderer_id,
int render_widget_id) {
base::AutoLock lock(lock_);
for (SurfaceMap::iterator it = surface_map_.begin(); it != surface_map_.end();
++it) {
const SurfaceInfo& info = it->second;
if (info.renderer_id == renderer_id &&
info.render_widget_id == render_widget_id) {
return it->first;
}
}
return 0;
}
int GpuSurfaceTracker::AddSurfaceForNativeWidget(
gfx::AcceleratedWidget widget) {
base::AutoLock lock(lock_);
int surface_id = next_surface_id_++;
surface_map_[surface_id] =
SurfaceInfo(0, 0, widget, gfx::GLSurfaceHandle(), NULL);
return surface_id;
}
void GpuSurfaceTracker::RemoveSurface(int surface_id) {
base::AutoLock lock(lock_);
DCHECK(surface_map_.find(surface_id) != surface_map_.end());
surface_map_.erase(surface_id);
}
bool GpuSurfaceTracker::GetRenderWidgetIDForSurface(int surface_id,
int* renderer_id,
int* render_widget_id) {
base::AutoLock lock(lock_);
SurfaceMap::iterator it = surface_map_.find(surface_id);
if (it == surface_map_.end())
return false;
const SurfaceInfo& info = it->second;
if (!info.handle.is_transport())
return false;
*renderer_id = info.renderer_id;
*render_widget_id = info.render_widget_id;
return true;
}
void GpuSurfaceTracker::SetSurfaceHandle(int surface_id,
const gfx::GLSurfaceHandle& handle) {
base::AutoLock lock(lock_);
DCHECK(surface_map_.find(surface_id) != surface_map_.end());
SurfaceInfo& info = surface_map_[surface_id];
info.handle = handle;
#if defined(TOOLKIT_GTK)
info.surface_ref = new SurfaceRefPluginWindow(handle.handle);
#endif // defined(TOOLKIT_GTK)
}
gfx::GLSurfaceHandle GpuSurfaceTracker::GetSurfaceHandle(int surface_id) {
base::AutoLock lock(lock_);
SurfaceMap::iterator it = surface_map_.find(surface_id);
if (it == surface_map_.end())
return gfx::GLSurfaceHandle();
return it->second.handle;
}
gfx::AcceleratedWidget GpuSurfaceTracker::AcquireNativeWidget(int surface_id) {
base::AutoLock lock(lock_);
SurfaceMap::iterator it = surface_map_.find(surface_id);
if (it == surface_map_.end())
return gfx::kNullAcceleratedWidget;
#if defined(OS_ANDROID)
if (it->second.native_widget != gfx::kNullAcceleratedWidget)
ANativeWindow_acquire(it->second.native_widget);
#endif // defined(OS_ANDROID)
return it->second.native_widget;
}
void GpuSurfaceTracker::SetNativeWidget(
int surface_id, gfx::AcceleratedWidget widget,
SurfaceRef* surface_ref) {
base::AutoLock lock(lock_);
SurfaceMap::iterator it = surface_map_.find(surface_id);
DCHECK(it != surface_map_.end());
SurfaceInfo& info = it->second;
info.native_widget = widget;
info.surface_ref = surface_ref;
}
std::size_t GpuSurfaceTracker::GetSurfaceCount() {
base::AutoLock lock(lock_);
return surface_map_.size();
}
GpuSurfaceTracker::SurfaceInfo::SurfaceInfo()
: renderer_id(0),
render_widget_id(0),
native_widget(gfx::kNullAcceleratedWidget) { }
GpuSurfaceTracker::SurfaceInfo::SurfaceInfo(
int renderer_id,
int render_widget_id,
const gfx::AcceleratedWidget& native_widget,
const gfx::GLSurfaceHandle& handle,
const scoped_refptr<SurfaceRef>& surface_ref)
: renderer_id(renderer_id),
render_widget_id(render_widget_id),
native_widget(native_widget),
handle(handle),
surface_ref(surface_ref) { }
GpuSurfaceTracker::SurfaceInfo::~SurfaceInfo() { }
} // namespace content