blob: 0d02906a3fd43624a772591fb5930e058f8489e0 [file] [log] [blame]
// Copyright (c) 2015 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/gl/gl_surface_egl_x11_gles2.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/x/xproto.h"
#include "ui/gfx/x/xproto_util.h"
#include "ui/gl/egl_util.h"
using ui::GetLastEGLErrorString;
using ui::X11EventSource;
namespace gl {
NativeViewGLSurfaceEGLX11GLES2::NativeViewGLSurfaceEGLX11GLES2(
x11::Window window)
: NativeViewGLSurfaceEGLX11(x11::Window::None), parent_window_(window) {}
bool NativeViewGLSurfaceEGLX11GLES2::InitializeNativeWindow() {
auto* connection = GetXNativeConnection();
auto geometry = connection->GetGeometry({parent_window_}).Sync();
if (!geometry) {
LOG(ERROR) << "GetGeometry failed for window "
<< static_cast<uint32_t>(parent_window_) << ".";
return false;
}
size_ = gfx::Size(geometry->width, geometry->height);
// Create a child window, with a CopyFromParent visual (to avoid inducing
// extra blits in the driver), that we can resize exactly in Resize(),
// correctly ordered with GL, so that we don't have invalid transient states.
// See https://crbug.com/326995.
set_window(connection->GenerateId<x11::Window>());
connection->CreateWindow(x11::CreateWindowRequest{
.wid = window(),
.parent = parent_window_,
.width = size_.width(),
.height = size_.height(),
.c_class = x11::WindowClass::InputOutput,
.background_pixmap = x11::Pixmap::None,
.bit_gravity = x11::Gravity::NorthWest,
.event_mask = x11::EventMask::Exposure,
});
connection->MapWindow({window()});
connection->Flush();
return true;
}
void NativeViewGLSurfaceEGLX11GLES2::Destroy() {
NativeViewGLSurfaceEGLX11::Destroy();
if (window_) {
auto* connection = GetXNativeConnection();
connection->DestroyWindow({window()});
window_ = 0;
connection->Flush();
}
}
EGLConfig NativeViewGLSurfaceEGLX11GLES2::GetConfig() {
if (!config_) {
// Get a config compatible with the window
DCHECK(window_);
auto* connection = GetXNativeConnection();
auto geometry = connection->GetGeometry({window()}).Sync();
if (!geometry)
return nullptr;
// 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,
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_PBUFFER_BIT,
EGL_NONE};
config_attribs[kBufferSizeOffset] = geometry->depth;
EGLDisplay display = GetHardwareDisplay();
EGLint num_configs;
if (!eglChooseConfig(display, config_attribs, &config_, 1, &num_configs)) {
LOG(ERROR) << "eglChooseConfig failed with error "
<< GetLastEGLErrorString();
return nullptr;
}
if (num_configs) {
EGLint config_depth;
if (!eglGetConfigAttrib(display, config_, EGL_BUFFER_SIZE,
&config_depth)) {
LOG(ERROR) << "eglGetConfigAttrib failed with error "
<< GetLastEGLErrorString();
return nullptr;
}
if (config_depth == geometry->depth) {
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 NativeViewGLSurfaceEGLX11GLES2::Resize(const gfx::Size& size,
float scale_factor,
const gfx::ColorSpace& color_space,
bool has_alpha) {
if (size == GetSize())
return true;
size_ = size;
eglWaitGL();
auto* connection = GetXNativeConnection();
connection->ConfigureWindow({
.window = window(),
.width = size.width(),
.height = size.height(),
});
connection->Flush();
eglWaitNative(EGL_CORE_NATIVE_ENGINE);
return true;
}
bool NativeViewGLSurfaceEGLX11GLES2::DispatchXEvent(x11::Event* x11_event) {
auto* expose = x11_event->As<x11::ExposeEvent>();
auto window = static_cast<x11::Window>(window_);
if (!expose || expose->window != window)
return false;
auto expose_copy = *expose;
expose_copy.window = parent_window_;
x11::SendEvent(expose_copy, parent_window_, x11::EventMask::Exposure);
x11::Connection::Get()->Flush();
return true;
}
NativeViewGLSurfaceEGLX11GLES2::~NativeViewGLSurfaceEGLX11GLES2() {
Destroy();
}
} // namespace gl