From 6b55ca96f37d53cddb0c455668006bea567fefdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 3 Jul 2012 18:26:13 +0200 Subject: [PATCH] Barebone X/EGL context. --- modules/FindEGL.cmake | 23 ++++++ modules/FindMagnum.cmake | 10 +++ modules/FindOpenGLES2.cmake | 23 ++++++ src/Contexts/CMakeLists.txt | 12 ++++ src/Contexts/EglContext.cpp | 138 ++++++++++++++++++++++++++++++++++++ src/Contexts/EglContext.h | 86 ++++++++++++++++++++++ 6 files changed, 292 insertions(+) create mode 100644 modules/FindEGL.cmake create mode 100644 modules/FindOpenGLES2.cmake create mode 100644 src/Contexts/EglContext.cpp create mode 100644 src/Contexts/EglContext.h diff --git a/modules/FindEGL.cmake b/modules/FindEGL.cmake new file mode 100644 index 000000000..fa7ee7cda --- /dev/null +++ b/modules/FindEGL.cmake @@ -0,0 +1,23 @@ +# - Find EGL +# +# This module defines: +# +# EGL_FOUND - True if EGL library is found +# EGL_LIBRARY - EGL library +# EGL_INCLUDE_DIR - Include dir +# + +# Library +find_library(EGL_LIBRARY EGL) + +# Include dir +find_path(EGL_INCLUDE_DIR + NAMES egl.h + PATH_SUFFIXES EGL +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args("EGL" DEFAULT_MSG + EGL_LIBRARY + EGL_INCLUDE_DIR +) diff --git a/modules/FindMagnum.cmake b/modules/FindMagnum.cmake index 55accdb7b..f4cddbe73 100644 --- a/modules/FindMagnum.cmake +++ b/modules/FindMagnum.cmake @@ -89,6 +89,16 @@ foreach(component ${Magnum_FIND_COMPONENTS}) unset(MAGNUM_${_COMPONENT}_LIBRARY) endif() endif() + + # X/EGL context dependencies + if(${component} STREQUAL EglContext) + find_package(OpenGLES2) + find_package(EGL) + find_package(X11) + if(NOT OPENGLES2_FOUND OR NOT EGL_FOUND OR NOT X11_FOUND) + unset(MAGNUM_${_COMPONENT}_LIBRARY) + endif() + endif() endif() # Mesh tools library diff --git a/modules/FindOpenGLES2.cmake b/modules/FindOpenGLES2.cmake new file mode 100644 index 000000000..c534bfd81 --- /dev/null +++ b/modules/FindOpenGLES2.cmake @@ -0,0 +1,23 @@ +# - Find OpenGL ES 2 +# +# This module defines: +# +# OPENGLES2_FOUND - True if OpenGL ES 2 library is found +# OPENGLES2_LIBRARY - OpenGL ES 2 library +# OPENGLES2_INCLUDE_DIR - Include dir +# + +# Library +find_library(OPENGLES2_LIBRARY GLESv2) + +# Include dir +find_path(OPENGLES2_INCLUDE_DIR + NAMES gl2.h + PATH_SUFFIXES GLES2 +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args("OpenGLES2" DEFAULT_MSG + OPENGLES2_LIBRARY + OPENGLES2_INCLUDE_DIR +) diff --git a/src/Contexts/CMakeLists.txt b/src/Contexts/CMakeLists.txt index a72c3ef83..3550ae14d 100644 --- a/src/Contexts/CMakeLists.txt +++ b/src/Contexts/CMakeLists.txt @@ -22,3 +22,15 @@ if(SDL2_FOUND) else() message(WARNING "SDL2 library was not found. SDL2 context library will not be generated.") endif() + +# X/EGL context +find_package(OpenGLES2) +find_package(EGL) +find_package(X11) +if(OPENGLES2_FOUND AND EGL_FOUND AND X11_FOUND) + add_library(MagnumEglContext STATIC EglContext.cpp) + install(FILES EglContext.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Contexts) + install(TARGETS MagnumEglContext DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) +else() + message(WARNING "OpenGL ES 2, EGL or X11 libraries were not found. EGL context library will not be generated.") +endif() diff --git a/src/Contexts/EglContext.cpp b/src/Contexts/EglContext.cpp new file mode 100644 index 000000000..fcf7de69f --- /dev/null +++ b/src/Contexts/EglContext.cpp @@ -0,0 +1,138 @@ +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "EglContext.h" + +using namespace std; + +namespace Magnum { namespace Contexts { + +EglContext::EglContext(int& argc, char** argv, const string& title, const Math::Vector2& size): viewportSize(size) { + /* Get default X display and root window, init EGL */ + xDisplay = XOpenDisplay(0); + display = eglGetDisplay(xDisplay); + eglInitialize(display, 0, 0); + #ifndef MAGNUM_TARGET_GLES + eglBindAPI(EGL_OPENGL_API); + #else + eglBindAPI(EGL_OPENGL_ES_API); + #endif + int screenNumber = DefaultScreen(xDisplay); + Window root = RootWindow(xDisplay, screenNumber); + + /* Choose EGL config */ + static const EGLint attribs[] = { + EGL_RED_SIZE, 1, + EGL_GREEN_SIZE, 1, + EGL_BLUE_SIZE, 1, + EGL_DEPTH_SIZE, 1, + #ifndef MAGNUM_TARGET_GLES + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + #else + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + #endif + EGL_NONE + }; + EGLConfig config; + EGLint configCount; + if(!eglChooseConfig(display, attribs, &config, 1, &configCount)) { + Error() << "Cannot get EGL visual config"; + exit(1); + } + + /* Get X visual */ + EGLint visualId; + if(!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visualId)) { + Error() << "Cannot get native visual ID"; + exit(1); + } + XVisualInfo *visInfo, visTemplate; + int visualCount; + visTemplate.visualid = visualId; + visInfo = XGetVisualInfo(xDisplay, VisualIDMask, &visTemplate, &visualCount); + if(!visInfo) { + Error() << "Cannot get X visual"; + exit(1); + } + + /* Create X Window */ + XSetWindowAttributes attr; + attr.background_pixel = 0; + attr.border_pixel = 0; + attr.colormap = XCreateColormap( xDisplay, root, visInfo->visual, AllocNone); + attr.event_mask = StructureNotifyMask|ExposureMask|KeyPressMask; + unsigned long mask = CWBackPixel|CWBorderPixel|CWColormap|CWEventMask; + xWindow = XCreateWindow(xDisplay, root, 20, 20, size.x(), size.y(), 0, visInfo->depth, InputOutput, visInfo->visual, mask, &attr); + XSetStandardProperties(xDisplay, xWindow, title.c_str(), 0, None, 0, 0, 0); + XFree(visInfo); + + /* Create context and window surface */ + static const EGLint contextAttributes[] = { + #ifdef MAGNUM_TARGET_GLES + EGL_CONTEXT_CLIENT_VERSION, 2, + #endif + EGL_NONE + }; + context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes); + if(!context) { + Error() << "Cannot create EGL context"; + exit(1); + } + surface = eglCreateWindowSurface(display, config, xWindow, NULL); + if(!surface) { + Error() << "Cannot create window surface"; + exit(1); + } + + /* Show window and set OpenGL context as current */ + XMapWindow(xDisplay, xWindow); + eglMakeCurrent(display, surface, surface, context); + + /** @bug Fixme: GLEW initialization fails (thinks that the context is not created) */ + #ifndef MAGNUM_TARGET_GLES + /* Init GLEW */ + GLenum err = glewInit(); + if(err != GLEW_OK) { + Error() << "EglContext: cannot initialize GLEW:" << glewGetErrorString(err); + exit(1); + } + #endif +} + +EglContext::~EglContext() { + /* Shut down EGL */ + eglDestroyContext(display, context); + eglDestroySurface(display, surface); + eglTerminate(display); + + /* Shut down X */ + XDestroyWindow(xDisplay, xWindow); + XCloseDisplay(xDisplay); +} + +int EglContext::exec() { + /* Call viewportEvent for the first time */ + viewportEvent(viewportSize); + + while(true) { + /** @todo Handle at least window closing and resizing */ + eglMakeCurrent(display, surface, surface, context); + drawEvent(); + } + + return 0; +} + +}} diff --git a/src/Contexts/EglContext.h b/src/Contexts/EglContext.h new file mode 100644 index 000000000..a063a591a --- /dev/null +++ b/src/Contexts/EglContext.h @@ -0,0 +1,86 @@ +#ifndef Magnum_Contexts_EglContext_h +#define Magnum_Contexts_EglContext_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Class Magnum::Contexts::EglContext + */ + +#include "Magnum.h" + +#include + +#ifndef SUPPORT_X11 +#define SUPPORT_X11 // OpenGL ES on BeagleBoard needs this (?) +#endif +#include + +#include "AbstractContext.h" + +namespace Magnum { namespace Contexts { + +/** +@brief X/EGL context + +Currently only barebone implementation with no event handling. +*/ +class EglContext: public AbstractContext { + public: + /** + * @brief Constructor + * @param argc Count of arguments of `main()` function + * @param argv Arguments of `main()` function + * @param title Window title + * @param size Window size + * + * Creates window with double-buffered OpenGL ES 2 context. + */ + EglContext(int& argc, char** argv, const std::string& title = "Magnum X/EGL context", const Math::Vector2& size = Math::Vector2(800, 600)); + + /** + * @brief Destructor + * + * Deletes context and destroys the window. + */ + ~EglContext(); + + int exec(); + + protected: + /** @copydoc GlutContext::viewportEvent() */ + virtual void viewportEvent(const Math::Vector2& size) = 0; + + /** @copydoc GlutContext::drawEvent() */ + virtual void drawEvent() = 0; + + /** @copydoc GlutContext::swapBuffers() */ + inline void swapBuffers() { eglSwapBuffers(display, surface); } + + private: + Display* xDisplay; + Window xWindow; + + EGLDisplay display; + EGLSurface surface; + EGLContext context; + + /** @todo Get this from the created window */ + Math::Vector2 viewportSize; +}; + +}} + +#endif