From 54946518dc54b8eabaa9e47c99ec6d7a852f345d Mon Sep 17 00:00:00 2001 From: Jupeyy Date: Thu, 5 Nov 2020 20:38:37 +0100 Subject: [PATCH 1/6] Add block list for drivers --- src/engine/client/backend_sdl.cpp | 138 ++++++++++++++++++++++-- src/engine/client/backend_sdl.h | 12 +++ src/engine/client/graphics_threaded.cpp | 12 +++ src/engine/client/graphics_threaded.h | 3 + src/engine/warning.h | 2 +- 5 files changed, 155 insertions(+), 12 deletions(-) diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index 83c1a9940..861e32b0c 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -3800,6 +3800,93 @@ static void ParseVersionString(const GLubyte *pStr, int &VersionMajor, int &Vers } } +/* TODO: move this somewhere nice, generalize it more for other drivers / vendors */ +struct SBackEndDriverBlockList +{ + int m_VersionIdentifierMin; + int m_VersionIdentifierMax; + int m_VersionMajorMin; + int m_VersionMajorMax; + int m_VersionMinorMin; + int m_VersionMinorMax; + int m_VersionPatchMin; + int m_VersionPatchMax; + const char *m_pReason; +}; + +static SBackEndDriverBlockList gs_aBlockList[] = { + {26, 26, 20, 20, 100, 100, 7800, 7999, "This Intel driver version can cause crashes, please update it to a newer version and remove any gfx_opengl* config from ddnet_settings.cfg."}}; + +static const char *ParseBlocklistDriverVersions(const GLubyte *pVendorStrGL, const GLubyte *pVersionStrGL) +{ + const char *pVendorStr = (const char *)pVendorStrGL; + const char *pVersionStr = (const char *)pVersionStrGL; + if(str_find_nocase(pVendorStr, "Intel") != NULL) + { + const char *pVersionStrStart = str_find_nocase(pVersionStr, "Build "); + if(pVersionStrStart != NULL) + { + // ignore "Build ", after that, it should directly start with the driver version + pVersionStrStart += (ptrdiff_t)str_length("Build "); + + // get the "major" version + char aVersionStrHelper[MAX_PATH_LENGTH]; // the size is random, but shouldn't be too small probably + const char *pIdentifier = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper) / sizeof(aVersionStrHelper[0])); + bool CheckDriver = false; + int VIdentifier = -1; + int VMajor = -1; + int VMinor = -1; + int VPatch = -1; + if(pIdentifier != NULL) + { + pVersionStrStart = pIdentifier; + VIdentifier = str_toint(aVersionStrHelper); + const char *pMajor = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper) / sizeof(aVersionStrHelper[0])); + if(pMajor != NULL) + { + pVersionStrStart = pMajor; + VMajor = str_toint(aVersionStrHelper); + const char *pMinor = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper) / sizeof(aVersionStrHelper[0])); + if(pMinor != NULL) + { + pVersionStrStart = pMinor; + VMinor = str_toint(aVersionStrHelper); + const char *pPatch = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper) / sizeof(aVersionStrHelper[0])); + if(pPatch != NULL) + { + //pVersionStrStart = pPatch; + VPatch = str_toint(aVersionStrHelper); + CheckDriver = true; + } + } + } + } + + if(CheckDriver) + { + for(auto &BlockListItem : gs_aBlockList) + { + if(VIdentifier >= BlockListItem.m_VersionIdentifierMin && VIdentifier <= BlockListItem.m_VersionIdentifierMax) + { + if(VMajor >= BlockListItem.m_VersionMajorMin && VMajor <= BlockListItem.m_VersionMajorMax) + { + if(VMinor >= BlockListItem.m_VersionMinorMin && VMinor <= BlockListItem.m_VersionMinorMax) + { + if(VPatch >= BlockListItem.m_VersionPatchMin && VPatch <= BlockListItem.m_VersionPatchMax) + { + return BlockListItem.m_pReason; + } + } + } + } + } + } + } + } + + return NULL; +} + static const char *GetGLErrorName(GLenum Type) { if(Type == GL_DEBUG_TYPE_ERROR) @@ -3886,34 +3973,54 @@ void CCommandProcessorFragment_SDL::Cmd_Init(const SCommand_Init *pCommand) dbg_msg("gfx", "Requested OpenGL debug mode, but the driver does not support the required extension"); } + const GLubyte *pVendorString = glGetString(GL_VENDOR); + dbg_msg("opengl", "Vendor string: %s", (const char *)pVendorString); + // check what this context can do const GLubyte *pVersionString = glGetString(GL_VERSION); dbg_msg("opengl", "Version string: %s", (const char *)pVersionString); // parse version string ParseVersionString(pVersionString, pCommand->m_pCapabilities->m_ContextMajor, pCommand->m_pCapabilities->m_ContextMinor, pCommand->m_pCapabilities->m_ContextPatch); + *pCommand->m_pInitError = 0; + + const char *pErrString = ParseBlocklistDriverVersions(pVendorString, pVersionString); + //if the driver is buggy, and the requested GL version is the default, fallback + if(pErrString != NULL && pCommand->m_RequestedMajor == 3 && pCommand->m_RequestedMinor == 0 && pCommand->m_RequestedPatch == 0) + { + // fallback to lowest GL version + pCommand->m_pCapabilities->m_ContextMajor = 1; + pCommand->m_pCapabilities->m_ContextMinor = 5; + pCommand->m_pCapabilities->m_ContextPatch = 0; + + // set backend error string + *pCommand->m_pErrStringPtr = pErrString; + *pCommand->m_pInitError = -2; + } + int MajorV = pCommand->m_pCapabilities->m_ContextMajor; int MinorV = pCommand->m_pCapabilities->m_ContextMinor; - *pCommand->m_pInitError = 0; - - if(MajorV < pCommand->m_RequestedMajor) + if(*pCommand->m_pInitError == 0) { - *pCommand->m_pInitError = -2; - } - else if(MajorV == pCommand->m_RequestedMajor) - { - if(MinorV < pCommand->m_RequestedMinor) + if(MajorV < pCommand->m_RequestedMajor) { *pCommand->m_pInitError = -2; } - else if(MinorV == pCommand->m_RequestedMinor) + else if(MajorV == pCommand->m_RequestedMajor) { - int PatchV = pCommand->m_pCapabilities->m_ContextPatch; - if(PatchV < pCommand->m_RequestedPatch) + if(MinorV < pCommand->m_RequestedMinor) { *pCommand->m_pInitError = -2; } + else if(MinorV == pCommand->m_RequestedMinor) + { + int PatchV = pCommand->m_pCapabilities->m_ContextPatch; + if(PatchV < pCommand->m_RequestedPatch) + { + *pCommand->m_pInitError = -2; + } + } } } @@ -4648,6 +4755,7 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt GetGlewVersion(GlewMajor, GlewMinor, GlewPatch); int InitError = 0; + const char *pErrorStr = NULL; InitError = IsVersionSupportedGlew(g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch, GlewMajor, GlewMinor, GlewPatch); @@ -4672,6 +4780,8 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt m_pProcessor = new CCommandProcessor_SDL_OpenGL(g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch); StartProcessor(m_pProcessor); + mem_zero(m_aErrorString, sizeof(m_aErrorString) / sizeof(m_aErrorString[0])); + // issue init commands for OpenGL and SDL CCommandBuffer CmdBuffer(1024, 512); //run sdl first to have the context in the thread @@ -4686,6 +4796,7 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt CmdSDL.m_GlewMinor = GlewMinor; CmdSDL.m_GlewPatch = GlewPatch; CmdSDL.m_pInitError = &InitError; + CmdSDL.m_pErrStringPtr = &pErrorStr; CmdBuffer.AddCommand(CmdSDL); RunBuffer(&CmdBuffer); WaitForIdle(); @@ -4741,6 +4852,11 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt g_Config.m_GfxOpenGLPatch = m_Capabilites.m_ContextPatch; } + if(pErrorStr != NULL) + { + str_copy(m_aErrorString, pErrorStr, sizeof(m_aErrorString) / sizeof(m_aErrorString[0])); + } + return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_OPENGL_VERSION_FAILED; } diff --git a/src/engine/client/backend_sdl.h b/src/engine/client/backend_sdl.h index a686c53a7..8dae2d279 100644 --- a/src/engine/client/backend_sdl.h +++ b/src/engine/client/backend_sdl.h @@ -419,6 +419,8 @@ public: SDL_GLContext m_GLContext; SBackendCapabilites *m_pCapabilities; + const char **m_pErrStringPtr; + int *m_pInitError; int m_RequestedMajor; @@ -487,6 +489,8 @@ class CGraphicsBackend_SDL_OpenGL : public CGraphicsBackend_Threaded bool m_UseNewOpenGL; + char m_aErrorString[256]; + public: virtual int Init(const char *pName, int *Screen, int *pWidth, int *pHeight, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight, int *pCurrentWidth, int *pCurrentHeight, class IStorage *pStorage); virtual int Shutdown(); @@ -512,6 +516,14 @@ public: virtual bool HasTextBuffering() { return m_Capabilites.m_TextBuffering; } virtual bool HasQuadContainerBuffering() { return m_Capabilites.m_QuadContainerBuffering; } virtual bool Has2DTextureArrays() { return m_Capabilites.m_2DArrayTextures; } + + virtual const char *GetErrorString() + { + if(m_aErrorString[0] != '\0') + return m_aErrorString; + + return NULL; + } }; #endif // ENGINE_CLIENT_BACKEND_SDL_H diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index b316f062c..f0f3cc695 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -2149,6 +2149,7 @@ int CGraphics_Threaded::IssueInit() Flags |= IGraphicsBackend::INITFLAG_RESIZABLE; int r = m_pBackend->Init("DDNet Client", &g_Config.m_GfxScreen, &g_Config.m_GfxScreenWidth, &g_Config.m_GfxScreenHeight, g_Config.m_GfxFsaaSamples, Flags, &m_DesktopScreenWidth, &m_DesktopScreenHeight, &m_ScreenWidth, &m_ScreenHeight, m_pStorage); + AddBackEndWarningIfExists(); m_IsNewOpenGL = m_pBackend->IsNewOpenGL(); m_OpenGLTileBufferingEnabled = m_IsNewOpenGL || m_pBackend->HasTileBuffering(); m_OpenGLQuadBufferingEnabled = m_IsNewOpenGL || m_pBackend->HasQuadBuffering(); @@ -2158,6 +2159,17 @@ int CGraphics_Threaded::IssueInit() return r; } +void CGraphics_Threaded::AddBackEndWarningIfExists() +{ + const char *pErrStr = m_pBackend->GetErrorString(); + if(pErrStr != NULL) + { + SWarning NewWarning; + str_format(NewWarning.m_aWarningMsg, sizeof(NewWarning.m_aWarningMsg), "%s", Localize(pErrStr)); + m_Warnings.emplace_back(NewWarning); + } +} + int CGraphics_Threaded::InitWindow() { int ErrorCode = IssueInit(); diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 2a2e224b5..13e0c4188 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -671,6 +671,7 @@ public: virtual bool HasTextBuffering() { return false; } virtual bool HasQuadContainerBuffering() { return false; } virtual bool Has2DTextureArrays() { return false; } + virtual const char *GetErrorString() { return NULL; } }; class CGraphics_Threaded : public IEngineGraphics @@ -801,6 +802,8 @@ class CGraphics_Threaded : public IEngineGraphics void KickCommandBuffer(); + void AddBackEndWarningIfExists(); + int IssueInit(); int InitWindow(); diff --git a/src/engine/warning.h b/src/engine/warning.h index 1fcd01ca8..64941b504 100644 --- a/src/engine/warning.h +++ b/src/engine/warning.h @@ -10,7 +10,7 @@ struct SWarning { str_copy(m_aWarningMsg, pMsg, sizeof(m_aWarningMsg)); } - char m_aWarningMsg[128]; + char m_aWarningMsg[256]; bool m_WasShown; }; From 5c79e9aa80d7080a4f2bf10570c4dad56841af2d Mon Sep 17 00:00:00 2001 From: def Date: Fri, 6 Nov 2020 17:15:47 +0100 Subject: [PATCH 2/6] Less deep nesting in ParseBlocklistDriverVersions --- src/engine/client/backend_sdl.cpp | 108 +++++++++++++----------------- 1 file changed, 48 insertions(+), 60 deletions(-) diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index 861e32b0c..8183f6cf1 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -3819,69 +3819,57 @@ static SBackEndDriverBlockList gs_aBlockList[] = { static const char *ParseBlocklistDriverVersions(const GLubyte *pVendorStrGL, const GLubyte *pVersionStrGL) { - const char *pVendorStr = (const char *)pVendorStrGL; - const char *pVersionStr = (const char *)pVersionStrGL; - if(str_find_nocase(pVendorStr, "Intel") != NULL) + if(str_find_nocase((const char *)pVendorStrGL, "Intel") == NULL) + return NULL; + + const char *pVersionStrStart = str_find_nocase((const char *)pVersionStrGL, "Build "); + if(pVersionStrStart == NULL) + return NULL; + + // ignore "Build ", after that, it should directly start with the driver version + pVersionStrStart += (ptrdiff_t)str_length("Build "); + + // get the "major" version + char aVersionStrHelper[512]; // the size is random, but shouldn't be too small probably + const char *pIdentifier = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper)); + if(pIdentifier == NULL) + return NULL; + + pVersionStrStart = pIdentifier; + int VIdentifier = str_toint(aVersionStrHelper); + const char *pMajor = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper)); + if(pMajor == NULL) + return NULL; + + pVersionStrStart = pMajor; + int VMajor = str_toint(aVersionStrHelper); + const char *pMinor = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper)); + if(pMinor == NULL) + return NULL; + + pVersionStrStart = pMinor; + int VMinor = str_toint(aVersionStrHelper); + const char *pPatch = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper)); + if(pPatch == NULL) + return NULL; + + int VPatch = str_toint(aVersionStrHelper); + + for(auto &BlockListItem : gs_aBlockList) { - const char *pVersionStrStart = str_find_nocase(pVersionStr, "Build "); - if(pVersionStrStart != NULL) - { - // ignore "Build ", after that, it should directly start with the driver version - pVersionStrStart += (ptrdiff_t)str_length("Build "); + if(VIdentifier < BlockListItem.m_VersionIdentifierMin || VIdentifier > BlockListItem.m_VersionIdentifierMax) + continue; - // get the "major" version - char aVersionStrHelper[MAX_PATH_LENGTH]; // the size is random, but shouldn't be too small probably - const char *pIdentifier = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper) / sizeof(aVersionStrHelper[0])); - bool CheckDriver = false; - int VIdentifier = -1; - int VMajor = -1; - int VMinor = -1; - int VPatch = -1; - if(pIdentifier != NULL) - { - pVersionStrStart = pIdentifier; - VIdentifier = str_toint(aVersionStrHelper); - const char *pMajor = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper) / sizeof(aVersionStrHelper[0])); - if(pMajor != NULL) - { - pVersionStrStart = pMajor; - VMajor = str_toint(aVersionStrHelper); - const char *pMinor = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper) / sizeof(aVersionStrHelper[0])); - if(pMinor != NULL) - { - pVersionStrStart = pMinor; - VMinor = str_toint(aVersionStrHelper); - const char *pPatch = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper) / sizeof(aVersionStrHelper[0])); - if(pPatch != NULL) - { - //pVersionStrStart = pPatch; - VPatch = str_toint(aVersionStrHelper); - CheckDriver = true; - } - } - } - } + if(VMajor < BlockListItem.m_VersionMajorMin || VMajor > BlockListItem.m_VersionMajorMax) + continue; - if(CheckDriver) - { - for(auto &BlockListItem : gs_aBlockList) - { - if(VIdentifier >= BlockListItem.m_VersionIdentifierMin && VIdentifier <= BlockListItem.m_VersionIdentifierMax) - { - if(VMajor >= BlockListItem.m_VersionMajorMin && VMajor <= BlockListItem.m_VersionMajorMax) - { - if(VMinor >= BlockListItem.m_VersionMinorMin && VMinor <= BlockListItem.m_VersionMinorMax) - { - if(VPatch >= BlockListItem.m_VersionPatchMin && VPatch <= BlockListItem.m_VersionPatchMax) - { - return BlockListItem.m_pReason; - } - } - } - } - } - } - } + if(VMinor < BlockListItem.m_VersionMinorMin || VMinor > BlockListItem.m_VersionMinorMax) + continue; + + if(VPatch < BlockListItem.m_VersionPatchMin || VPatch > BlockListItem.m_VersionPatchMax) + continue; + + return BlockListItem.m_pReason; } return NULL; From 3b90f97aa5083f79d8f2b824db63fa35593e3621 Mon Sep 17 00:00:00 2001 From: def Date: Fri, 6 Nov 2020 18:18:55 +0100 Subject: [PATCH 3/6] Pull out blocklist_driver.cpp and unit test it --- CMakeLists.txt | 5 ++ src/engine/client/backend_sdl.cpp | 91 +++----------------------- src/engine/client/backend_sdl.h | 1 + src/engine/client/blocklist_driver.cpp | 66 +++++++++++++++++++ src/engine/client/blocklist_driver.h | 6 ++ src/test/blocklist_driver.cpp | 18 +++++ 6 files changed, 104 insertions(+), 83 deletions(-) create mode 100644 src/engine/client/blocklist_driver.cpp create mode 100644 src/engine/client/blocklist_driver.h create mode 100644 src/test/blocklist_driver.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c06e1bea..10efdedee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1644,6 +1644,8 @@ if(CLIENT) set_src(ENGINE_CLIENT GLOB src/engine/client backend_sdl.cpp backend_sdl.h + blocklist_driver.cpp + blocklist_driver.h client.cpp client.h demoedit.cpp @@ -2114,6 +2116,7 @@ if(GTEST_FOUND OR DOWNLOAD_GTEST) set_src(TESTS GLOB src/test aio.cpp bezier.cpp + blocklist_driver.cpp color.cpp csv.cpp datafile.cpp @@ -2135,6 +2138,8 @@ if(GTEST_FOUND OR DOWNLOAD_GTEST) unix.cpp ) set(TESTS_EXTRA + src/engine/client/blocklist_driver.cpp + src/engine/client/blocklist_driver.h src/engine/server/name_ban.cpp src/engine/server/name_ban.h src/game/server/teehistorian.cpp diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index 8183f6cf1..0c8e1f674 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -3754,7 +3754,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadContainerAsSpriteMultipl // ------------ CCommandProcessorFragment_SDL -static void ParseVersionString(const GLubyte *pStr, int &VersionMajor, int &VersionMinor, int &VersionPatch) +static void ParseVersionString(const char *pStr, int &VersionMajor, int &VersionMinor, int &VersionPatch) { if(pStr) { @@ -3765,12 +3765,12 @@ static void ParseVersionString(const GLubyte *pStr, int &VersionMajor, int &Vers bool LastWasNumber = false; while(*pStr && TotalNumbersPassed < 3) { - if(*pStr >= (GLubyte)'0' && *pStr <= (GLubyte)'9') + if(*pStr >= '0' && *pStr <= '9') { aCurNumberStr[CurNumberStrLen++] = (char)*pStr; LastWasNumber = true; } - else if(LastWasNumber && (*pStr == (GLubyte)'.' || *pStr == (GLubyte)' ' || *pStr == (GLubyte)'\0')) + else if(LastWasNumber && (*pStr == '.' || *pStr == ' ' || *pStr == '\0')) { int CurNumber = 0; if(CurNumberStrLen > 0) @@ -3783,7 +3783,7 @@ static void ParseVersionString(const GLubyte *pStr, int &VersionMajor, int &Vers LastWasNumber = false; - if(*pStr != (GLubyte)'.') + if(*pStr != '.') break; } else @@ -3800,81 +3800,6 @@ static void ParseVersionString(const GLubyte *pStr, int &VersionMajor, int &Vers } } -/* TODO: move this somewhere nice, generalize it more for other drivers / vendors */ -struct SBackEndDriverBlockList -{ - int m_VersionIdentifierMin; - int m_VersionIdentifierMax; - int m_VersionMajorMin; - int m_VersionMajorMax; - int m_VersionMinorMin; - int m_VersionMinorMax; - int m_VersionPatchMin; - int m_VersionPatchMax; - const char *m_pReason; -}; - -static SBackEndDriverBlockList gs_aBlockList[] = { - {26, 26, 20, 20, 100, 100, 7800, 7999, "This Intel driver version can cause crashes, please update it to a newer version and remove any gfx_opengl* config from ddnet_settings.cfg."}}; - -static const char *ParseBlocklistDriverVersions(const GLubyte *pVendorStrGL, const GLubyte *pVersionStrGL) -{ - if(str_find_nocase((const char *)pVendorStrGL, "Intel") == NULL) - return NULL; - - const char *pVersionStrStart = str_find_nocase((const char *)pVersionStrGL, "Build "); - if(pVersionStrStart == NULL) - return NULL; - - // ignore "Build ", after that, it should directly start with the driver version - pVersionStrStart += (ptrdiff_t)str_length("Build "); - - // get the "major" version - char aVersionStrHelper[512]; // the size is random, but shouldn't be too small probably - const char *pIdentifier = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper)); - if(pIdentifier == NULL) - return NULL; - - pVersionStrStart = pIdentifier; - int VIdentifier = str_toint(aVersionStrHelper); - const char *pMajor = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper)); - if(pMajor == NULL) - return NULL; - - pVersionStrStart = pMajor; - int VMajor = str_toint(aVersionStrHelper); - const char *pMinor = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper)); - if(pMinor == NULL) - return NULL; - - pVersionStrStart = pMinor; - int VMinor = str_toint(aVersionStrHelper); - const char *pPatch = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper)); - if(pPatch == NULL) - return NULL; - - int VPatch = str_toint(aVersionStrHelper); - - for(auto &BlockListItem : gs_aBlockList) - { - if(VIdentifier < BlockListItem.m_VersionIdentifierMin || VIdentifier > BlockListItem.m_VersionIdentifierMax) - continue; - - if(VMajor < BlockListItem.m_VersionMajorMin || VMajor > BlockListItem.m_VersionMajorMax) - continue; - - if(VMinor < BlockListItem.m_VersionMinorMin || VMinor > BlockListItem.m_VersionMinorMax) - continue; - - if(VPatch < BlockListItem.m_VersionPatchMin || VPatch > BlockListItem.m_VersionPatchMax) - continue; - - return BlockListItem.m_pReason; - } - - return NULL; -} - static const char *GetGLErrorName(GLenum Type) { if(Type == GL_DEBUG_TYPE_ERROR) @@ -3961,12 +3886,12 @@ void CCommandProcessorFragment_SDL::Cmd_Init(const SCommand_Init *pCommand) dbg_msg("gfx", "Requested OpenGL debug mode, but the driver does not support the required extension"); } - const GLubyte *pVendorString = glGetString(GL_VENDOR); - dbg_msg("opengl", "Vendor string: %s", (const char *)pVendorString); + const char *pVendorString = (const char *)glGetString(GL_VENDOR); + dbg_msg("opengl", "Vendor string: %s", pVendorString); // check what this context can do - const GLubyte *pVersionString = glGetString(GL_VERSION); - dbg_msg("opengl", "Version string: %s", (const char *)pVersionString); + const char *pVersionString = (const char *)glGetString(GL_VERSION); + dbg_msg("opengl", "Version string: %s", pVersionString); // parse version string ParseVersionString(pVersionString, pCommand->m_pCapabilities->m_ContextMajor, pCommand->m_pCapabilities->m_ContextMinor, pCommand->m_pCapabilities->m_ContextPatch); diff --git a/src/engine/client/backend_sdl.h b/src/engine/client/backend_sdl.h index 8dae2d279..550a62c71 100644 --- a/src/engine/client/backend_sdl.h +++ b/src/engine/client/backend_sdl.h @@ -4,6 +4,7 @@ #include "SDL.h" #include "SDL_opengl.h" +#include "blocklist_driver.h" #include "graphics_threaded.h" #include diff --git a/src/engine/client/blocklist_driver.cpp b/src/engine/client/blocklist_driver.cpp new file mode 100644 index 000000000..1df09d06b --- /dev/null +++ b/src/engine/client/blocklist_driver.cpp @@ -0,0 +1,66 @@ +#include "blocklist_driver.h" + +#include + +#define VERSION_PARTS 4 + +struct SVersion +{ + int m_Parts[VERSION_PARTS]; + + bool operator<=(const SVersion &Other) const + { + for(int i = 0; i < VERSION_PARTS; i++) + { + if(m_Parts[i] < Other.m_Parts[i]) + return true; + if(m_Parts[i] > Other.m_Parts[i]) + return false; + } + return true; + } +}; + +/* TODO: generalize it more for other drivers / vendors */ +struct SBackEndDriverBlockList +{ + SVersion m_VersionMin; + SVersion m_VersionMax; + const char *m_pReason; +}; + +static SBackEndDriverBlockList gs_aBlockList[] = { + {{26, 20, 100, 7800}, {26, 20, 100, 7999}, "This Intel driver version can cause crashes, please update it to a newer version and remove any gfx_opengl* config from ddnet_settings.cfg."}}; + +const char *ParseBlocklistDriverVersions(const char *pVendorStr, const char *pVersionStr) +{ + if(str_find_nocase(pVendorStr, "Intel") == NULL) + return NULL; + + const char *pVersionStrStart = str_find_nocase(pVersionStr, "Build "); + if(pVersionStrStart == NULL) + return NULL; + + // ignore "Build ", after that, it should directly start with the driver version + pVersionStrStart += (ptrdiff_t)str_length("Build "); + + char aVersionStrHelper[512]; // the size is random, but shouldn't be too small probably + + SVersion Version; + for(int &VersionPart : Version.m_Parts) + { + pVersionStrStart = str_next_token(pVersionStrStart, ".", aVersionStrHelper, sizeof(aVersionStrHelper)); + if(pVersionStrStart == NULL) + return NULL; + + VersionPart = str_toint(aVersionStrHelper); + } + + for(const auto &BlockListItem : gs_aBlockList) + { + if(BlockListItem.m_VersionMin <= Version && Version <= BlockListItem.m_VersionMax) + return BlockListItem.m_pReason; + } + + return NULL; +} diff --git a/src/engine/client/blocklist_driver.h b/src/engine/client/blocklist_driver.h new file mode 100644 index 000000000..8baa032a1 --- /dev/null +++ b/src/engine/client/blocklist_driver.h @@ -0,0 +1,6 @@ +#ifndef ENGINE_CLIENT_BLOCKLIST_DRIVER_H +#define ENGINE_CLIENT_BLOCKLIST_DRIVER_H + +const char *ParseBlocklistDriverVersions(const char *pVendorStr, const char *pVersionStr); + +#endif // ENGINE_CLIENT_BLOCKLIST_DRIVER_H diff --git a/src/test/blocklist_driver.cpp b/src/test/blocklist_driver.cpp new file mode 100644 index 000000000..d3e601881 --- /dev/null +++ b/src/test/blocklist_driver.cpp @@ -0,0 +1,18 @@ +#include + +#include + +TEST(BlocklistDriver, Valid) +{ + EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.7810"), "This Intel driver version can cause crashes, please update it to a newer version and remove any gfx_opengl* config from ddnet_settings.cfg."); + EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.7926"), "This Intel driver version can cause crashes, please update it to a newer version and remove any gfx_opengl* config from ddnet_settings.cfg."); + EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.7985"), "This Intel driver version can cause crashes, please update it to a newer version and remove any gfx_opengl* config from ddnet_settings.cfg."); +} + +TEST(BlocklistDriver, Invalid) +{ + EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 25.20.100.7810"), NULL); + EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.7799"), NULL); + EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.8000"), NULL); + EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 27.20.100.7900"), NULL); +} From 62e291b4d107866090b8e0f1b24dc0e2b3e39033 Mon Sep 17 00:00:00 2001 From: def Date: Fri, 6 Nov 2020 19:00:23 +0100 Subject: [PATCH 4/6] Allow opengl version 2.0 --- src/engine/client/backend_sdl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index 0c8e1f674..8a1e56cb2 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -3901,9 +3901,9 @@ void CCommandProcessorFragment_SDL::Cmd_Init(const SCommand_Init *pCommand) //if the driver is buggy, and the requested GL version is the default, fallback if(pErrString != NULL && pCommand->m_RequestedMajor == 3 && pCommand->m_RequestedMinor == 0 && pCommand->m_RequestedPatch == 0) { - // fallback to lowest GL version - pCommand->m_pCapabilities->m_ContextMajor = 1; - pCommand->m_pCapabilities->m_ContextMinor = 5; + // fallback to known good GL version + pCommand->m_pCapabilities->m_ContextMajor = 2; + pCommand->m_pCapabilities->m_ContextMinor = 0; pCommand->m_pCapabilities->m_ContextPatch = 0; // set backend error string From 81a11532c52f63be4570516735e9ca9b5f62b436 Mon Sep 17 00:00:00 2001 From: Jupeyy Date: Sat, 7 Nov 2020 06:54:08 +0100 Subject: [PATCH 5/6] Track the driver state --- src/engine/client/backend_sdl.cpp | 29 +++++++++++++++++++++----- src/engine/client/blocklist_driver.cpp | 15 +++++++++++-- src/engine/client/blocklist_driver.h | 2 +- src/engine/shared/config_variables.h | 1 + src/test/blocklist_driver.cpp | 16 +++++++------- 5 files changed, 48 insertions(+), 15 deletions(-) diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index 8a1e56cb2..aeca5c88f 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -3897,18 +3897,37 @@ void CCommandProcessorFragment_SDL::Cmd_Init(const SCommand_Init *pCommand) *pCommand->m_pInitError = 0; - const char *pErrString = ParseBlocklistDriverVersions(pVendorString, pVersionString); + int BlocklistMajor = -1, BlocklistMinor = -1, BlocklistPatch = -1; + const char *pErrString = ParseBlocklistDriverVersions(pVendorString, pVersionString, BlocklistMajor, BlocklistMinor, BlocklistPatch); //if the driver is buggy, and the requested GL version is the default, fallback if(pErrString != NULL && pCommand->m_RequestedMajor == 3 && pCommand->m_RequestedMinor == 0 && pCommand->m_RequestedPatch == 0) { - // fallback to known good GL version - pCommand->m_pCapabilities->m_ContextMajor = 2; + // if not already in the error state, set the GL version + if(g_Config.m_GfxDriverIsBlocked == 0) + { + // fallback to known good GL version + pCommand->m_pCapabilities->m_ContextMajor = BlocklistMajor; + pCommand->m_pCapabilities->m_ContextMinor = BlocklistMinor; + pCommand->m_pCapabilities->m_ContextPatch = BlocklistPatch; + + // set backend error string + *pCommand->m_pErrStringPtr = pErrString; + *pCommand->m_pInitError = -2; + + g_Config.m_GfxDriverIsBlocked = 1; + } + } + // if the driver was in a blocked error state, but is not anymore, reset all config variables + else if(pErrString == NULL && g_Config.m_GfxDriverIsBlocked == 1) + { + pCommand->m_pCapabilities->m_ContextMajor = 3; pCommand->m_pCapabilities->m_ContextMinor = 0; pCommand->m_pCapabilities->m_ContextPatch = 0; - // set backend error string - *pCommand->m_pErrStringPtr = pErrString; + // tell the caller to reinitialize the context *pCommand->m_pInitError = -2; + + g_Config.m_GfxDriverIsBlocked = 0; } int MajorV = pCommand->m_pCapabilities->m_ContextMajor; diff --git a/src/engine/client/blocklist_driver.cpp b/src/engine/client/blocklist_driver.cpp index 1df09d06b..db592b66d 100644 --- a/src/engine/client/blocklist_driver.cpp +++ b/src/engine/client/blocklist_driver.cpp @@ -26,13 +26,19 @@ struct SBackEndDriverBlockList { SVersion m_VersionMin; SVersion m_VersionMax; + + // the OpenGL version, that is supported + int m_AllowedMajor; + int m_AllowedMinor; + int m_AllowedPatch; + const char *m_pReason; }; static SBackEndDriverBlockList gs_aBlockList[] = { - {{26, 20, 100, 7800}, {26, 20, 100, 7999}, "This Intel driver version can cause crashes, please update it to a newer version and remove any gfx_opengl* config from ddnet_settings.cfg."}}; + {{26, 20, 100, 7800}, {26, 20, 100, 7999}, 2, 0, 0, "This Intel driver version can cause crashes, please update it to a newer version."}}; -const char *ParseBlocklistDriverVersions(const char *pVendorStr, const char *pVersionStr) +const char *ParseBlocklistDriverVersions(const char *pVendorStr, const char *pVersionStr, int &BlocklistMajor, int &BlocklistMinor, int &BlocklistPatch) { if(str_find_nocase(pVendorStr, "Intel") == NULL) return NULL; @@ -59,7 +65,12 @@ const char *ParseBlocklistDriverVersions(const char *pVendorStr, const char *pVe for(const auto &BlockListItem : gs_aBlockList) { if(BlockListItem.m_VersionMin <= Version && Version <= BlockListItem.m_VersionMax) + { + BlocklistMajor = BlockListItem.m_AllowedMajor; + BlocklistMinor = BlockListItem.m_AllowedMinor; + BlocklistPatch = BlockListItem.m_AllowedPatch; return BlockListItem.m_pReason; + } } return NULL; diff --git a/src/engine/client/blocklist_driver.h b/src/engine/client/blocklist_driver.h index 8baa032a1..310310b4b 100644 --- a/src/engine/client/blocklist_driver.h +++ b/src/engine/client/blocklist_driver.h @@ -1,6 +1,6 @@ #ifndef ENGINE_CLIENT_BLOCKLIST_DRIVER_H #define ENGINE_CLIENT_BLOCKLIST_DRIVER_H -const char *ParseBlocklistDriverVersions(const char *pVendorStr, const char *pVersionStr); +const char *ParseBlocklistDriverVersions(const char *pVendorStr, const char *pVersionStr, int &BlocklistMajor, int &BlocklistMinor, int &BlocklistPatch); #endif // ENGINE_CLIENT_BLOCKLIST_DRIVER_H diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index f46478a25..152c04798 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -395,6 +395,7 @@ MACRO_CONFIG_INT(GfxOpenGLPatch, gfx_opengl_patch, 0, 0, 10, CFGFLAG_SAVE | CFGF MACRO_CONFIG_INT(GfxOpenGLTextureLODBIAS, gfx_opengl_texture_lod_bias, -500, -15000, 15000, CFGFLAG_SAVE | CFGFLAG_CLIENT, "The lod bias for OpenGL texture sampling multiplied by 1000") MACRO_CONFIG_INT(Gfx3DTextureAnalysisDone, gfx_3d_texture_analysis_done, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Analyzed, if sampling 3D/2D array textures was correct") +MACRO_CONFIG_INT(GfxDriverIsBlocked, gfx_driver_is_blocked, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "If 1, the current driver is in a blocked error state.") #if !defined(CONF_PLATFORM_MACOSX) MACRO_CONFIG_INT(GfxEnableTextureUnitOptimization, gfx_enable_texture_unit_optimization, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Use multiple texture units, instead of only one.") #else diff --git a/src/test/blocklist_driver.cpp b/src/test/blocklist_driver.cpp index d3e601881..13d2ecbac 100644 --- a/src/test/blocklist_driver.cpp +++ b/src/test/blocklist_driver.cpp @@ -4,15 +4,17 @@ TEST(BlocklistDriver, Valid) { - EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.7810"), "This Intel driver version can cause crashes, please update it to a newer version and remove any gfx_opengl* config from ddnet_settings.cfg."); - EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.7926"), "This Intel driver version can cause crashes, please update it to a newer version and remove any gfx_opengl* config from ddnet_settings.cfg."); - EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.7985"), "This Intel driver version can cause crashes, please update it to a newer version and remove any gfx_opengl* config from ddnet_settings.cfg."); + int Major, Minor, Patch; + EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.7810", Major, Minor, Patch), "This Intel driver version can cause crashes, please update it to a newer version."); + EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.7926", Major, Minor, Patch), "This Intel driver version can cause crashes, please update it to a newer version."); + EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.7985", Major, Minor, Patch), "This Intel driver version can cause crashes, please update it to a newer version."); } TEST(BlocklistDriver, Invalid) { - EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 25.20.100.7810"), NULL); - EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.7799"), NULL); - EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.8000"), NULL); - EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 27.20.100.7900"), NULL); + int Major, Minor, Patch; + EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 25.20.100.7810", Major, Minor, Patch), NULL); + EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.7799", Major, Minor, Patch), NULL); + EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.8000", Major, Minor, Patch), NULL); + EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 27.20.100.7900", Major, Minor, Patch), NULL); } From d04f2cf96241948a062e68bbcf346e990a0f2b76 Mon Sep 17 00:00:00 2001 From: def Date: Sat, 7 Nov 2020 11:14:58 +0100 Subject: [PATCH 6/6] blocklist_driver unit test: also check gl version --- src/test/blocklist_driver.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/test/blocklist_driver.cpp b/src/test/blocklist_driver.cpp index 13d2ecbac..aa0cb926b 100644 --- a/src/test/blocklist_driver.cpp +++ b/src/test/blocklist_driver.cpp @@ -2,12 +2,31 @@ #include -TEST(BlocklistDriver, Valid) +TEST(BlocklistDriver, Valid1) { - int Major, Minor, Patch; + int Major = -1, Minor = -1, Patch = -1; EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.7810", Major, Minor, Patch), "This Intel driver version can cause crashes, please update it to a newer version."); + EXPECT_EQ(Major, 2); + EXPECT_EQ(Minor, 0); + EXPECT_EQ(Patch, 0); +} + +TEST(BlocklistDriver, Valid2) +{ + int Major = -1, Minor = -1, Patch = -1; EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.7926", Major, Minor, Patch), "This Intel driver version can cause crashes, please update it to a newer version."); + EXPECT_EQ(Major, 2); + EXPECT_EQ(Minor, 0); + EXPECT_EQ(Patch, 0); +} + +TEST(BlocklistDriver, Valid3) +{ + int Major = -1, Minor = -1, Patch = -1; EXPECT_STREQ(ParseBlocklistDriverVersions("Intel", "Build 26.20.100.7985", Major, Minor, Patch), "This Intel driver version can cause crashes, please update it to a newer version."); + EXPECT_EQ(Major, 2); + EXPECT_EQ(Minor, 0); + EXPECT_EQ(Patch, 0); } TEST(BlocklistDriver, Invalid)