Index: ps/trunk/build/premake/premake5.lua =================================================================== --- ps/trunk/build/premake/premake5.lua +++ ps/trunk/build/premake/premake5.lua @@ -772,6 +772,8 @@ "graphics", "graphics/scripting", "renderer", + "renderer/backend", + "renderer/backend/gl", "renderer/scripting", "third_party/mikktspace", "third_party/ogre3d_preprocessor" Index: ps/trunk/source/lib/ogl.h =================================================================== --- ps/trunk/source/lib/ogl.h +++ ps/trunk/source/lib/ogl.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -32,7 +32,7 @@ /** * initialization: import extension function pointers and do feature detect. - * call before using any other function, and after each video mode change. + * call before using any other function. * fails if OpenGL not ready for use. **/ extern void ogl_Init(); Index: ps/trunk/source/lib/ogl.cpp =================================================================== --- ps/trunk/source/lib/ogl.cpp +++ ps/trunk/source/lib/ogl.cpp @@ -33,7 +33,6 @@ #include "lib/external_libraries/libsdl.h" #include "lib/debug.h" -#include "lib/sysdep/gfx.h" #include "lib/res/h_mgr.h" #if MSC_VERSION Index: ps/trunk/source/lib/sysdep/gfx.h =================================================================== --- ps/trunk/source/lib/sysdep/gfx.h +++ ps/trunk/source/lib/sysdep/gfx.h @@ -1,46 +0,0 @@ -/* Copyright (C) 2020 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * 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. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * graphics card detection. - */ - -#ifndef INCLUDED_GFX -#define INCLUDED_GFX - -namespace gfx { - -/** - * @return description of graphics card, -* or L"" if unknown. - **/ -LIB_API std::wstring CardName(); - -/** - * @return string describing the graphics driver and its version, - * or L"" if unknown. - **/ -LIB_API std::wstring DriverInfo(); - -} // namespace gfx - -#endif // #ifndef INCLUDED_GFX Index: ps/trunk/source/lib/sysdep/gfx.cpp =================================================================== --- ps/trunk/source/lib/sysdep/gfx.cpp +++ ps/trunk/source/lib/sysdep/gfx.cpp @@ -1,92 +0,0 @@ -/* Copyright (C) 2020 Wildfire Games. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * 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. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * graphics card detection. - */ - -#include "precompiled.h" -#include "lib/sysdep/gfx.h" - -#include "lib/external_libraries/libsdl.h" -#include "lib/ogl.h" - -#if OS_WIN -# include "lib/sysdep/os/win/wgfx.h" -#endif - -#include - -namespace gfx { - -std::wstring CardName() -{ - // GL_VENDOR+GL_RENDERER are good enough here, so we don't use WMI to detect the cards. - // On top of that WMI can cause crashes with Nvidia Optimus and some netbooks - // see http://trac.wildfiregames.com/ticket/1952 - // http://trac.wildfiregames.com/ticket/1575 - wchar_t cardName[128]; - const char* vendor = (const char*)glGetString(GL_VENDOR); - const char* renderer = (const char*)glGetString(GL_RENDERER); - // (happens if called before ogl_Init or between glBegin and glEnd.) - if(!vendor || !renderer) - return L""; - swprintf_s(cardName, ARRAY_SIZE(cardName), L"%hs %hs", vendor, renderer); - - // remove crap from vendor names. (don't dare touch the model name - - // it's too risky, there are too many different strings) -#define SHORTEN(what, charsToKeep)\ - if(!wcsncmp(cardName, what, ARRAY_SIZE(what)-1))\ - memmove(cardName+charsToKeep, cardName+ARRAY_SIZE(what)-1, (wcslen(cardName)-(ARRAY_SIZE(what)-1)+1)*sizeof(wchar_t)); - SHORTEN(L"ATI Technologies Inc.", 3); - SHORTEN(L"NVIDIA Corporation", 6); - SHORTEN(L"S3 Graphics", 2); // returned by EnumDisplayDevices - SHORTEN(L"S3 Graphics, Incorporated", 2); // returned by GL_VENDOR -#undef SHORTEN - - return cardName; -} - - -std::wstring DriverInfo() -{ - std::wstring driverInfo; -#if OS_WIN - driverInfo = wgfx_DriverInfo(); - if(driverInfo.empty()) -#endif - { - const char* version = (const char*)glGetString(GL_VERSION); - if(version) - { - // add "OpenGL" to differentiate this from the real driver version - // (returned by platform-specific detect routines). - driverInfo = std::wstring(L"OpenGL ") + std::wstring(version, version+strlen(version)); - } - } - - if(driverInfo.empty()) - return L"(unknown)"; - return driverInfo; -} - -} // namespace gfx Index: ps/trunk/source/lib/sysdep/os/osx/osx.cpp =================================================================== --- ps/trunk/source/lib/sysdep/os/osx/osx.cpp +++ ps/trunk/source/lib/sysdep/os/osx/osx.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -24,7 +24,6 @@ #include "lib/lib.h" #include "lib/sysdep/sysdep.h" -#include "lib/sysdep/gfx.h" #include "lib/utf8.h" #include "osx_bundle.h" Index: ps/trunk/source/lib/sysdep/os/win/wgfx.cpp =================================================================== --- ps/trunk/source/lib/sysdep/os/win/wgfx.cpp +++ ps/trunk/source/lib/sysdep/os/win/wgfx.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -27,7 +27,6 @@ #include "precompiled.h" #include "lib/sysdep/os/win/wgfx.h" -#include "lib/sysdep/gfx.h" #include "lib/sysdep/os/win/wdll_ver.h" #include "lib/sysdep/os/win/wutil.h" Index: ps/trunk/source/ps/GameSetup/GameSetup.cpp =================================================================== --- ps/trunk/source/ps/GameSetup/GameSetup.cpp +++ ps/trunk/source/ps/GameSetup/GameSetup.cpp @@ -931,15 +931,9 @@ g_GUI = new CGUIManager(); - // (must come after SetVideoMode, since it calls ogl_Init) CStr8 renderPath = "default"; CFG_GET_VAL("renderpath", renderPath); - if ((ogl_HaveExtensions(0, "GL_ARB_vertex_program", "GL_ARB_fragment_program", nullptr) // ARB - && ogl_HaveExtensions(0, "GL_ARB_vertex_shader", "GL_ARB_fragment_shader", nullptr)) // GLSL - || !ogl_HaveExtension("GL_ARB_vertex_buffer_object") // VBO - || ogl_HaveExtensions(0, "GL_ARB_multitexture", "GL_EXT_draw_range_elements", nullptr) - || (!ogl_HaveExtension("GL_EXT_framebuffer_object") && !ogl_HaveExtension("GL_ARB_framebuffer_object")) - || RenderPathEnum::FromString(renderPath) == FIXED) + if (RenderPathEnum::FromString(renderPath) == FIXED) { // It doesn't make sense to continue working here, because we're not // able to display anything. Index: ps/trunk/source/ps/GameSetup/HWDetect.h =================================================================== --- ps/trunk/source/ps/GameSetup/HWDetect.h +++ ps/trunk/source/ps/GameSetup/HWDetect.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,7 +21,7 @@ /** * Runs hardware-detection script to adjust default config settings * and/or emit warnings depending on the user's system configuration. - * This must only be called after ogl_Init. + * This must only be called after backend device creation. */ void RunHardwareDetection(); Index: ps/trunk/source/ps/GameSetup/HWDetect.cpp =================================================================== --- ps/trunk/source/ps/GameSetup/HWDetect.cpp +++ ps/trunk/source/ps/GameSetup/HWDetect.cpp @@ -25,7 +25,6 @@ #include "lib/res/graphics/ogl_tex.h" #include "lib/posix/posix_utsname.h" #include "lib/sysdep/cpu.h" -#include "lib/sysdep/gfx.h" #include "lib/sysdep/numa.h" #include "lib/sysdep/os_cpu.h" #if ARCH_X86_X64 @@ -43,6 +42,7 @@ #include "ps/scripting/JSInterface_Debug.h" #include "ps/UserReport.h" #include "ps/VideoMode.h" +#include "renderer/backend/gl/Device.h" #include "scriptinterface/FunctionWrapper.h" #include "scriptinterface/JSON.h" #include "scriptinterface/Object.h" @@ -160,8 +160,8 @@ Script::SetProperty(rq, settings, "build_gcc", (int)GCC_VERSION); Script::SetProperty(rq, settings, "build_clang", (int)CLANG_VERSION); - Script::SetProperty(rq, settings, "gfx_card", gfx::CardName()); - Script::SetProperty(rq, settings, "gfx_drv_ver", gfx::DriverInfo()); + Script::SetProperty(rq, settings, "gfx_card", g_VideoMode.GetBackendDevice()->GetName()); + Script::SetProperty(rq, settings, "gfx_drv_ver", g_VideoMode.GetBackendDevice()->GetDriverInformation()); #if CONFIG2_AUDIO if (g_SoundManager) { Index: ps/trunk/source/ps/Util.cpp =================================================================== --- ps/trunk/source/ps/Util.cpp +++ ps/trunk/source/ps/Util.cpp @@ -28,7 +28,6 @@ #if ARCH_X86_X64 #include "lib/sysdep/arch/x86_x64/topology.h" #endif -#include "lib/sysdep/gfx.h" #include "lib/sysdep/cpu.h" #include "lib/sysdep/os_cpu.h" #include "lib/sysdep/smbios.h" @@ -44,6 +43,7 @@ #include "ps/GameSetup/GameSetup.h" #include "ps/Pyrogenesis.h" #include "ps/VideoMode.h" +#include "renderer/backend/gl/Device.h" #include "renderer/Renderer.h" #if CONFIG2_AUDIO @@ -53,29 +53,6 @@ #include #include -static std::string SplitExts(const char *exts) -{ - std::string str = exts; - std::string ret = ""; - size_t idx = str.find_first_of(" "); - while(idx != std::string::npos) - { - if(idx >= str.length() - 1) - { - ret += str; - break; - } - - ret += str.substr(0, idx); - ret += "\n"; - str = str.substr(idx + 1); - idx = str.find_first_of(" "); - } - - return ret; -} - - void WriteSystemInfo() { TIMER(L"write_sys_info"); @@ -126,10 +103,8 @@ fprintf(f, "Memory : %u MiB; %u MiB free\n", (unsigned)os_cpu_MemorySize(), (unsigned)os_cpu_MemoryAvailable()); // graphics - const std::wstring cardName = gfx::CardName(); - const std::wstring driverInfo = gfx::DriverInfo(); - fprintf(f, "Graphics Card : %ls\n", cardName.c_str()); - fprintf(f, "OpenGL Drivers : %s; %ls\n", glGetString(GL_VERSION), driverInfo.c_str()); + fprintf(f, "Video Card : %s\n", g_VideoMode.GetBackendDevice()->GetName().c_str()); + fprintf(f, "Video Driver : %s\n", g_VideoMode.GetBackendDevice()->GetDriverInformation().c_str()); fprintf(f, "Video Mode : %dx%d:%d\n", g_VideoMode.GetXRes(), g_VideoMode.GetYRes(), g_VideoMode.GetBPP()); #if CONFIG2_AUDIO @@ -147,9 +122,12 @@ #endif // OpenGL extensions (write them last, since it's a lot of text) - const char* exts = ogl_ExtensionString(); - if (!exts) exts = "{unknown}"; - fprintf(f, "\nOpenGL Extensions: \n%s\n", SplitExts(exts).c_str()); + fprintf(f, "\nBackend Extensions:\n"); + if (g_VideoMode.GetBackendDevice()->GetExtensions().empty()) + fprintf(f, "{unknown}\n"); + else + for (const std::string& extension : g_VideoMode.GetBackendDevice()->GetExtensions()) + fprintf(f, "%s\n", extension.c_str()); // System Management BIOS (even more text than OpenGL extensions) std::string smbios = SMBIOS::StringizeStructures(SMBIOS::GetStructures()); Index: ps/trunk/source/ps/VideoMode.h =================================================================== --- ps/trunk/source/ps/VideoMode.h +++ ps/trunk/source/ps/VideoMode.h @@ -25,6 +25,17 @@ typedef struct SDL_Window SDL_Window; typedef void* SDL_GLContext; +namespace Renderer +{ +namespace Backend +{ +namespace GL +{ +class CDevice; +} +} +} + class CVideoMode { public: @@ -54,6 +65,12 @@ void Shutdown(); /** + * Creates a backend device. Also we use wxWidgets in Atlas so we don't need + * to create one for that case. + */ + bool CreateBackendDevice(const bool createSDLContext); + + /** * Resize the SDL window and associated graphics stuff to the new size. */ bool ResizeWindow(int w, int h); @@ -112,6 +129,8 @@ Backend GetBackend() const { return m_Backend; } + Renderer::Backend::GL::CDevice* GetBackendDevice() { return m_BackendDevice.get(); } + private: void ReadConfig(); int GetBestBPP(); @@ -125,7 +144,6 @@ bool m_IsInitialised = false; SDL_Window* m_Window = nullptr; - SDL_GLContext m_Context = nullptr; // Initial desktop settings. // Frequency is in Hz, and BPP means bits per pixels (not bytes per pixels). @@ -167,6 +185,7 @@ std::unique_ptr m_Cursor; Backend m_Backend = Backend::GL; + std::unique_ptr m_BackendDevice; }; extern CVideoMode g_VideoMode; Index: ps/trunk/source/ps/VideoMode.cpp =================================================================== --- ps/trunk/source/ps/VideoMode.cpp +++ ps/trunk/source/ps/VideoMode.cpp @@ -24,7 +24,6 @@ #include "lib/config2.h" #include "lib/external_libraries/libsdl.h" #include "lib/ogl.h" -#include "lib/sysdep/gfx.h" #include "lib/tex/tex.h" #include "ps/CConsole.h" #include "ps/CLogger.h" @@ -34,6 +33,7 @@ #include "ps/Game.h" #include "ps/GameSetup/Config.h" #include "ps/Pyrogenesis.h" +#include "renderer/backend/gl/Device.h" #include "renderer/Renderer.h" namespace @@ -286,11 +286,15 @@ return false; } - m_Context = SDL_GL_CreateContext(m_Window); - if (!m_Context) +#if OS_WIN + // We need to set the window for an error dialog. + wutil_SetAppWindow(m_Window); +#endif + + if (!CreateBackendDevice(true)) { - LOGERROR("SetVideoMode failed in SDL_GL_CreateContext: %dx%d:%d %d (\"%s\")", - w, h, bpp, fullscreen ? 1 : 0, SDL_GetError()); + LOGERROR("SetVideoMode failed in backend device creation: %dx%d:%d %d", + w, h, bpp, fullscreen ? 1 : 0); return false; } } @@ -330,11 +334,6 @@ else SDL_SetWindowGrab(m_Window, SDL_FALSE); -#if OS_WIN - // We need to set the window for an error dialog. - wutil_SetAppWindow(m_Window); -#endif - m_IsFullscreen = fullscreen; g_xres = m_CurrentW; @@ -468,9 +467,6 @@ atexit(SDL_Quit); // End work around. - ogl_Init(); // required after each mode change - // (TODO: does that mean we need to call this when toggling fullscreen later?) - m_IsInitialised = true; if (!m_ConfigFullscreen) @@ -505,11 +501,7 @@ m_IsFullscreen = false; m_IsInitialised = false; - if (m_Context) - { - SDL_GL_DeleteContext(m_Context); - m_Context = nullptr; - } + m_BackendDevice.reset(); if (m_Window) { SDL_DestroyWindow(m_Window); @@ -517,6 +509,12 @@ } } +bool CVideoMode::CreateBackendDevice(const bool createSDLContext) +{ + m_BackendDevice = Renderer::Backend::GL::CDevice::Create(createSDLContext ? m_Window : nullptr); + return !!m_BackendDevice; +} + bool CVideoMode::ResizeWindow(int w, int h) { ENSURE(m_IsInitialised); Index: ps/trunk/source/renderer/Renderer.cpp =================================================================== --- ps/trunk/source/renderer/Renderer.cpp +++ ps/trunk/source/renderer/Renderer.cpp @@ -1388,8 +1388,10 @@ { bool checkGLErrorAfterSwap = false; CFG_GET_VAL("gl.checkerrorafterswap", checkGLErrorAfterSwap); +#if defined(NDEBUG) if (!checkGLErrorAfterSwap) return; +#endif PROFILE3("error check"); // We have to check GL errors after SwapBuffer to avoid possible // synchronizations during rendering. Index: ps/trunk/source/renderer/backend/gl/Device.h =================================================================== --- ps/trunk/source/renderer/backend/gl/Device.h +++ ps/trunk/source/renderer/backend/gl/Device.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2021 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_GL_DEVICE +#define INCLUDED_RENDERER_BACKEND_GL_DEVICE + +#include "lib/external_libraries/libsdl.h" + +#include +#include +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +class CDevice +{ +public: + ~CDevice(); + + /** + * Creates the GL device and the GL context for the window if it presents. + */ + static std::unique_ptr Create(SDL_Window* window); + + const std::string& GetName() const { return m_Name; } + const std::string& GetVersion() const { return m_Version; } + const std::string& GetDriverInformation() const { return m_DriverInformation; } + const std::vector& GetExtensions() const { return m_Extensions; } + +private: + CDevice(); + + SDL_GLContext m_Context = nullptr; + + std::string m_Name; + std::string m_Version; + std::string m_DriverInformation; + std::vector m_Extensions; +}; + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_GL_DEVICE Index: ps/trunk/source/renderer/backend/gl/Device.cpp =================================================================== --- ps/trunk/source/renderer/backend/gl/Device.cpp +++ ps/trunk/source/renderer/backend/gl/Device.cpp @@ -0,0 +1,166 @@ +/* Copyright (C) 2021 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "Device.h" + +#include "lib/external_libraries/libsdl.h" +#include "lib/ogl.h" +#include "ps/CLogger.h" + +#if OS_WIN +#include "lib/sysdep/os/win/wgfx.h" +#endif + +#include +#include +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +namespace +{ + +std::string GetNameImpl() +{ + // GL_VENDOR+GL_RENDERER are good enough here, so we don't use WMI to detect the cards. + // On top of that WMI can cause crashes with Nvidia Optimus and some netbooks + // see http://trac.wildfiregames.com/ticket/1952 + // http://trac.wildfiregames.com/ticket/1575 + char cardName[128]; + const char* vendor = reinterpret_cast(glGetString(GL_VENDOR)); + const char* renderer = reinterpret_cast(glGetString(GL_RENDERER)); + // Happens if called before GL initialization. + if (!vendor || !renderer) + return {}; + sprintf_s(cardName, std::size(cardName), "%s %s", vendor, renderer); + + // Remove crap from vendor names. (don't dare touch the model name - + // it's too risky, there are too many different strings). +#define SHORTEN(what, charsToKeep) \ + if (!strncmp(cardName, what, std::size(what) - 1)) \ + memmove(cardName + charsToKeep, cardName + std::size(what) - 1, (strlen(cardName) - (std::size(what) - 1) + 1) * sizeof(char)); + SHORTEN("ATI Technologies Inc.", 3); + SHORTEN("NVIDIA Corporation", 6); + SHORTEN("S3 Graphics", 2); // returned by EnumDisplayDevices + SHORTEN("S3 Graphics, Incorporated", 2); // returned by GL_VENDOR +#undef SHORTEN + + return cardName; +} + +std::string GetVersionImpl() +{ + return reinterpret_cast(glGetString(GL_VERSION)); +} + +std::string GetDriverInformationImpl() +{ + const std::string version = GetVersionImpl(); + + std::string driverInfo; +#if OS_WIN + driverInfo = CStrW(wgfx_DriverInfo()).ToUTF8(); + if (driverInfo.empty()) +#endif + { + if (!version.empty()) + { + // Add "OpenGL" to differentiate this from the real driver version + // (returned by platform-specific detect routines). + driverInfo = std::string("OpenGL ") + version; + } + } + + if (driverInfo.empty()) + return version; + return version + " " + driverInfo; +} + +std::vector GetExtensionsImpl() +{ + std::vector extensions; + const std::string exts = ogl_ExtensionString(); + boost::split(extensions, exts, boost::algorithm::is_space(), boost::token_compress_on); + std::sort(extensions.begin(), extensions.end()); + return extensions; +} + +} // anonymous namespace + +// static +std::unique_ptr CDevice::Create(SDL_Window* window) +{ + std::unique_ptr device(new CDevice()); + + if (window) + { + device->m_Context = SDL_GL_CreateContext(window); + if (!device->m_Context) + { + LOGERROR("SDL_GL_CreateContext failed: '%s'", SDL_GetError()); + return nullptr; + } + } + + ogl_Init(); + + if ((ogl_HaveExtensions(0, "GL_ARB_vertex_program", "GL_ARB_fragment_program", nullptr) // ARB + && ogl_HaveExtensions(0, "GL_ARB_vertex_shader", "GL_ARB_fragment_shader", nullptr)) // GLSL + || !ogl_HaveExtension("GL_ARB_vertex_buffer_object") // VBO + || ogl_HaveExtensions(0, "GL_ARB_multitexture", "GL_EXT_draw_range_elements", nullptr) + || (!ogl_HaveExtension("GL_EXT_framebuffer_object") && !ogl_HaveExtension("GL_ARB_framebuffer_object"))) + { + // It doesn't make sense to continue working here, because we're not + // able to display anything. + DEBUG_DISPLAY_FATAL_ERROR( + L"Your graphics card doesn't appear to be fully compatible with OpenGL shaders." + L" The game does not support pre-shader graphics cards." + L" You are advised to try installing newer drivers and/or upgrade your graphics card." + L" For more information, please see http://www.wildfiregames.com/forum/index.php?showtopic=16734" + ); + } + + device->m_Name = GetNameImpl(); + device->m_Version = GetVersionImpl(); + device->m_DriverInformation = GetDriverInformationImpl(); + device->m_Extensions = GetExtensionsImpl(); + + return device; +} + +CDevice::CDevice() = default; + +CDevice::~CDevice() +{ + if (m_Context) + SDL_GL_DeleteContext(m_Context); +} + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer Index: ps/trunk/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp =================================================================== --- ps/trunk/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp +++ ps/trunk/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp @@ -111,7 +111,7 @@ { UNUSED2(msg); - ogl_Init(); + g_VideoMode.CreateBackendDevice(false); InitGraphics(g_AtlasGameLoop->args, g_InitFlags, {});