diff options
Diffstat (limited to 'gfx/angle/src/libANGLE/renderer/gl/glx/WindowSurfaceGLX.cpp')
-rwxr-xr-x | gfx/angle/src/libANGLE/renderer/gl/glx/WindowSurfaceGLX.cpp | 244 |
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; +} + +} |