blob: ab0db73c1e1308ab1bb2de674dd91788db9090b3 [file] [log] [blame]
// Copyright (c) 2011 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 "chrome/browser/renderer_host/accelerated_surface_container_touch.h"
#include <X11/Xlib.h>
#include <X11/extensions/Xcomposite.h>
#include "base/memory/scoped_ptr.h"
#include "third_party/angle/include/EGL/egl.h"
#include "third_party/angle/include/EGL/eglext.h"
#include "ui/gfx/gl/gl_bindings.h"
#include "ui/gfx/gl/gl_implementation.h"
#include "ui/gfx/gl/gl_surface_egl.h"
#include "ui/gfx/gl/gl_surface_glx.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/transform.h"
namespace {
class AcceleratedSurfaceContainerTouchEGL
: public AcceleratedSurfaceContainerTouch {
public:
AcceleratedSurfaceContainerTouchEGL(const gfx::Size& size,
uint64 surface_handle);
// TextureGL implementation
virtual void Draw(const ui::TextureDrawParams& params,
const gfx::Rect& clip_bounds_in_texture) OVERRIDE;
private:
~AcceleratedSurfaceContainerTouchEGL();
void* image_;
DISALLOW_COPY_AND_ASSIGN(AcceleratedSurfaceContainerTouchEGL);
};
class AcceleratedSurfaceContainerTouchGLX
: public AcceleratedSurfaceContainerTouch {
public:
AcceleratedSurfaceContainerTouchGLX(const gfx::Size& size,
uint64 surface_handle);
// TextureGL implementation
virtual void Draw(const ui::TextureDrawParams& params,
const gfx::Rect& clip_bounds_in_texture) OVERRIDE;
private:
~AcceleratedSurfaceContainerTouchGLX();
XID pixmap_;
XID glx_pixmap_;
DISALLOW_COPY_AND_ASSIGN(AcceleratedSurfaceContainerTouchGLX);
};
class ScopedPtrXFree {
public:
void operator()(void* x) const {
::XFree(x);
}
};
AcceleratedSurfaceContainerTouchEGL::AcceleratedSurfaceContainerTouchEGL(
const gfx::Size& size,
uint64 surface_handle)
: AcceleratedSurfaceContainerTouch(size),
image_(NULL) {
ui::SharedResources* instance = ui::SharedResources::GetInstance();
DCHECK(instance);
instance->MakeSharedContextCurrent();
image_ = eglCreateImageKHR(
gfx::GLSurfaceEGL::GetHardwareDisplay(), EGL_NO_CONTEXT,
EGL_NATIVE_PIXMAP_KHR, reinterpret_cast<void*>(surface_handle), NULL);
glGenTextures(1, &texture_id_);
glBindTexture(GL_TEXTURE_2D, texture_id_);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image_);
glFlush();
}
AcceleratedSurfaceContainerTouchEGL::~AcceleratedSurfaceContainerTouchEGL() {
ui::SharedResources* instance = ui::SharedResources::GetInstance();
DCHECK(instance);
instance->MakeSharedContextCurrent();
eglDestroyImageKHR(gfx::GLSurfaceEGL::GetHardwareDisplay(), image_);
glFlush();
}
void AcceleratedSurfaceContainerTouchEGL::Draw(
const ui::TextureDrawParams& params,
const gfx::Rect& clip_bounds_in_texture) {
ui::SharedResources* instance = ui::SharedResources::GetInstance();
DCHECK(instance);
ui::TextureDrawParams modified_params = params;
// Texture from GPU is flipped vertically.
ui::Transform flipped;
flipped.SetScaleY(-1.0);
flipped.SetTranslateY(size_.height());
flipped.ConcatTransform(params.transform);
modified_params.transform = flipped;
DrawInternal(*instance->program_no_swizzle(),
modified_params,
clip_bounds_in_texture);
}
AcceleratedSurfaceContainerTouchGLX::AcceleratedSurfaceContainerTouchGLX(
const gfx::Size& size,
uint64 surface_handle)
: AcceleratedSurfaceContainerTouch(size),
pixmap_(0),
glx_pixmap_(0) {
ui::SharedResources* instance = ui::SharedResources::GetInstance();
DCHECK(instance);
instance->MakeSharedContextCurrent();
// Create pixmap from window.
Display* dpy = gfx::GLSurfaceGLX::GetDisplay();
int event_base, error_base;
if (XCompositeQueryExtension(dpy, &event_base, &error_base)) {
int major = 0, minor = 2;
XCompositeQueryVersion(dpy, &major, &minor);
if (major == 0 && minor < 2) {
LOG(ERROR) << "Pixmap from window not supported.";
return;
}
}
pixmap_ = XCompositeNameWindowPixmap(dpy, surface_handle);
// Wrap the pixmap in a GLXPixmap
int screen = DefaultScreen(dpy);
XWindowAttributes gwa;
XGetWindowAttributes(dpy, RootWindow(dpy, screen), &gwa);
unsigned int visualid = XVisualIDFromVisual(gwa.visual);
int nfbconfigs, config;
scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> fbconfigs(
glXGetFBConfigs(dpy, screen, &nfbconfigs));
for (config = 0; config < nfbconfigs; config++) {
XVisualInfo* visinfo = glXGetVisualFromFBConfig(
dpy, fbconfigs.get()[config]);
if (!visinfo || visinfo->visualid != visualid)
continue;
int value;
glXGetFBConfigAttrib(dpy,
fbconfigs.get()[config],
GLX_DRAWABLE_TYPE,
&value);
if (!(value & GLX_PIXMAP_BIT))
continue;
glXGetFBConfigAttrib(dpy,
fbconfigs.get()[config],
GLX_BIND_TO_TEXTURE_TARGETS_EXT,
&value);
if (!(value & GLX_TEXTURE_2D_BIT_EXT))
continue;
glXGetFBConfigAttrib(dpy,
fbconfigs.get()[config],
GLX_BIND_TO_TEXTURE_RGB_EXT,
&value);
if (value == GL_FALSE)
continue;
break;
}
if (config == nfbconfigs) {
LOG(ERROR)
<< "Could not find configuration suitable for binding a pixmap "
<< "as a texture.";
return;
}
const int pixmapAttribs[] = {
GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT,
0
};
glx_pixmap_ = glXCreatePixmap(
dpy, fbconfigs.get()[config], pixmap_, pixmapAttribs);
// Create texture.
glGenTextures(1, &texture_id_);
glBindTexture(GL_TEXTURE_2D, texture_id_);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
AcceleratedSurfaceContainerTouchGLX::~AcceleratedSurfaceContainerTouchGLX() {
ui::SharedResources* instance = ui::SharedResources::GetInstance();
DCHECK(instance);
instance->MakeSharedContextCurrent();
Display* dpy = gfx::GLSurfaceGLX::GetDisplay();
if (glx_pixmap_)
glXDestroyGLXPixmap(dpy, glx_pixmap_);
if (pixmap_)
XFreePixmap(dpy, pixmap_);
}
void AcceleratedSurfaceContainerTouchGLX::Draw(
const ui::TextureDrawParams& params,
const gfx::Rect& clip_bounds_in_texture) {
ui::SharedResources* instance = ui::SharedResources::GetInstance();
DCHECK(instance);
Display* dpy = gfx::GLSurfaceGLX::GetDisplay();
glBindTexture(GL_TEXTURE_2D, texture_id_);
glXBindTexImageEXT(dpy, glx_pixmap_, GLX_FRONT_LEFT_EXT, NULL);
DrawInternal(*instance->program_no_swizzle(),
params,
clip_bounds_in_texture);
glXReleaseTexImageEXT(dpy, glx_pixmap_, GLX_FRONT_LEFT_EXT);
}
} // namespace
AcceleratedSurfaceContainerTouch::AcceleratedSurfaceContainerTouch(
const gfx::Size& size) : TextureGL(size) {
}
// static
AcceleratedSurfaceContainerTouch*
AcceleratedSurfaceContainerTouch::CreateAcceleratedSurfaceContainer(
const gfx::Size& size,
uint64 surface_handle) {
switch (gfx::GetGLImplementation()) {
case gfx::kGLImplementationDesktopGL:
return new AcceleratedSurfaceContainerTouchGLX(size,
surface_handle);
case gfx::kGLImplementationEGLGLES2:
return new AcceleratedSurfaceContainerTouchEGL(size,
surface_handle);
default:
NOTREACHED();
return NULL;
}
}
void AcceleratedSurfaceContainerTouch::SetCanvas(
const SkCanvas& canvas,
const gfx::Point& origin,
const gfx::Size& overall_size) {
NOTREACHED();
}