blob: 986dda1dacf4e33c2f438a44fc1926d8fb0265a1 [file] [log] [blame]
// Copyright 2016 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 "ui/ozone/platform/x11/x11_surface_factory.h"
#include <X11/Xlib.h>
#include "third_party/khronos/EGL/egl.h"
#include "ui/gfx/x/x11_types.h"
#include "ui/gl/egl_util.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/ozone/common/egl_util.h"
namespace ui {
namespace {
// GLSurface implementation for Ozone X11 EGL.
class GLSurfaceEGLOzoneX11 : public gl::NativeViewGLSurfaceEGL {
public:
explicit GLSurfaceEGLOzoneX11(EGLNativeWindowType window);
// gl::NativeViewGLSurfaceEGL:
EGLConfig GetConfig() override;
bool Resize(const gfx::Size& size,
float scale_factor,
bool has_alpha) override;
private:
~GLSurfaceEGLOzoneX11() override;
DISALLOW_COPY_AND_ASSIGN(GLSurfaceEGLOzoneX11);
};
GLSurfaceEGLOzoneX11::GLSurfaceEGLOzoneX11(EGLNativeWindowType window)
: NativeViewGLSurfaceEGL(window) {}
EGLConfig GLSurfaceEGLOzoneX11::GetConfig() {
// Try matching the window depth with an alpha channel, because we're worried
// the destination alpha width could constrain blending precision.
const int kBufferSizeOffset = 1;
const int kAlphaSizeOffset = 3;
EGLint config_attribs[] = {EGL_BUFFER_SIZE,
~0, // To be replaced.
EGL_ALPHA_SIZE,
8,
EGL_BLUE_SIZE,
8,
EGL_GREEN_SIZE,
8,
EGL_RED_SIZE,
8,
EGL_RENDERABLE_TYPE,
EGL_OPENGL_ES2_BIT,
EGL_SURFACE_TYPE,
EGL_WINDOW_BIT,
EGL_NONE};
// Get the depth of XWindow for surface.
XWindowAttributes win_attribs;
if (XGetWindowAttributes(gfx::GetXDisplay(), window_, &win_attribs)) {
config_attribs[kBufferSizeOffset] = win_attribs.depth;
}
EGLDisplay display = GetDisplay();
EGLConfig config;
EGLint num_configs;
if (!eglChooseConfig(display, config_attribs, &config, 1, &num_configs)) {
LOG(ERROR) << "eglChooseConfig failed with error "
<< GetLastEGLErrorString();
return nullptr;
}
if (num_configs > 0) {
EGLint config_depth;
if (!eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &config_depth)) {
LOG(ERROR) << "eglGetConfigAttrib failed with error "
<< GetLastEGLErrorString();
return nullptr;
}
if (config_depth == config_attribs[kBufferSizeOffset]) {
return config;
}
}
// Try without an alpha channel.
config_attribs[kAlphaSizeOffset] = 0;
if (!eglChooseConfig(display, config_attribs, &config, 1, &num_configs)) {
LOG(ERROR) << "eglChooseConfig failed with error "
<< GetLastEGLErrorString();
return nullptr;
}
if (num_configs == 0) {
LOG(ERROR) << "No suitable EGL configs found.";
return nullptr;
}
return config;
}
bool GLSurfaceEGLOzoneX11::Resize(const gfx::Size& size,
float scale_factor,
bool has_alpha) {
if (size == GetSize())
return true;
size_ = size;
eglWaitGL();
XResizeWindow(gfx::GetXDisplay(), window_, size.width(), size.height());
eglWaitNative(EGL_CORE_NATIVE_ENGINE);
return true;
}
GLSurfaceEGLOzoneX11::~GLSurfaceEGLOzoneX11() {
Destroy();
}
} // namespace
X11SurfaceFactory::X11SurfaceFactory() {}
X11SurfaceFactory::~X11SurfaceFactory() {}
bool X11SurfaceFactory::UseNewSurfaceAPI() {
return true;
}
scoped_refptr<gl::GLSurface> X11SurfaceFactory::CreateViewGLSurface(
gl::GLImplementation implementation,
gfx::AcceleratedWidget widget) {
if (implementation != gl::kGLImplementationEGLGLES2) {
NOTREACHED();
return nullptr;
}
return gl::InitializeGLSurface(new GLSurfaceEGLOzoneX11(widget));
}
scoped_refptr<gl::GLSurface> X11SurfaceFactory::CreateOffscreenGLSurface(
gl::GLImplementation implementation,
const gfx::Size& size) {
if (implementation != gl::kGLImplementationEGLGLES2) {
NOTREACHED();
return nullptr;
}
return gl::InitializeGLSurface(new gl::PbufferGLSurfaceEGL(size));
}
bool X11SurfaceFactory::LoadEGLGLES2Bindings(
AddGLLibraryCallback add_gl_library,
SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
return LoadDefaultEGLGLES2Bindings(add_gl_library, set_gl_get_proc_address);
}
intptr_t X11SurfaceFactory::GetNativeDisplay() {
return reinterpret_cast<intptr_t>(gfx::GetXDisplay());
}
} // namespace ui