// 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.h" #include "ui/events/platform/platform_event_source.h" #include "ui/gl/egl_util.h" extern "C" { #include } using ui::GetLastEGLErrorString; using ui::PlatformEvent; using ui::PlatformEventSource; namespace gfx { NativeViewGLSurfaceEGLX11::NativeViewGLSurfaceEGLX11(EGLNativeWindowType window) : NativeViewGLSurfaceEGL(0), parent_window_(window) { } bool NativeViewGLSurfaceEGLX11::InitializeNativeWindow() { Display* x11_display = GetNativeDisplay(); XWindowAttributes attributes; if (!XGetWindowAttributes(x11_display, parent_window_, &attributes)) { LOG(ERROR) << "XGetWindowAttributes failed for window " << parent_window_ << "."; return false; } size_ = gfx::Size(attributes.width, attributes.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. XSetWindowAttributes swa; memset(&swa, 0, sizeof(swa)); swa.background_pixmap = 0; swa.bit_gravity = NorthWestGravity; window_ = XCreateWindow(x11_display, parent_window_, 0, 0, size_.width(), size_.height(), 0, CopyFromParent, InputOutput, CopyFromParent, CWBackPixmap | CWBitGravity, &swa); XMapWindow(x11_display, window_); // The event source can be nullptr in tests, when we don't care about Exposes. if (PlatformEventSource* source = PlatformEventSource::GetInstance()) { XSelectInput(x11_display, window_, ExposureMask); source->AddPlatformEventDispatcher(this); } XFlush(x11_display); return true; } void NativeViewGLSurfaceEGLX11::Destroy() { if (window_) { if (PlatformEventSource* source = PlatformEventSource::GetInstance()) source->RemovePlatformEventDispatcher(this); Display* x11_display = GetNativeDisplay(); XDestroyWindow(x11_display, window_); window_ = 0; XFlush(x11_display); } NativeViewGLSurfaceEGL::Destroy(); } EGLConfig NativeViewGLSurfaceEGLX11::GetConfig() { if (!config_) { // Get a config compatible with the window DCHECK(window_); XWindowAttributes win_attribs; if (!XGetWindowAttributes(GetNativeDisplay(), window_, &win_attribs)) { return NULL; } // 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] = win_attribs.depth; EGLDisplay display = GetHardwareDisplay(); EGLint num_configs; if (!eglChooseConfig(display, config_attribs, &config_, 1, &num_configs)) { LOG(ERROR) << "eglChooseConfig failed with error " << GetLastEGLErrorString(); return NULL; } if (num_configs) { EGLint config_depth; if (!eglGetConfigAttrib(display, config_, EGL_BUFFER_SIZE, &config_depth)) { LOG(ERROR) << "eglGetConfigAttrib failed with error " << GetLastEGLErrorString(); return NULL; } if (config_depth == win_attribs.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 NULL; } if (num_configs == 0) { LOG(ERROR) << "No suitable EGL configs found."; return NULL; } } return config_; } bool NativeViewGLSurfaceEGLX11::Resize(const gfx::Size& size, float scale_factor, bool has_alpha) { if (size == GetSize()) return true; size_ = size; eglWaitGL(); XResizeWindow(GetNativeDisplay(), window_, size.width(), size.height()); eglWaitNative(EGL_CORE_NATIVE_ENGINE); return true; } bool NativeViewGLSurfaceEGLX11::CanDispatchEvent(const PlatformEvent& event) { return event->type == Expose && event->xexpose.window == window_; } uint32_t NativeViewGLSurfaceEGLX11::DispatchEvent(const PlatformEvent& event) { XEvent x_event = *event; x_event.xexpose.window = parent_window_; Display* x11_display = GetNativeDisplay(); XSendEvent(x11_display, parent_window_, False, ExposureMask, &x_event); XFlush(x11_display); return ui::POST_DISPATCH_STOP_PROPAGATION; } NativeViewGLSurfaceEGLX11::~NativeViewGLSurfaceEGLX11() { Destroy(); } } // namespace gfx