1 // Copyright (c) 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ui/gl/gl_surface_egl_x11_gles2.h"
6 
7 #include "ui/base/x/x11_util.h"
8 #include "ui/gfx/x/xproto.h"
9 #include "ui/gfx/x/xproto_util.h"
10 #include "ui/gl/egl_util.h"
11 
12 using ui::GetLastEGLErrorString;
13 using ui::X11EventSource;
14 
15 namespace gl {
16 
NativeViewGLSurfaceEGLX11GLES2(x11::Window window)17 NativeViewGLSurfaceEGLX11GLES2::NativeViewGLSurfaceEGLX11GLES2(
18     x11::Window window)
19     : NativeViewGLSurfaceEGLX11(x11::Window::None), parent_window_(window) {}
20 
InitializeNativeWindow()21 bool NativeViewGLSurfaceEGLX11GLES2::InitializeNativeWindow() {
22   auto* connection = GetXNativeConnection();
23   auto geometry = connection->GetGeometry({parent_window_}).Sync();
24   if (!geometry) {
25     LOG(ERROR) << "GetGeometry failed for window "
26                << static_cast<uint32_t>(parent_window_) << ".";
27     return false;
28   }
29 
30   size_ = gfx::Size(geometry->width, geometry->height);
31 
32   // Create a child window, with a CopyFromParent visual (to avoid inducing
33   // extra blits in the driver), that we can resize exactly in Resize(),
34   // correctly ordered with GL, so that we don't have invalid transient states.
35   // See https://crbug.com/326995.
36   set_window(connection->GenerateId<x11::Window>());
37   connection->CreateWindow(x11::CreateWindowRequest{
38       .wid = window(),
39       .parent = parent_window_,
40       .width = size_.width(),
41       .height = size_.height(),
42       .c_class = x11::WindowClass::InputOutput,
43       .background_pixmap = x11::Pixmap::None,
44       .bit_gravity = x11::Gravity::NorthWest,
45       .event_mask = x11::EventMask::Exposure,
46   });
47   connection->MapWindow({window()});
48   connection->Flush();
49 
50   return true;
51 }
52 
Destroy()53 void NativeViewGLSurfaceEGLX11GLES2::Destroy() {
54   NativeViewGLSurfaceEGLX11::Destroy();
55 
56   if (window_) {
57     auto* connection = GetXNativeConnection();
58     connection->DestroyWindow({window()});
59     window_ = 0;
60     connection->Flush();
61   }
62 }
63 
GetConfig()64 EGLConfig NativeViewGLSurfaceEGLX11GLES2::GetConfig() {
65   if (!config_) {
66     // Get a config compatible with the window
67     DCHECK(window_);
68     auto* connection = GetXNativeConnection();
69     auto geometry = connection->GetGeometry({window()}).Sync();
70     if (!geometry)
71       return nullptr;
72 
73     // Try matching the window depth with an alpha channel,
74     // because we're worried the destination alpha width could
75     // constrain blending precision.
76     const int kBufferSizeOffset = 1;
77     const int kAlphaSizeOffset = 3;
78     EGLint config_attribs[] = {EGL_BUFFER_SIZE,
79                                ~0,
80                                EGL_ALPHA_SIZE,
81                                8,
82                                EGL_BLUE_SIZE,
83                                8,
84                                EGL_GREEN_SIZE,
85                                8,
86                                EGL_RED_SIZE,
87                                8,
88                                EGL_RENDERABLE_TYPE,
89                                EGL_OPENGL_ES2_BIT,
90                                EGL_SURFACE_TYPE,
91                                EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
92                                EGL_NONE};
93     config_attribs[kBufferSizeOffset] = geometry->depth;
94 
95     EGLDisplay display = GetHardwareDisplay();
96     EGLint num_configs;
97     if (!eglChooseConfig(display, config_attribs, &config_, 1, &num_configs)) {
98       LOG(ERROR) << "eglChooseConfig failed with error "
99                  << GetLastEGLErrorString();
100       return nullptr;
101     }
102 
103     if (num_configs) {
104       EGLint config_depth;
105       if (!eglGetConfigAttrib(display, config_, EGL_BUFFER_SIZE,
106                               &config_depth)) {
107         LOG(ERROR) << "eglGetConfigAttrib failed with error "
108                    << GetLastEGLErrorString();
109         return nullptr;
110       }
111 
112       if (config_depth == geometry->depth) {
113         return config_;
114       }
115     }
116 
117     // Try without an alpha channel.
118     config_attribs[kAlphaSizeOffset] = 0;
119     if (!eglChooseConfig(display, config_attribs, &config_, 1, &num_configs)) {
120       LOG(ERROR) << "eglChooseConfig failed with error "
121                  << GetLastEGLErrorString();
122       return nullptr;
123     }
124 
125     if (num_configs == 0) {
126       LOG(ERROR) << "No suitable EGL configs found.";
127       return nullptr;
128     }
129   }
130   return config_;
131 }
132 
Resize(const gfx::Size & size,float scale_factor,const gfx::ColorSpace & color_space,bool has_alpha)133 bool NativeViewGLSurfaceEGLX11GLES2::Resize(const gfx::Size& size,
134                                             float scale_factor,
135                                             const gfx::ColorSpace& color_space,
136                                             bool has_alpha) {
137   if (size == GetSize())
138     return true;
139 
140   size_ = size;
141 
142   eglWaitGL();
143   auto* connection = GetXNativeConnection();
144   connection->ConfigureWindow({
145       .window = window(),
146       .width = size.width(),
147       .height = size.height(),
148   });
149   connection->Flush();
150   eglWaitNative(EGL_CORE_NATIVE_ENGINE);
151 
152   return true;
153 }
154 
DispatchXEvent(x11::Event * x11_event)155 bool NativeViewGLSurfaceEGLX11GLES2::DispatchXEvent(x11::Event* x11_event) {
156   auto* expose = x11_event->As<x11::ExposeEvent>();
157   auto window = static_cast<x11::Window>(window_);
158   if (!expose || expose->window != window)
159     return false;
160 
161   auto expose_copy = *expose;
162   expose_copy.window = parent_window_;
163   x11::SendEvent(expose_copy, parent_window_, x11::EventMask::Exposure);
164   x11::Connection::Get()->Flush();
165   return true;
166 }
167 
~NativeViewGLSurfaceEGLX11GLES2()168 NativeViewGLSurfaceEGLX11GLES2::~NativeViewGLSurfaceEGLX11GLES2() {
169   Destroy();
170 }
171 
172 }  // namespace gl
173