• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // WindowSurfaceGLX.cpp: GLX implementation of egl::Surface for windows
8 
9 #include "libANGLE/renderer/gl/glx/WindowSurfaceGLX.h"
10 
11 #include "common/debug.h"
12 
13 #include "libANGLE/renderer/gl/glx/DisplayGLX.h"
14 #include "libANGLE/renderer/gl/glx/FunctionsGLX.h"
15 
16 namespace rx
17 {
18 
IgnoreX11Errors(Display *,XErrorEvent *)19 static int IgnoreX11Errors(Display *, XErrorEvent *)
20 {
21     return 0;
22 }
23 
WindowSurfaceGLX(const egl::SurfaceState & state,const FunctionsGLX & glx,DisplayGLX * glxDisplay,Window window,Display * display,glx::FBConfig fbConfig)24 WindowSurfaceGLX::WindowSurfaceGLX(const egl::SurfaceState &state,
25                                    const FunctionsGLX &glx,
26                                    DisplayGLX *glxDisplay,
27                                    Window window,
28                                    Display *display,
29                                    glx::FBConfig fbConfig)
30     : SurfaceGLX(state),
31       mParent(window),
32       mWindow(0),
33       mDisplay(display),
34       mGLX(glx),
35       mGLXDisplay(glxDisplay),
36       mFBConfig(fbConfig),
37       mGLXWindow(0)
38 {}
39 
~WindowSurfaceGLX()40 WindowSurfaceGLX::~WindowSurfaceGLX()
41 {
42     if (mGLXWindow)
43     {
44         mGLX.destroyWindow(mGLXWindow);
45     }
46 
47     if (mWindow)
48     {
49         // When destroying the window, it may happen that the window has already been
50         // destroyed by the application (this happens in Chromium). There is no way to
51         // atomically check that a window exists and to destroy it so instead we call
52         // XDestroyWindow, ignoring any errors.
53         auto oldErrorHandler = XSetErrorHandler(IgnoreX11Errors);
54         XDestroyWindow(mDisplay, mWindow);
55         XSync(mDisplay, False);
56         XSetErrorHandler(oldErrorHandler);
57     }
58 
59     mGLXDisplay->syncXCommands();
60 }
61 
initialize(const egl::Display * display)62 egl::Error WindowSurfaceGLX::initialize(const egl::Display *display)
63 {
64     // Check that the window's visual ID is valid, as part of the AMGLE_x11_visual
65     // extension.
66     {
67         XWindowAttributes windowAttributes;
68         XGetWindowAttributes(mDisplay, mParent, &windowAttributes);
69         unsigned long visualId = windowAttributes.visual->visualid;
70 
71         if (!mGLXDisplay->isValidWindowVisualId(visualId))
72         {
73             return egl::EglBadMatch() << "The visual of native_window doesn't match the visual "
74                                          "given with ANGLE_X11_VISUAL_ID";
75         }
76     }
77 
78     // The visual of the X window, GLX window and GLX context must match,
79     // however we received a user-created window that can have any visual
80     // and wouldn't work with our GLX context. To work in all cases, we
81     // create a child window with the right visual that covers all of its
82     // parent.
83     XVisualInfo *visualInfo = mGLX.getVisualFromFBConfig(mFBConfig);
84     if (!visualInfo)
85     {
86         return egl::EglBadNativeWindow() << "Failed to get the XVisualInfo for the child window.";
87     }
88     Visual *visual = visualInfo->visual;
89 
90     if (!getWindowDimensions(mParent, &mParentWidth, &mParentHeight))
91     {
92         return egl::EglBadNativeWindow() << "Failed to get the parent window's dimensions.";
93     }
94 
95     // The depth, colormap and visual must match otherwise we get a X error
96     // so we specify the colormap attribute. Also we do not want the window
97     // to be taken into account for input so we specify the event and
98     // do-not-propagate masks to 0 (the defaults). Finally we specify the
99     // border pixel attribute so that we can use a different visual depth
100     // than our parent (seems like X uses that as a condition to render
101     // the subwindow in a different buffer)
102     XSetWindowAttributes attributes;
103     unsigned long attributeMask = CWColormap | CWBorderPixel;
104 
105     Colormap colormap = XCreateColormap(mDisplay, mParent, visual, AllocNone);
106     if (!colormap)
107     {
108         XFree(visualInfo);
109         return egl::EglBadNativeWindow() << "Failed to create the Colormap for the child window.";
110     }
111     attributes.colormap     = colormap;
112     attributes.border_pixel = 0;
113 
114     // TODO(cwallez) set up our own error handler to see if the call failed
115     mWindow    = XCreateWindow(mDisplay, mParent, 0, 0, mParentWidth, mParentHeight, 0,
116                             visualInfo->depth, InputOutput, visual, attributeMask, &attributes);
117     mGLXWindow = mGLX.createWindow(mFBConfig, mWindow, nullptr);
118 
119     XMapWindow(mDisplay, mWindow);
120     XSelectInput(mDisplay, mWindow, ExposureMask);  // For XExposeEvent forwarding from child window
121     XFlush(mDisplay);
122 
123     XFree(visualInfo);
124     XFreeColormap(mDisplay, colormap);
125 
126     mGLXDisplay->syncXCommands();
127 
128     return egl::NoError();
129 }
130 
makeCurrent(const gl::Context * context)131 egl::Error WindowSurfaceGLX::makeCurrent(const gl::Context *context)
132 {
133     return egl::NoError();
134 }
135 
swap(const gl::Context * context)136 egl::Error WindowSurfaceGLX::swap(const gl::Context *context)
137 {
138     // We need to swap before resizing as some drivers clobber the back buffer
139     // when the window is resized.
140     mGLXDisplay->setSwapInterval(mGLXWindow, &mSwapControl);
141     mGLX.swapBuffers(mGLXWindow);
142 
143     egl::Error error = checkForResize();
144     if (error.isError())
145     {
146         return error;
147     }
148 
149     return egl::NoError();
150 }
151 
postSubBuffer(const gl::Context * context,EGLint x,EGLint y,EGLint width,EGLint height)152 egl::Error WindowSurfaceGLX::postSubBuffer(const gl::Context *context,
153                                            EGLint x,
154                                            EGLint y,
155                                            EGLint width,
156                                            EGLint height)
157 {
158     UNIMPLEMENTED();
159     return egl::NoError();
160 }
161 
querySurfacePointerANGLE(EGLint attribute,void ** value)162 egl::Error WindowSurfaceGLX::querySurfacePointerANGLE(EGLint attribute, void **value)
163 {
164     UNIMPLEMENTED();
165     return egl::NoError();
166 }
167 
bindTexImage(const gl::Context * context,gl::Texture * texture,EGLint buffer)168 egl::Error WindowSurfaceGLX::bindTexImage(const gl::Context *context,
169                                           gl::Texture *texture,
170                                           EGLint buffer)
171 {
172     UNIMPLEMENTED();
173     return egl::NoError();
174 }
175 
releaseTexImage(const gl::Context * context,EGLint buffer)176 egl::Error WindowSurfaceGLX::releaseTexImage(const gl::Context *context, EGLint buffer)
177 {
178     UNIMPLEMENTED();
179     return egl::NoError();
180 }
181 
setSwapInterval(EGLint interval)182 void WindowSurfaceGLX::setSwapInterval(EGLint interval)
183 {
184     mSwapControl.targetSwapInterval = interval;
185 }
186 
getWidth() const187 EGLint WindowSurfaceGLX::getWidth() const
188 {
189     // The size of the window is always the same as the cached size of its parent.
190     return mParentWidth;
191 }
192 
getHeight() const193 EGLint WindowSurfaceGLX::getHeight() const
194 {
195     // The size of the window is always the same as the cached size of its parent.
196     return mParentHeight;
197 }
198 
isPostSubBufferSupported() const199 EGLint WindowSurfaceGLX::isPostSubBufferSupported() const
200 {
201     UNIMPLEMENTED();
202     return EGL_FALSE;
203 }
204 
getSwapBehavior() const205 EGLint WindowSurfaceGLX::getSwapBehavior() const
206 {
207     return EGL_BUFFER_DESTROYED;
208 }
209 
checkForResize()210 egl::Error WindowSurfaceGLX::checkForResize()
211 {
212     // TODO(cwallez) set up our own error handler to see if the call failed
213     unsigned int newParentWidth, newParentHeight;
214     if (!getWindowDimensions(mParent, &newParentWidth, &newParentHeight))
215     {
216         return egl::EglBadCurrentSurface() << "Failed to retrieve the size of the parent window.";
217     }
218 
219     if (mParentWidth != newParentWidth || mParentHeight != newParentHeight)
220     {
221         mParentWidth  = newParentWidth;
222         mParentHeight = newParentHeight;
223 
224         mGLX.waitGL();
225         XResizeWindow(mDisplay, mWindow, mParentWidth, mParentHeight);
226         mGLX.waitX();
227         XSync(mDisplay, False);
228     }
229 
230     return egl::NoError();
231 }
232 
getDrawable() const233 glx::Drawable WindowSurfaceGLX::getDrawable() const
234 {
235     return mGLXWindow;
236 }
237 
getWindowDimensions(Window window,unsigned int * width,unsigned int * height) const238 bool WindowSurfaceGLX::getWindowDimensions(Window window,
239                                            unsigned int *width,
240                                            unsigned int *height) const
241 {
242     Window root;
243     int x, y;
244     unsigned int border, depth;
245     return XGetGeometry(mDisplay, window, &root, &x, &y, width, height, &border, &depth) != 0;
246 }
247 
getSyncValues(EGLuint64KHR * ust,EGLuint64KHR * msc,EGLuint64KHR * sbc)248 egl::Error WindowSurfaceGLX::getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc)
249 {
250     if (!mGLX.getSyncValuesOML(mGLXWindow, reinterpret_cast<int64_t *>(ust),
251                                reinterpret_cast<int64_t *>(msc), reinterpret_cast<int64_t *>(sbc)))
252     {
253         return egl::EglBadSurface() << "glXGetSyncValuesOML failed.";
254     }
255     return egl::NoError();
256 }
257 
getMscRate(EGLint * numerator,EGLint * denominator)258 egl::Error WindowSurfaceGLX::getMscRate(EGLint *numerator, EGLint *denominator)
259 {
260     if (!mGLX.getMscRateOML(mGLXWindow, reinterpret_cast<int32_t *>(numerator),
261                             reinterpret_cast<int32_t *>(denominator)))
262     {
263         return egl::EglBadSurface() << "glXGetMscRateOML failed.";
264     }
265     return egl::NoError();
266 }
267 
268 }  // namespace rx
269