From 0f7687ea558cbddbb77676a19fa8191864408b11 Mon Sep 17 00:00:00 2001 From: Egor Date: Sun, 24 Dec 2017 12:48:18 -0800 Subject: Half implemented OpenGL context initialization in Linux --- Graphics/GraphicsEngineOpenGL/CMakeLists.txt | 15 +- .../GraphicsEngineOpenGL/include/GLContextLinux.h | 14 +- Graphics/GraphicsEngineOpenGL/include/pch.h | 18 ++ .../interface/RenderDeviceFactoryOpenGL.h | 15 +- .../GraphicsEngineOpenGL/src/GLContextLinux.cpp | 301 +++++++++++++++++++++ .../src/RenderDeviceFactoryOpenGL.cpp | 33 ++- Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp | 10 +- 7 files changed, 373 insertions(+), 33 deletions(-) create mode 100644 Graphics/GraphicsEngineOpenGL/src/GLContextLinux.cpp (limited to 'Graphics/GraphicsEngineOpenGL') diff --git a/Graphics/GraphicsEngineOpenGL/CMakeLists.txt b/Graphics/GraphicsEngineOpenGL/CMakeLists.txt index bc4b423a..adf556b2 100644 --- a/Graphics/GraphicsEngineOpenGL/CMakeLists.txt +++ b/Graphics/GraphicsEngineOpenGL/CMakeLists.txt @@ -81,21 +81,20 @@ set(SOURCE if(PLATFORM_WIN32) list(APPEND SOURCE src/GLContextWindows.cpp) - list(APPEND SOURCE src/RenderDeviceGLImpl.cpp) - - set(APPEND INCLUDE include/GLContextWindows.h) + list(APPEND INCLUDE include/GLContextWindows.h) elseif(PLATFORM_ANDROID) list(APPEND SOURCE src/GLContextAndroid.cpp) list(APPEND SOURCE src/RenderDeviceGLESImpl.cpp) list(APPEND SOURCE src/GLStubs.cpp) - set(APPEND INCLUDE include/GLContextAndroid.h) - set(APPEND INCLUDE include/GLStubs.h) - set(APPEND INCLUDE include/RenderDeviceGLESImpl.h) + list(APPEND INCLUDE include/GLContextAndroid.h) + list(APPEND INCLUDE include/GLStubs.h) + list(APPEND INCLUDE include/RenderDeviceGLESImpl.h) - set(APPEND INTERFACE interface/RenderDeviceGLES.h) + list(APPEND INTERFACE interface/RenderDeviceGLES.h) elseif(PLATFORM_LINUX) - set(APPEND INCLUDE include/GLContextLinux.h) + list(APPEND SOURCE src/GLContextLinux.cpp) + list(APPEND INCLUDE include/GLContextLinux.h) else() message(FATAL_ERROR "Unknown platform") endif() diff --git a/Graphics/GraphicsEngineOpenGL/include/GLContextLinux.h b/Graphics/GraphicsEngineOpenGL/include/GLContextLinux.h index ff6796cb..e4eaacc8 100644 --- a/Graphics/GraphicsEngineOpenGL/include/GLContextLinux.h +++ b/Graphics/GraphicsEngineOpenGL/include/GLContextLinux.h @@ -30,23 +30,25 @@ namespace Diligent { SwapChainDesc SwapChainAttribs; void *pNativeWndHandle = nullptr; + void *pDisplay = nullptr; }; class GLContext { public: - typedef void* NativeGLContextType; + typedef GLXContext NativeGLContextType; - GLContext(const ContextInitInfo &Info, struct DeviceCaps &DeviceCaps) {} - ~GLContext() {} - void SwapBuffers() {} + GLContext(const ContextInitInfo &Info, struct DeviceCaps &DeviceCaps); + ~GLContext(); + void SwapBuffers(); const SwapChainDesc& GetSwapChainDesc()const{ return m_SwapChainAttribs; } - NativeGLContextType GetCurrentNativeGLContext() { return nullptr; } + NativeGLContextType GetCurrentNativeGLContext(); private: - void* m_Context; + void *m_pNativeWindow = nullptr; + NativeGLContextType m_Context; SwapChainDesc m_SwapChainAttribs; }; } diff --git a/Graphics/GraphicsEngineOpenGL/include/pch.h b/Graphics/GraphicsEngineOpenGL/include/pch.h index 5860750a..af72d7f7 100644 --- a/Graphics/GraphicsEngineOpenGL/include/pch.h +++ b/Graphics/GraphicsEngineOpenGL/include/pch.h @@ -56,6 +56,24 @@ # endif # include "GL/glew.h" +# include + +// Undefine beautiful defines from GL/glx.h -> X11/Xlib.h +# ifdef Bool +# undef Bool +# endif +# ifdef True +# undef True +# endif +# ifdef False +# undef False +# endif +# ifdef Status +# undef Status +# endif +# ifdef Success +# undef Success +# endif # elif defined(PLATFORM_ANDROID) diff --git a/Graphics/GraphicsEngineOpenGL/interface/RenderDeviceFactoryOpenGL.h b/Graphics/GraphicsEngineOpenGL/interface/RenderDeviceFactoryOpenGL.h index cbf67c8a..36d05353 100644 --- a/Graphics/GraphicsEngineOpenGL/interface/RenderDeviceFactoryOpenGL.h +++ b/Graphics/GraphicsEngineOpenGL/interface/RenderDeviceFactoryOpenGL.h @@ -56,12 +56,15 @@ namespace Diligent class IEngineFactoryOpenGL { public: - virtual void CreateDeviceAndSwapChainGL( const EngineCreationAttribs& CreationAttribs, - IRenderDevice **ppDevice, - IDeviceContext **ppImmediateContext, - const SwapChainDesc& SCDesc, - void *pNativeWndHandle, - ISwapChain **ppSwapChain ) = 0; + virtual void CreateDeviceAndSwapChainGL(const EngineCreationAttribs& CreationAttribs, + IRenderDevice **ppDevice, + IDeviceContext **ppImmediateContext, + const SwapChainDesc& SCDesc, + void *pNativeWndHandle, + #if PLATFORM_LINUX + void *pDisplay, + #endif + ISwapChain **ppSwapChain ) = 0; virtual void CreateHLSL2GLSLConverter(IHLSL2GLSLConverter **ppConverter) = 0; virtual void AttachToActiveGLContext( const EngineCreationAttribs& CreationAttribs, diff --git a/Graphics/GraphicsEngineOpenGL/src/GLContextLinux.cpp b/Graphics/GraphicsEngineOpenGL/src/GLContextLinux.cpp new file mode 100644 index 00000000..2cab04c2 --- /dev/null +++ b/Graphics/GraphicsEngineOpenGL/src/GLContextLinux.cpp @@ -0,0 +1,301 @@ +/* Copyright 2015-2017 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" + +#include "GLContextLinux.h" +#include "DeviceCaps.h" +#include "GLTypeConversions.h" + +namespace Diligent +{ + void openglCallbackFunction( GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar* message, + const void* userParam ) + { + std::stringstream MessageSS; + + MessageSS << std::endl << "OPENGL DEBUG MESSAGE: " << message << std::endl; + MessageSS << "Type: "; + switch( type ) { + case GL_DEBUG_TYPE_ERROR: + MessageSS << "ERROR"; + break; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: + MessageSS << "DEPRECATED_BEHAVIOR"; + break; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: + MessageSS << "UNDEFINED_BEHAVIOR"; + break; + case GL_DEBUG_TYPE_PORTABILITY: + MessageSS << "PORTABILITY"; + break; + case GL_DEBUG_TYPE_PERFORMANCE: + MessageSS << "PERFORMANCE"; + break; + case GL_DEBUG_TYPE_OTHER: + MessageSS << "OTHER"; + break; + } + MessageSS << std::endl; + + MessageSS << "Severity: "; + switch( severity ){ + case GL_DEBUG_SEVERITY_LOW: + MessageSS << "LOW"; + break; + case GL_DEBUG_SEVERITY_MEDIUM: + MessageSS << "MEDIUM"; + break; + case GL_DEBUG_SEVERITY_HIGH: + MessageSS << "HIGH"; + break; + } + MessageSS << std::endl; + + LOG_INFO_MESSAGE_ONCE( MessageSS.str().c_str() ); + } + + GLContext::GLContext( const ContextInitInfo &Info, DeviceCaps &DeviceCaps ) : + m_SwapChainAttribs(Info.SwapChainAttribs), + m_Context(0), + m_pNativeWindow(nullptr) + { + Int32 MajorVersion = 0, MinorVersion = 0; + if(Info.pNativeWndHandle != nullptr) + { + auto wnd = static_cast(reinterpret_cast(Info.pNativeWndHandle)); + auto display = reinterpret_cast(Info.pDisplay); + VERIFY_EXPR(display != nullptr); + + XWindowAttributes XWndAttribs; + XGetWindowAttributes(display, wnd, &XWndAttribs); + + m_SwapChainAttribs.Width = XWndAttribs.width; + m_SwapChainAttribs.Height = XWndAttribs.height; + +#if 0 + auto tmpCtx = glXCreateContext(display, XWndAttribs.visual, NULL, GL_TRUE); + glXMakeCurrent(display, wnd, tmpCtx); + + glxewInit(); + int scrnum = DefaultScreen(display); + int elemc = 0; + GLXFBConfig *fbcfg = glXChooseFBConfig(display, scrnum, NULL, &elemc); + if (!fbcfg) + { + LOG_ERROR_AND_THROW("Couldn't get FB configs\n"); + } + else + { + LOG_INFO_MESSAGE("Got ", elemc," FB configs\n"); + } + + MajorVersion = 4; + MinorVersion = 3; + int glattr[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, MajorVersion, + GLX_CONTEXT_MINOR_VERSION_ARB, MinorVersion, + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + None + }; + + m_Context = glXCreateContextAttribsARB(display, fbcfg[0], NULL, true, glattr); + + glXMakeCurrent(display, None, NULL); + glXDestroyContext(display, tmpCtx); + + glXMakeCurrent(display, wnd, m_Context); + + // glewExperimental = GL_TRUE; + GLenum err = glewInit(); + if( GLEW_OK != err ){ + LOG_ERROR( "Failed to initialize GLEW" ); + exit(1); + } + + // See http://www.opengl.org/wiki/Tutorial:_OpenGL_3.1_The_First_Triangle_(C%2B%2B/Win) + // http://www.opengl.org/wiki/Creating_an_OpenGL_Context_(WGL) + PIXELFORMATDESCRIPTOR pfd; + memset( &pfd, 0, sizeof( PIXELFORMATDESCRIPTOR ) ); + pfd.nSize = sizeof( PIXELFORMATDESCRIPTOR ); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 32; + pfd.cDepthBits = 32; + pfd.iLayerType = PFD_MAIN_PLANE; + + + m_WindowHandleToDeviceContext = GetDC( hWnd ); + int nPixelFormat = ChoosePixelFormat( m_WindowHandleToDeviceContext, &pfd ); + + if( nPixelFormat == 0 ) + LOG_ERROR_AND_THROW( "Invalid Pixel Format" ); + + BOOL bResult = SetPixelFormat( m_WindowHandleToDeviceContext, nPixelFormat, &pfd ); + if( !bResult ) + LOG_ERROR_AND_THROW( "Failed to set Pixel Format" ); + + // Create standard OpenGL (2.1) rendering context which will be used only temporarily, + HGLRC tempContext = wglCreateContext( m_WindowHandleToDeviceContext ); + // and make it current + wglMakeCurrent( m_WindowHandleToDeviceContext, tempContext ); +#endif + // Initialize GLEW + GLenum err = glewInit(); + if( GLEW_OK != err ) + LOG_ERROR_AND_THROW( "Failed to initialize GLEW" ); +#if 0 + if( wglewIsSupported( "WGL_ARB_create_context" ) == 1 ) + { + MajorVersion = 4; + MinorVersion = 4; + // Setup attributes for a new OpenGL rendering context + int attribs[] = + { + WGL_CONTEXT_MAJOR_VERSION_ARB, MajorVersion, + WGL_CONTEXT_MINOR_VERSION_ARB, MinorVersion, + WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + GL_CONTEXT_PROFILE_MASK, GL_CONTEXT_CORE_PROFILE_BIT, + 0, 0 + }; + +#ifdef _DEBUG + attribs[5] |= WGL_CONTEXT_DEBUG_BIT_ARB; +#endif + + // Create new rendering context + // In order to create new OpenGL rendering context we have to call function wglCreateContextAttribsARB(), + // which is an OpenGL function and requires OpenGL to be active when it is called. + // The only way is to create an old context, activate it, and while it is active create a new one. + // Very inconsistent, but we have to live with it! + m_Context = wglCreateContextAttribsARB( m_WindowHandleToDeviceContext, 0, attribs ); + + // Delete tempContext + wglMakeCurrent( NULL, NULL ); + wglDeleteContext( tempContext ); + // Make new context current + wglMakeCurrent( m_WindowHandleToDeviceContext, m_Context ); + wglSwapIntervalEXT( 0 ); + } + else + { //It's not possible to make a GL 4.x context. Use the old style context (GL 2.1 and before) + m_Context = tempContext; + } +#endif + if( glDebugMessageCallback ) + { + glEnable( GL_DEBUG_OUTPUT_SYNCHRONOUS ); + glDebugMessageCallback( openglCallbackFunction, nullptr ); + GLuint unusedIds = 0; + glDebugMessageControl( GL_DONT_CARE, + GL_DONT_CARE, + GL_DONT_CARE, + 0, + &unusedIds, + true ); + } + } + else + { + auto CurrentCtx = glXGetCurrentContext(); + if (CurrentCtx == 0) + { + LOG_ERROR_AND_THROW("No current GL context found! Provide non-null handle to a native Window to create a GL context") + } + + // Initialize GLEW + GLenum err = glewInit(); + if( GLEW_OK != err ) + LOG_ERROR_AND_THROW( "Failed to initialize GLEW" ); + } + + //Checking GL version + const GLubyte *GLVersionString = glGetString( GL_VERSION ); + const GLubyte *GLRenderer = glGetString(GL_RENDERER); + + //Or better yet, use the GL3 way to get the version number + glGetIntegerv( GL_MAJOR_VERSION, &MajorVersion ); + glGetIntegerv( GL_MINOR_VERSION, &MinorVersion ); + LOG_INFO_MESSAGE(Info.pNativeWndHandle != nullptr ? "Initialized OpenGL " : "Attached to OpenGL ", MajorVersion, '.', MinorVersion, " context (", GLVersionString, ", ", GLRenderer, ')') + + // Under the standard filtering rules for cubemaps, filtering does not work across faces of the cubemap. + // This results in a seam across the faces of a cubemap. This was a hardware limitation in the past, but + // modern hardware is capable of interpolating across a cube face boundary. + // GL_TEXTURE_CUBE_MAP_SEAMLESS is not defined in OpenGLES + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + if( glGetError() != GL_NO_ERROR ) + LOG_ERROR_MESSAGE("Failed to enable seamless cubemap filtering"); + + // When GL_FRAMEBUFFER_SRGB is enabled, and if the destination image is in the sRGB colorspace + // then OpenGL will assume the shader's output is in the linear RGB colorspace. It will therefore + // convert the output from linear RGB to sRGB. + // Any writes to images that are not in the sRGB format should not be affected. + // Thus this setting should be just set once and left that way + glEnable(GL_FRAMEBUFFER_SRGB); + if( glGetError() != GL_NO_ERROR ) + LOG_ERROR_MESSAGE("Failed to enable SRGB framebuffers"); + + DeviceCaps.DevType = DeviceType::OpenGL; + DeviceCaps.MajorVersion = MajorVersion; + DeviceCaps.MinorVersion = MinorVersion; + bool IsGL43OrAbove = MajorVersion >= 5 || MajorVersion == 4 && MinorVersion >= 3; + auto &TexCaps = DeviceCaps.TexCaps; + TexCaps.bTexture2DMSSupported = IsGL43OrAbove; + TexCaps.bTexture2DMSArraySupported = IsGL43OrAbove; + TexCaps.bTextureViewSupported = IsGL43OrAbove; + TexCaps.bCubemapArraysSupported = IsGL43OrAbove; + DeviceCaps.bMultithreadedResourceCreationSupported = False; + } + + GLContext::~GLContext() + { +#if 0 + // Do not destroy context if it was created by the app. + if( m_Context ) + { + wglMakeCurrent( m_WindowHandleToDeviceContext, 0 ); + wglDeleteContext( m_Context ); + } +#endif + } + + void GLContext::SwapBuffers() + { + //glXSwapBuffers(display, wnd); + // if(m_WindowHandleToDeviceContext) + // ::SwapBuffers( m_WindowHandleToDeviceContext ); + // else + LOG_ERROR("Swap buffer failed because window handle to device context is not initialized") + } + + GLContext::NativeGLContextType GLContext::GetCurrentNativeGLContext() + { + return glXGetCurrentContext(); + } +} diff --git a/Graphics/GraphicsEngineOpenGL/src/RenderDeviceFactoryOpenGL.cpp b/Graphics/GraphicsEngineOpenGL/src/RenderDeviceFactoryOpenGL.cpp index aa19f8ee..b2ba404e 100644 --- a/Graphics/GraphicsEngineOpenGL/src/RenderDeviceFactoryOpenGL.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/RenderDeviceFactoryOpenGL.cpp @@ -57,12 +57,15 @@ public: return &TheFactory; } - virtual void CreateDeviceAndSwapChainGL( const EngineCreationAttribs& CreationAttribs, - IRenderDevice **ppDevice, - IDeviceContext **ppImmediateContext, - const SwapChainDesc& SCDesc, - void *pNativeWndHandle, - ISwapChain **ppSwapChain )override final; + virtual void CreateDeviceAndSwapChainGL(const EngineCreationAttribs& CreationAttribs, + IRenderDevice **ppDevice, + IDeviceContext **ppImmediateContext, + const SwapChainDesc& SCDesc, + void *pNativeWndHandle, + #if PLATFORM_LINUX + void *pDisplay, + #endif + ISwapChain **ppSwapChain )override final; virtual void CreateHLSL2GLSLConverter(IHLSL2GLSLConverter **ppConverter)override final; @@ -87,12 +90,15 @@ public: /// * On Android platform, this should be a pointer to the native window (ANativeWindow*) /// \param [out] ppSwapChain - Address of the memory location where pointer to the new /// swap chain will be written. -void EngineFactoryOpenGLImpl::CreateDeviceAndSwapChainGL( const EngineCreationAttribs& CreationAttribs, - IRenderDevice **ppDevice, - IDeviceContext **ppImmediateContext, - const SwapChainDesc& SCDesc, - void *pNativeWndHandle, - Diligent::ISwapChain **ppSwapChain ) +void EngineFactoryOpenGLImpl::CreateDeviceAndSwapChainGL(const EngineCreationAttribs& CreationAttribs, + IRenderDevice **ppDevice, + IDeviceContext **ppImmediateContext, + const SwapChainDesc& SCDesc, + void *pNativeWndHandle, + #if PLATFORM_LINUX + void *pDisplay, + #endif + ISwapChain **ppSwapChain ) { VERIFY( ppDevice && ppImmediateContext && ppSwapChain, "Null pointer provided" ); if( !ppDevice || !ppImmediateContext || !ppSwapChain ) @@ -109,6 +115,9 @@ void EngineFactoryOpenGLImpl::CreateDeviceAndSwapChainGL( const EngineCreationAt ContextInitInfo InitInfo; InitInfo.pNativeWndHandle = pNativeWndHandle; + #if PLATFORM_LINUX + InitInfo.pDisplay = pDisplay; + #endif InitInfo.SwapChainAttribs = SCDesc; RenderDeviceGLImpl *pRenderDeviceOpenGL( NEW_RC_OBJ(RawMemAllocator, "TRenderDeviceGLImpl instance", TRenderDeviceGLImpl)(RawMemAllocator, InitInfo) ); pRenderDeviceOpenGL->QueryInterface(IID_RenderDevice, reinterpret_cast(ppDevice) ); diff --git a/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp index 2ef716ed..ea26a880 100644 --- a/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/ShaderGLImpl.cpp @@ -47,7 +47,7 @@ ShaderGLImpl::ShaderGLImpl(IReferenceCounters *pRefCounters, RenderDeviceGLImpl String Settings; -#if defined(PLATFORM_WIN32) +#if defined(PLATFORM_WIN32) || defined(PLATFORM_LINUX) Settings.append( "#version 430 core\n" "#define DESKTOP_GL 1\n" @@ -112,6 +112,8 @@ ShaderGLImpl::ShaderGLImpl(IReferenceCounters *pRefCounters, RenderDeviceGLImpl "precision highp uimageCube;\n" "precision highp uimage2DArray;\n" ); +#elif +# error "Undefined platform" #endif // It would be much more convenient to use row_major matrices. // But unfortunatelly on NVIDIA, the following directive @@ -225,6 +227,12 @@ ShaderGLImpl::ShaderGLImpl(IReferenceCounters *pRefCounters, RenderDeviceGLImpl glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &compiled); if(!compiled) { + std::string FullSource; + for(const auto *str : ShaderStrings) + FullSource.append(str); + + LOG_INFO_MESSAGE("Failed shader full source: \n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n", FullSource, "\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n"); + std::stringstream ErrorMsgSS; ErrorMsgSS << "Failed to compile shader file \""<< (ShaderCreationAttribs.FilePath != nullptr ? ShaderCreationAttribs.FilePath : "") << '\"' << std::endl; int infoLogLen = 0; -- cgit v1.2.3