diff options
author | Zolnai Tamás <tamas.zolnai@collabora.com> | 2014-03-14 18:51:06 +0100 |
---|---|---|
committer | Zolnai Tamás <tamas.zolnai@collabora.com> | 2014-03-14 19:59:22 +0100 |
commit | a5d178b424d55f61bb3502bb9cbc7ea96aee2cd7 (patch) | |
tree | aafe2e279b5d467c4c514af40c32b0122e253f95 /vcl | |
parent | 04b70c682e2cdc52b144961a83d05fd203de6884 (diff) |
Introduce OpenGLContext in vclopengl
Move DummyChart::initOpengl() and
DummyChart::initWindow into this class.
Change-Id: If3c1bb52cb2819019f0dda626612a164709b17ac
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/Library_vclopengl.mk | 5 | ||||
-rw-r--r-- | vcl/source/opengl/OpenGLContext.cxx | 417 |
2 files changed, 420 insertions, 2 deletions
diff --git a/vcl/Library_vclopengl.mk b/vcl/Library_vclopengl.mk index 5c52add5f3aa..f65f89586e44 100644 --- a/vcl/Library_vclopengl.mk +++ b/vcl/Library_vclopengl.mk @@ -35,13 +35,14 @@ $(eval $(call gb_Library_use_libraries,vclopengl,\ $(eval $(call gb_Library_add_exception_objects,vclopengl,\ vcl/source/opengl/OpenGLRender \ + vcl/source/opengl/OpenGLContext \ )) ifeq ($(strip $(OS)),WNT) $(eval $(call gb_Library_use_system_win32_libs,vclopengl,\ opengl32 \ - gdi32 \ - glu32 \ + gdi32 \ + glu32 \ )) else ifeq ($(OS),MACOSX) $(eval $(call gb_Library_use_system_darwin_frameworks,vclopengl,\ diff --git a/vcl/source/opengl/OpenGLContext.cxx b/vcl/source/opengl/OpenGLContext.cxx new file mode 100644 index 000000000000..70ec988fc0d8 --- /dev/null +++ b/vcl/source/opengl/OpenGLContext.cxx @@ -0,0 +1,417 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <vcl/OpenGLContext.hxx> + + +using namespace com::sun::star; + +namespace { + +#ifdef DBG_UTIL + +namespace { + +const char* getSeverityString(GLenum severity) +{ + switch(severity) + { + case GL_DEBUG_SEVERITY_LOW: + return "low"; + case GL_DEBUG_SEVERITY_MEDIUM: + return "medium"; + case GL_DEBUG_SEVERITY_HIGH: + return "high"; + default: + ; + } + + return "unknown"; +} + +const char* getSourceString(GLenum source) +{ + switch(source) + { + case GL_DEBUG_SOURCE_API: + return "API"; + case GL_DEBUG_SOURCE_SHADER_COMPILER: + return "shader compiler"; + case GL_DEBUG_SOURCE_WINDOW_SYSTEM: + return "window system"; + case GL_DEBUG_SOURCE_THIRD_PARTY: + return "third party"; + case GL_DEBUG_SOURCE_APPLICATION: + return "Libreoffice"; + case GL_DEBUG_SOURCE_OTHER: + return "unknown"; + default: + ; + } + + return "unknown"; +} + +const char* getTypeString(GLenum type) +{ + switch(type) + { + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: + return "deprecated behavior"; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: + return "undefined behavior"; + case GL_DEBUG_TYPE_PERFORMANCE: + return "performance"; + case GL_DEBUG_TYPE_PORTABILITY: + return "portability"; + case GL_DEBUG_TYPE_MARKER: + return "marker"; + case GL_DEBUG_TYPE_PUSH_GROUP: + return "push group"; + case GL_DEBUG_TYPE_POP_GROUP: + return "pop group"; + case GL_DEBUG_TYPE_OTHER: + return "other"; + default: + ; + } + + return "unkown"; +} + +extern "C" void +#if defined _WIN32 +APIENTRY +#endif +debug_callback(GLenum source, GLenum type, GLuint id, + GLenum severity, GLsizei , const GLchar* message, GLvoid* ) +{ + SAL_WARN("vcl.opengl", "OpenGL debug message: source: " << getSourceString(source) << ", type: " + << getTypeString(type) << ", id: " << id << ", severity: " << getSeverityString(severity) << " with message: " << message); +} + +} + +#endif + +#if defined( UNX ) +static bool errorTriggered; +int oglErrorHandler( Display* /*dpy*/, XErrorEvent* /*evnt*/ ) +{ + errorTriggered = true; + + return 0; +} + +} +#endif + +bool OpenGLContext::init(OpenGLRender& rGLRender) +{ + m_pWindow.reset(new Window(0, WB_NOBORDER|WB_NODIALOGCONTROL)); + SAL_INFO("vcl.opengl", "OpenGLContext::OpenGLContext----start"); + initWindow(); + m_pWindow->setPosSizePixel(0,0,0,0); + m_aGLWin.Width = 0; + m_aGLWin.Height = 0; + +#if defined( WNT ) + m_aGLWin.hDC = GetDC(m_aGLWin.hWnd); +#elif defined( MACOSX ) + +#elif defined( UNX ) + m_aGLWin.ctx = glXCreateContext(m_aGLWin.dpy, + m_aGLWin.vi, + 0, + GL_TRUE); + if( m_aGLWin.ctx == NULL ) + { + OSL_TRACE("unable to create GLX context"); + return false; + } +#endif + +#if defined( WNT ) + PIXELFORMATDESCRIPTOR PixelFormatFront = // PixelFormat Tells Windows How We Want Things To Be + { + sizeof(PIXELFORMATDESCRIPTOR), + 1, // Version Number + PFD_DRAW_TO_WINDOW | + PFD_SUPPORT_OPENGL | + PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, // Request An RGBA Format + (BYTE)32, // Select Our Color Depth + 0, 0, 0, 0, 0, 0, // Color Bits Ignored + 0, // No Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + 64, // 32 bit Z-BUFFER + 0, // 0 bit stencil buffer + 0, // No Auxiliary Buffer + 0, // now ignored + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; + + // we must check whether can set the MSAA + int WindowPix; + rGLRender.InitMultisample(PixelFormatFront); + if (rGLRender.GetMSAASupport()) + { + WindowPix = rGLRender.GetMSAAFormat(); + } + else + { + WindowPix = ChoosePixelFormat(m_aGLWin.hDC,&PixelFormatFront); + } + SetPixelFormat(m_aGLWin.hDC,WindowPix,&PixelFormatFront); + m_aGLWin.hRC = wglCreateContext(m_aGLWin.hDC); + wglMakeCurrent(m_aGLWin.hDC,m_aGLWin.hRC); + +#elif defined( MACOSX ) + +#elif defined( UNX ) + if( !glXMakeCurrent( m_aGLWin.dpy, m_aGLWin.win, m_aGLWin.ctx ) ) + { + OSL_TRACE("unable to select current GLX context"); + return false; + } + + int glxMinor, glxMajor; + double nGLXVersion = 0; + if( glXQueryVersion( m_aGLWin.dpy, &glxMajor, &glxMinor ) ) + nGLXVersion = glxMajor + 0.1*glxMinor; + OSL_TRACE("available GLX version: %f", nGLXVersion); + + m_aGLWin.GLExtensions = glGetString( GL_EXTENSIONS ); + OSL_TRACE("available GL extensions: %s", m_aGLWin.GLExtensions); + + if( m_aGLWin.HasGLXExtension("GLX_SGI_swap_control" ) ) + { + // enable vsync + typedef GLint (*glXSwapIntervalProc)(GLint); + glXSwapIntervalProc glXSwapInterval = (glXSwapIntervalProc) glXGetProcAddress( (const GLubyte*) "glXSwapIntervalSGI" ); + if( glXSwapInterval ) { + int (*oldHandler)(Display* /*dpy*/, XErrorEvent* /*evnt*/); + + // replace error handler temporarily + oldHandler = XSetErrorHandler( oglErrorHandler ); + + errorTriggered = false; + + glXSwapInterval( 1 ); + + // sync so that we possibly get an XError + glXWaitGL(); + XSync(m_aGLWin.dpy, false); + + if( errorTriggered ) + OSL_TRACE("error when trying to set swap interval, NVIDIA or Mesa bug?"); + else + OSL_TRACE("set swap interval to 1 (enable vsync)"); + + // restore the error handler + XSetErrorHandler( oldHandler ); + } + } + +#endif + + rGLRender.InitOpenGL(m_aGLWin); + +#ifdef DBG_UTIL + // only enable debug output in dbgutil build + if( GLEW_ARB_debug_output ) + { + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(&debug_callback, NULL); + } + +#endif + + glEnable(GL_TEXTURE_2D); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + // Enable depth test + glEnable(GL_DEPTH_TEST); + // Accept fragment if it closer to the camera than the former one + glDepthFunc(GL_LESS); + +#if defined( WNT ) + SwapBuffers(m_aGLWin.hDC); + glFlush(); +#elif defined( MACOSX ) + +#elif defined( UNX ) + glXSwapBuffers(m_aGLWin.dpy, m_aGLWin.win); +#endif + glEnable(GL_LIGHTING); + GLfloat light_direction[] = { 0.0 , 0.0 , 1.0 }; + GLfloat materialDiffuse[] = { 1.0 , 1.0 , 1.0 , 1.0}; + glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_direction); + glMaterialfv(GL_FRONT,GL_DIFFUSE,materialDiffuse); + glEnable(GL_LIGHT0); + glEnable(GL_NORMALIZE); + SAL_INFO("vcl.opengl", "OpenGLContext::init----end"); + return true; +} + +void OpenGLContext::setWinSize(const Size& rSize) +{ + m_pWindow->SetSizePixel(rSize); + m_pChildWindow->SetSizePixel(rSize); +} + +#if defined( WNT ) + +bool OpenGLContext::initWindow() +{ + const SystemEnvData* sysData(m_pWindow->GetSystemData()); + m_aGLWin.hWnd = sysData->hWnd; + SystemWindowData winData; + winData.nSize = sizeof(winData); + m_pChildWindow.reset(new SystemChildWindow(m_pWindow.get(), 0, &winData, sal_False)); + + + if( m_pChildWindow ) + { + m_pChildWindow->SetMouseTransparent( sal_True ); + m_pChildWindow->SetParentClipMode( PARENTCLIPMODE_NOCLIP ); + m_pChildWindow->EnableEraseBackground( sal_False ); + m_pChildWindow->SetControlForeground(); + m_pChildWindow->SetControlBackground(); + m_pChildWindow->EnablePaint(sal_False); + m_aGLWin.hWnd = sysData->hWnd; + } + + return true; +} + +#elif defined( MACOSX ) + +bool OpenGLContext::initWindow() +{ + return false; +} + +#elif defined( UNX ) + +namespace { + +// we need them before glew can initialize them +// glew needs an OpenGL context so we need to get the address manually +void initOpenGLFunctionPointers() +{ + glXChooseFBConfig = (GLXFBConfig*(*)(Display *dpy, int screen, const int *attrib_list, int *nelements))glXGetProcAddressARB((GLubyte*)"glXChooseFBConfig"); + glXGetVisualFromFBConfig = (XVisualInfo*(*)(Display *dpy, GLXFBConfig config))glXGetProcAddressARB((GLubyte*)"glXGetVisualFromFBConfig"); // try to find a visual for the current set of attributes + glXGetFBConfigAttrib = (int(*)(Display *dpy, GLXFBConfig config, int attribute, int* value))glXGetProcAddressARB((GLubyte*)"glXGetFBConfigAttrib"); + +} + +} + +bool OpenGLContext::initWindow() +{ + const SystemEnvData* sysData(m_pWindow->GetSystemData()); + + m_aGLWin.dpy = reinterpret_cast<Display*>(sysData->pDisplay); + + if( !glXQueryExtension( m_aGLWin.dpy, NULL, NULL ) ) + return false; + + m_aGLWin.win = sysData->aWindow; + + OSL_TRACE("parent window: %d", m_aGLWin.win); + + XWindowAttributes xattr; + XGetWindowAttributes( m_aGLWin.dpy, m_aGLWin.win, &xattr ); + + m_aGLWin.screen = XScreenNumberOfScreen( xattr.screen ); + + static int visual_attribs[] = + { + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 8, + GLX_DEPTH_SIZE, 24, + GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, + None + }; + + const SystemEnvData* pChildSysData = NULL; + m_pChildWindow.reset(); + + initOpenGLFunctionPointers(); + + int fbCount = 0; + GLXFBConfig* pFBC = glXChooseFBConfig( m_aGLWin.dpy, + m_aGLWin.screen, + visual_attribs, &fbCount ); + + if(!pFBC) + { + SAL_WARN("vcl.opengl", "no suitable fb format found"); + return false; + } + + int best_fbc = -1, best_num_samp = -1; + for(int i = 0; i < fbCount; ++i) + { + XVisualInfo* pVi = glXGetVisualFromFBConfig( m_aGLWin.dpy, pFBC[i] ); + if(pVi) + { + // pick the one with the most samples per pixel + int nSampleBuf = 0; + int nSamples = 0; + glXGetFBConfigAttrib( m_aGLWin.dpy, pFBC[i], GLX_SAMPLE_BUFFERS, &nSampleBuf ); + glXGetFBConfigAttrib( m_aGLWin.dpy, pFBC[i], GLX_SAMPLES , &nSamples ); + + if ( best_fbc < 0 || (nSampleBuf && ( nSamples > best_num_samp )) ) + { + best_fbc = i; + best_num_samp = nSamples; + } + } + XFree( pVi ); + } + + XVisualInfo* vi = glXGetVisualFromFBConfig( m_aGLWin.dpy, pFBC[best_fbc] ); + if( vi ) + { + SystemWindowData winData; + winData.nSize = sizeof(winData); + OSL_TRACE("using VisualID %08X", vi->visualid); + winData.pVisual = (void*)(vi->visual); + m_pChildWindow.reset(new SystemChildWindow(m_pWindow.get(), 0, &winData, false)); + pChildSysData = m_pChildWindow->GetSystemData(); + } + + if (!m_pChildWindow || !pChildSysData) + return false; + + m_pChildWindow->SetMouseTransparent( true ); + m_pChildWindow->SetParentClipMode( PARENTCLIPMODE_NOCLIP ); + m_pChildWindow->EnableEraseBackground( false ); + m_pChildWindow->SetControlForeground(); + m_pChildWindow->SetControlBackground(); + + m_aGLWin.dpy = reinterpret_cast<Display*>(pChildSysData->pDisplay); + m_aGLWin.win = pChildSysData->aWindow; + m_aGLWin.vi = vi; + m_aGLWin.GLXExtensions = glXQueryExtensionsString( m_aGLWin.dpy, m_aGLWin.screen ); + OSL_TRACE("available GLX extensions: %s", m_aGLWin.GLXExtensions); + + return true; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |