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