diff --git a/es-app/src/guis/GuiMenu.cpp b/es-app/src/guis/GuiMenu.cpp index b866a5d09..a2dd6d2be 100644 --- a/es-app/src/guis/GuiMenu.cpp +++ b/es-app/src/guis/GuiMenu.cpp @@ -1224,6 +1224,30 @@ void GuiMenu::openOtherOptions() } }); +#if !defined(USE_OPENGLES) + // Anti-aliasing (MSAA). + auto antiAliasing = std::make_shared>( + getHelpStyle(), "ANTI-ALIASING (MSAA)", false); + const std::string& selectedAntiAliasing { + std::to_string(Settings::getInstance()->getInt("AntiAliasing"))}; + antiAliasing->add("DISABLED", "0", selectedAntiAliasing == "0"); + antiAliasing->add("2X", "2", selectedAntiAliasing == "2"); + antiAliasing->add("4X", "4", selectedAntiAliasing == "4"); + // If there are no objects returned, then there must be a manually modified entry in the + // configuration file. Simply set anti-aliasing to "0" in this case. + if (antiAliasing->getSelectedObjects().size() == 0) + antiAliasing->selectEntry(0); + s->addWithLabel("ANTI-ALIASING (MSAA) (REQUIRES RESTART)", antiAliasing); + s->addSaveFunc([this, antiAliasing, s] { + if (antiAliasing->getSelected() != + std::to_string(Settings::getInstance()->getInt("AntiAliasing"))) { + Settings::getInstance()->setInt("AntiAliasing", + atoi(antiAliasing->getSelected().c_str())); + s->setNeedsSaving(); + } + }); +#endif + // Display/monitor. auto displayIndex = std::make_shared>( getHelpStyle(), "DISPLAY/MONITOR INDEX", false); diff --git a/es-app/src/main.cpp b/es-app/src/main.cpp index e93f6de03..a74d2668e 100644 --- a/es-app/src/main.cpp +++ b/es-app/src/main.cpp @@ -238,7 +238,7 @@ bool parseArgs(int argc, char* argv[]) } if (strcmp(argv[i], "--display") == 0) { if (i >= argc - 1 || atoi(argv[i + 1]) < 1 || atoi(argv[i + 1]) > 4) { - std::cerr << "Error: Invalid display index supplied.\n"; + std::cerr << "Error: Invalid display index supplied\n"; return false; } int DisplayIndex {atoi(argv[i + 1])}; @@ -248,14 +248,14 @@ bool parseArgs(int argc, char* argv[]) } else if (strcmp(argv[i], "--resolution") == 0) { if (i >= argc - 2) { - std::cerr << "Error: Invalid resolution values supplied.\n"; + std::cerr << "Error: Invalid resolution values supplied\n"; return false; } std::string widthArg {argv[i + 1]}; std::string heightArg {argv[i + 2]}; if (widthArg.find_first_not_of("0123456789") != std::string::npos || heightArg.find_first_not_of("0123456789") != std::string::npos) { - std::cerr << "Error: Invalid resolution values supplied.\n"; + std::cerr << "Error: Invalid resolution values supplied\n"; return false; } int width {atoi(argv[i + 1])}; @@ -263,7 +263,7 @@ bool parseArgs(int argc, char* argv[]) if (width < 224 || height < 224 || width > 7680 || height > 7680 || height < width / 4 || width < height / 2) { std::cerr << "Error: Unsupported resolution " << width << "x" << height - << " supplied.\n"; + << " supplied\n"; return false; } Settings::getInstance()->setInt("WindowWidth", width); @@ -272,7 +272,7 @@ bool parseArgs(int argc, char* argv[]) } else if (strcmp(argv[i], "--screensize") == 0) { if (i >= argc - 2) { - std::cerr << "Error: Invalid screensize values supplied.\n"; + std::cerr << "Error: Invalid screensize values supplied\n"; return false; } int width {atoi(argv[i + 1])}; @@ -283,7 +283,7 @@ bool parseArgs(int argc, char* argv[]) } else if (strcmp(argv[i], "--screenoffset") == 0) { if (i >= argc - 2) { - std::cerr << "Error: Invalid screenoffset values supplied.\n"; + std::cerr << "Error: Invalid screenoffset values supplied\n"; return false; } int x {atoi(argv[i + 1])}; @@ -294,13 +294,13 @@ bool parseArgs(int argc, char* argv[]) } else if (strcmp(argv[i], "--screenrotate") == 0) { if (i >= argc - 1) { - std::cerr << "Error: No screenrotate value supplied.\n"; + std::cerr << "Error: No screenrotate value supplied\n"; return false; } std::string rotateValue {argv[i + 1]}; if (rotateValue != "on" && rotateValue != "off" && rotateValue != "1" && rotateValue != "0") { - std::cerr << "Error: Invalid screenrotate value supplied.\n"; + std::cerr << "Error: Invalid screenrotate value supplied\n"; return false; } bool screenRotate {(rotateValue == "on" || rotateValue == "1") ? true : false}; @@ -309,13 +309,13 @@ bool parseArgs(int argc, char* argv[]) } else if (strcmp(argv[i], "--vsync") == 0) { if (i >= argc - 1) { - std::cerr << "Error: No VSync value supplied.\n"; + std::cerr << "Error: No VSync value supplied\n"; return false; } std::string vSyncValue = argv[i + 1]; if (vSyncValue != "on" && vSyncValue != "off" && vSyncValue != "1" && vSyncValue != "0") { - std::cerr << "Error: Invalid VSync value supplied.\n"; + std::cerr << "Error: Invalid VSync value supplied\n"; return false; } bool vSync {(vSyncValue == "on" || vSyncValue == "1") ? true : false}; @@ -324,7 +324,7 @@ bool parseArgs(int argc, char* argv[]) } else if (strcmp(argv[i], "--max-vram") == 0) { if (i >= argc - 1) { - std::cerr << "Error: Invalid VRAM value supplied.\n"; + std::cerr << "Error: Invalid VRAM value supplied\n"; return false; } int maxVRAM {atoi(argv[i + 1])}; @@ -332,6 +332,27 @@ bool parseArgs(int argc, char* argv[]) settingsNeedSaving = true; ++i; } +#if !defined(USE_OPENGLES) + else if (strcmp(argv[i], "--anti-aliasing") == 0) { + bool invalidValue {false}; + int antiAlias {0}; + if (i >= argc - 1) { + invalidValue = true; + } + else { + antiAlias = atoi(argv[i + 1]); + if (antiAlias != 0 && antiAlias != 2 && antiAlias != 4) + invalidValue = true; + } + if (invalidValue) { + std::cerr << "Error: Invalid anti-aliasing value supplied\n"; + return false; + } + Settings::getInstance()->setInt("AntiAliasing", antiAlias); + settingsNeedSaving = true; + ++i; + } +#endif else if (strcmp(argv[i], "--no-splash") == 0) { Settings::getInstance()->setBool("SplashScreen", false); } @@ -385,6 +406,9 @@ bool parseArgs(int argc, char* argv[]) " --screenrotate [1/on or 0/off] Rotate application screen 180 degrees\n" " --vsync [1/on or 0/off] Turn VSync on or off (default is on)\n" " --max-vram [size] Max VRAM to use (in mebibytes) before swapping\n" +#if !defined(USE_OPENGLES) +" --anti-aliasing [0, 2 or 4] Set MSAA anti-aliasing to disabled, 2x or 4x\n" +#endif " --no-splash Don't show the splash screen during startup\n" " --gamelist-only Skip automatic game ROM search, only read from gamelist.xml\n" " --ignore-gamelist Ignore the gamelist.xml files (useful for troubleshooting)\n" diff --git a/es-core/src/Settings.cpp b/es-core/src/Settings.cpp index 66696b12b..b60c4f5f8 100644 --- a/es-core/src/Settings.cpp +++ b/es-core/src/Settings.cpp @@ -247,6 +247,9 @@ void Settings::setDefaults() mIntMap["MaxVRAM"] = {512, 512}; #endif mIntMap["DisplayIndex"] = {1, 1}; +#if !defined(USE_OPENGLES) + mIntMap["AntiAliasing"] = {0, 0}; +#endif #if defined(__APPLE__) mStringMap["KeyboardQuitShortcut"] = {"CmdQ", "CmdQ"}; #else diff --git a/es-core/src/renderers/RendererOpenGL.cpp b/es-core/src/renderers/RendererOpenGL.cpp index adaa1dbff..edfa9c83a 100644 --- a/es-core/src/renderers/RendererOpenGL.cpp +++ b/es-core/src/renderers/RendererOpenGL.cpp @@ -192,6 +192,14 @@ void RendererOpenGL::setup() SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + +#if !defined(USE_OPENGLES) + const int antiAliasing {Settings::getInstance()->getInt("AntiAliasing")}; + if (antiAliasing == 2 || antiAliasing == 4) { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antiAliasing); + } +#endif } bool RendererOpenGL::createContext() @@ -238,6 +246,17 @@ bool RendererOpenGL::createContext() GL_CHECK_ERROR(glPixelStorei(GL_PACK_ALIGNMENT, 1)); GL_CHECK_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); +#if !defined(USE_OPENGLES) + const int antiAliasing {Settings::getInstance()->getInt("AntiAliasing")}; + if (antiAliasing == 2 || antiAliasing == 4) { + GL_CHECK_ERROR(glEnable(GL_MULTISAMPLE)); + LOG(LogInfo) << "Anti-aliasing: " << antiAliasing << "x MSAA"; + } + else { + LOG(LogInfo) << "Anti-aliasing: disabled"; + } +#endif + // These are used for the shader post processing. GL_CHECK_ERROR(glGenFramebuffers(1, &mShaderFBO1)); GL_CHECK_ERROR(glGenFramebuffers(1, &mShaderFBO2)); @@ -279,6 +298,15 @@ void RendererOpenGL::destroyContext() destroyTexture(mPostProcTexture1); destroyTexture(mPostProcTexture2); destroyTexture(mWhiteTexture); + + mShaderProgramVector.clear(); + + mCoreShader.reset(); + mBlurHorizontalShader.reset(); + mBlurVerticalShader.reset(); + mScanlinelShader.reset(); + mLastShader.reset(); + SDL_GL_DeleteContext(mSDLContext); mSDLContext = nullptr; }