| // 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 |