summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/libANGLE/renderer/gl/glx/WindowSurfaceGLX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/src/libANGLE/renderer/gl/glx/WindowSurfaceGLX.cpp')
-rwxr-xr-xgfx/angle/src/libANGLE/renderer/gl/glx/WindowSurfaceGLX.cpp244
1 files changed, 244 insertions, 0 deletions
diff --git a/gfx/angle/src/libANGLE/renderer/gl/glx/WindowSurfaceGLX.cpp b/gfx/angle/src/libANGLE/renderer/gl/glx/WindowSurfaceGLX.cpp
new file mode 100755
index 000000000..21b1b316f
--- /dev/null
+++ b/gfx/angle/src/libANGLE/renderer/gl/glx/WindowSurfaceGLX.cpp
@@ -0,0 +1,244 @@
+//
+// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// WindowSurfaceGLX.cpp: GLX implementation of egl::Surface for windows
+
+#include "libANGLE/renderer/gl/glx/WindowSurfaceGLX.h"
+
+#include "common/debug.h"
+
+#include "libANGLE/renderer/gl/glx/DisplayGLX.h"
+#include "libANGLE/renderer/gl/glx/FunctionsGLX.h"
+
+namespace rx
+{
+
+static int IgnoreX11Errors(Display *, XErrorEvent *)
+{
+ return 0;
+}
+
+WindowSurfaceGLX::WindowSurfaceGLX(const egl::SurfaceState &state,
+ const FunctionsGLX &glx,
+ DisplayGLX *glxDisplay,
+ RendererGL *renderer,
+ Window window,
+ Display *display,
+ glx::Context context,
+ glx::FBConfig fbConfig)
+ : SurfaceGLX(state, renderer),
+ mParent(window),
+ mWindow(0),
+ mDisplay(display),
+ mGLX(glx),
+ mGLXDisplay(glxDisplay),
+ mContext(context),
+ mFBConfig(fbConfig),
+ mGLXWindow(0)
+{
+}
+
+WindowSurfaceGLX::~WindowSurfaceGLX()
+{
+ if (mGLXWindow)
+ {
+ mGLX.destroyWindow(mGLXWindow);
+ }
+
+ if (mWindow)
+ {
+ // When destroying the window, it may happen that the window has already been
+ // destroyed by the application (this happens in Chromium). There is no way to
+ // atomically check that a window exists and to destroy it so instead we call
+ // XDestroyWindow, ignoring any errors.
+ auto oldErrorHandler = XSetErrorHandler(IgnoreX11Errors);
+ XDestroyWindow(mDisplay, mWindow);
+ XSync(mDisplay, False);
+ XSetErrorHandler(oldErrorHandler);
+ }
+
+ mGLXDisplay->syncXCommands();
+}
+
+egl::Error WindowSurfaceGLX::initialize()
+{
+ // Check that the window's visual ID is valid, as part of the AMGLE_x11_visual
+ // extension.
+ {
+ XWindowAttributes windowAttributes;
+ XGetWindowAttributes(mDisplay, mParent, &windowAttributes);
+ unsigned long visualId = windowAttributes.visual->visualid;
+
+ if (!mGLXDisplay->isValidWindowVisualId(visualId))
+ {
+ return egl::Error(EGL_BAD_MATCH,
+ "The visual of native_window doesn't match the visual given with "
+ "ANGLE_X11_VISUAL_ID");
+ }
+ }
+
+ // The visual of the X window, GLX window and GLX context must match,
+ // however we received a user-created window that can have any visual
+ // and wouldn't work with our GLX context. To work in all cases, we
+ // create a child window with the right visual that covers all of its
+ // parent.
+ XVisualInfo *visualInfo = mGLX.getVisualFromFBConfig(mFBConfig);
+ if (!visualInfo)
+ {
+ return egl::Error(EGL_BAD_NATIVE_WINDOW, "Failed to get the XVisualInfo for the child window.");
+ }
+ Visual* visual = visualInfo->visual;
+
+ if (!getWindowDimensions(mParent, &mParentWidth, &mParentHeight))
+ {
+ return egl::Error(EGL_BAD_NATIVE_WINDOW, "Failed to get the parent window's dimensions.");
+ }
+
+ // The depth, colormap and visual must match otherwise we get a X error
+ // so we specify the colormap attribute. Also we do not want the window
+ // to be taken into account for input so we specify the event and
+ // do-not-propagate masks to 0 (the defaults). Finally we specify the
+ // border pixel attribute so that we can use a different visual depth
+ // than our parent (seems like X uses that as a condition to render
+ // the subwindow in a different buffer)
+ XSetWindowAttributes attributes;
+ unsigned long attributeMask = CWColormap | CWBorderPixel;
+
+ Colormap colormap = XCreateColormap(mDisplay, mParent, visual, AllocNone);
+ if(!colormap)
+ {
+ XFree(visualInfo);
+ return egl::Error(EGL_BAD_NATIVE_WINDOW, "Failed to create the Colormap for the child window.");
+ }
+ attributes.colormap = colormap;
+ attributes.border_pixel = 0;
+
+ //TODO(cwallez) set up our own error handler to see if the call failed
+ mWindow = XCreateWindow(mDisplay, mParent, 0, 0, mParentWidth, mParentHeight,
+ 0, visualInfo->depth, InputOutput, visual, attributeMask, &attributes);
+ mGLXWindow = mGLX.createWindow(mFBConfig, mWindow, nullptr);
+
+ XMapWindow(mDisplay, mWindow);
+ XFlush(mDisplay);
+
+ XFree(visualInfo);
+ XFreeColormap(mDisplay, colormap);
+
+ mGLXDisplay->syncXCommands();
+
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error WindowSurfaceGLX::makeCurrent()
+{
+ if (mGLX.makeCurrent(mGLXWindow, mContext) != True)
+ {
+ return egl::Error(EGL_BAD_DISPLAY);
+ }
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error WindowSurfaceGLX::swap()
+{
+ // We need to swap before resizing as some drivers clobber the back buffer
+ // when the window is resized.
+ mGLXDisplay->setSwapInterval(mGLXWindow, &mSwapControl);
+ mGLX.swapBuffers(mGLXWindow);
+
+ egl::Error error = checkForResize();
+ if (error.isError())
+ {
+ return error;
+ }
+
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error WindowSurfaceGLX::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height)
+{
+ UNIMPLEMENTED();
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error WindowSurfaceGLX::querySurfacePointerANGLE(EGLint attribute, void **value)
+{
+ UNIMPLEMENTED();
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error WindowSurfaceGLX::bindTexImage(gl::Texture *texture, EGLint buffer)
+{
+ UNIMPLEMENTED();
+ return egl::Error(EGL_SUCCESS);
+}
+
+egl::Error WindowSurfaceGLX::releaseTexImage(EGLint buffer)
+{
+ UNIMPLEMENTED();
+ return egl::Error(EGL_SUCCESS);
+}
+
+void WindowSurfaceGLX::setSwapInterval(EGLint interval)
+{
+ mSwapControl.targetSwapInterval = interval;
+}
+
+EGLint WindowSurfaceGLX::getWidth() const
+{
+ // The size of the window is always the same as the cached size of its parent.
+ return mParentWidth;
+}
+
+EGLint WindowSurfaceGLX::getHeight() const
+{
+ // The size of the window is always the same as the cached size of its parent.
+ return mParentHeight;
+}
+
+EGLint WindowSurfaceGLX::isPostSubBufferSupported() const
+{
+ UNIMPLEMENTED();
+ return EGL_FALSE;
+}
+
+EGLint WindowSurfaceGLX::getSwapBehavior() const
+{
+ return EGL_BUFFER_PRESERVED;
+}
+
+egl::Error WindowSurfaceGLX::checkForResize()
+{
+ // TODO(cwallez) set up our own error handler to see if the call failed
+ unsigned int newParentWidth, newParentHeight;
+ if (!getWindowDimensions(mParent, &newParentWidth, &newParentHeight))
+ {
+ return egl::Error(EGL_BAD_CURRENT_SURFACE,
+ "Failed to retrieve the size of the parent window.");
+ }
+
+ if (mParentWidth != newParentWidth || mParentHeight != newParentHeight)
+ {
+ mParentWidth = newParentWidth;
+ mParentHeight = newParentHeight;
+
+ mGLX.waitGL();
+ XResizeWindow(mDisplay, mWindow, mParentWidth, mParentHeight);
+ mGLX.waitX();
+ XSync(mDisplay, False);
+ }
+
+ return egl::Error(EGL_SUCCESS);
+}
+
+bool WindowSurfaceGLX::getWindowDimensions(Window window, unsigned int *width, unsigned int *height) const
+{
+ Window root;
+ int x, y;
+ unsigned int border, depth;
+ return XGetGeometry(mDisplay, window, &root, &x, &y, width, height, &border, &depth) != 0;
+}
+
+}