From 5be55d38ed5d1bb2fc254a209fe49096bfd4b29f Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sun, 12 Feb 2023 22:14:09 +0100 Subject: [PATCH] Added support for running the application at lower resolution in fullscreen padded mode. Also added support for offsetting the screen contents within the application window. --- es-app/src/Screensaver.cpp | 6 +- es-app/src/main.cpp | 81 +++++++------- es-core/src/Settings.cpp | 25 ++--- es-core/src/renderers/Renderer.cpp | 131 +++++++++++++++-------- es-core/src/renderers/Renderer.h | 34 ++++-- es-core/src/renderers/RendererOpenGL.cpp | 60 ++++++++--- es-core/src/renderers/RendererOpenGL.h | 1 + 7 files changed, 213 insertions(+), 125 deletions(-) diff --git a/es-app/src/Screensaver.cpp b/es-app/src/Screensaver.cpp index 5111d87d1..fe7c77ed8 100644 --- a/es-app/src/Screensaver.cpp +++ b/es-app/src/Screensaver.cpp @@ -601,8 +601,8 @@ void Screensaver::generateOverlayInfo() if (mGameName == "" || mSystemName == "") return; - float posX {mRenderer->getWindowWidth() * 0.023f}; - float posY {mRenderer->getWindowHeight() * 0.02f}; + float posX {mRenderer->getScreenWidth() * 0.023f}; + float posY {mRenderer->getScreenHeight() * 0.02f}; std::string favoriteChar; if (mCurrentGame && mCurrentGame->getFavorite()) @@ -629,7 +629,7 @@ void Screensaver::generateOverlayInfo() else textSizeX = mGameOverlayFont[0].get()->sizeText(systemName).x; - float marginX {mRenderer->getWindowWidth() * 0.01f}; + float marginX {mRenderer->getScreenWidth() * 0.01f}; mGameOverlayRectangleCoords.clear(); mGameOverlayRectangleCoords.push_back(posX - marginX); diff --git a/es-app/src/main.cpp b/es-app/src/main.cpp index 6782dd8a3..f24b646d5 100644 --- a/es-app/src/main.cpp +++ b/es-app/src/main.cpp @@ -266,17 +266,6 @@ bool parseArgs(int argc, char* argv[]) << " supplied\n"; return false; } - Settings::getInstance()->setInt("WindowWidth", width); - Settings::getInstance()->setInt("WindowHeight", height); - i += 2; - } - else if (strcmp(argv[i], "--screensize") == 0) { - if (i >= argc - 2) { - std::cerr << "Error: Invalid screensize values supplied\n"; - return false; - } - int width {atoi(argv[i + 1])}; - int height {atoi(argv[i + 2])}; Settings::getInstance()->setInt("ScreenWidth", width); Settings::getInstance()->setInt("ScreenHeight", height); i += 2; @@ -307,18 +296,34 @@ bool parseArgs(int argc, char* argv[]) settingsNeedSaving = true; ++i; } + else if (strcmp(argv[i], "--fullscreen-padding") == 0) { + if (i >= argc - 1) { + std::cerr << "Error: No fullscreen-padding value supplied\n"; + return false; + } + std::string fullscreenPaddingValue {argv[i + 1]}; + if (fullscreenPaddingValue != "on" && fullscreenPaddingValue != "off" && + fullscreenPaddingValue != "1" && fullscreenPaddingValue != "0") { + std::cerr << "Error: Invalid fullscreen-padding value supplied\n"; + return false; + } + const bool fullscreenPadding { + (fullscreenPaddingValue == "on" || fullscreenPaddingValue == "1") ? true : false}; + Settings::getInstance()->setBool("FullscreenPadding", fullscreenPadding); + ++i; + } else if (strcmp(argv[i], "--vsync") == 0) { if (i >= argc - 1) { std::cerr << "Error: No VSync value supplied\n"; return false; } - std::string vSyncValue = argv[i + 1]; + std::string vSyncValue {argv[i + 1]}; if (vSyncValue != "on" && vSyncValue != "off" && vSyncValue != "1" && vSyncValue != "0") { std::cerr << "Error: Invalid VSync value supplied\n"; return false; } - bool vSync {(vSyncValue == "on" || vSyncValue == "1") ? true : false}; + const bool vSync {(vSyncValue == "on" || vSyncValue == "1") ? true : false}; Settings::getInstance()->setBool("VSync", vSync); ++i; } @@ -327,7 +332,7 @@ bool parseArgs(int argc, char* argv[]) std::cerr << "Error: Invalid VRAM value supplied\n"; return false; } - int maxVRAM {atoi(argv[i + 1])}; + const int maxVRAM {atoi(argv[i + 1])}; Settings::getInstance()->setInt("MaxVRAM", maxVRAM); settingsNeedSaving = true; ++i; @@ -401,28 +406,30 @@ bool parseArgs(int argc, char* argv[]) "Usage: emulationstation [options]\n" "EmulationStation Desktop Edition, Emulator Frontend\n\n" "Options:\n" -" --display [1 to 4] Display/monitor to use\n" -" --resolution [width] [height] Application resolution\n" -" --screenrotate [0, 90, 180 or 270] Rotate screen contents within application window\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" +" --display [1 to 4] Display/monitor to use\n" +" --resolution [width] [height] Application resolution\n" +" --screenoffset [horiz.] [vert.] Offset screen contents within application window\n" +" --screenrotate [0, 90, 180 or 270] Rotate screen contents within application window\n" +" --fullscreen-padding [1/on or 0/off] Padding if --resolution is lower than display resolution\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" +" --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" -" --show-hidden-files Show hidden files and folders\n" -" --show-hidden-games Show hidden games\n" -" --force-full Force the UI mode to Full\n" -" --force-kiosk Force the UI mode to Kiosk\n" -" --force-kid Force the UI mode to Kid\n" -" --force-input-config Force configuration of input devices\n" -" --create-system-dirs Create game system directories\n" -" --home [path] Directory to use as home path\n" -" --debug Print debug information\n" -" --version, -v Display version information\n" -" --help, -h Summon a sentient, angry tuba\n"; +" --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\n" +" --show-hidden-files Show hidden files and folders\n" +" --show-hidden-games Show hidden games\n" +" --force-full Force the UI mode to Full\n" +" --force-kiosk Force the UI mode to Kiosk\n" +" --force-kid Force the UI mode to Kid\n" +" --force-input-config Force configuration of input devices\n" +" --create-system-dirs Create game system directories\n" +" --home [path] Directory to use as home path\n" +" --debug Print debug information\n" +" --version, -v Display version information\n" +" --help, -h Summon a sentient, angry tuba\n"; // clang-format on return false; // Exit after printing help. } @@ -601,8 +608,8 @@ int main(int argc, char* argv[]) // TODO: Remove when application window resizing has been implemented. Settings::getInstance()->setBool("Debug", true); Log::setReportingLevel(LogDebug); - Settings::getInstance()->setInt("WindowWidth", 1280); - Settings::getInstance()->setInt("WindowHeight", 720); + Settings::getInstance()->setInt("ScreenWidth", 1280); + Settings::getInstance()->setInt("ScreenHeight", 720); #endif // Check if the configuration file exists, and if not, create it. @@ -613,7 +620,7 @@ int main(int argc, char* argv[]) Settings::getInstance()->saveFile(); } else if (settingsNeedSaving) { - LOG(LogInfo) << "Saving settings that were modified by the passed command line options..."; + LOG(LogInfo) << "Saving settings that were modified by command line options..."; Settings::getInstance()->saveFile(); } diff --git a/es-core/src/Settings.cpp b/es-core/src/Settings.cpp index 7e67c8d6a..11b090dfd 100644 --- a/es-core/src/Settings.cpp +++ b/es-core/src/Settings.cpp @@ -26,22 +26,18 @@ namespace std::vector settingsSkipSaving { // clang-format off // These options can be set using command-line arguments: - "WindowWidth", // Set via --resolution [width] [height] - "WindowHeight", // set via --resolution [width] [height] + "ScreenWidth", // Set via --resolution [width] [height] + "ScreenHeight", // set via --resolution [width] [height] + "ScreenOffsetX", // Set via --screenoffset [horiz.] [vert.] + "ScreenOffsetY", // Set via --screenoffset [horiz.] [vert.] + "FullscreenPadding", // Set via --fullscreen-padding [1/on or 0/off] + "VSync", // --vsync [1/on or 0/off] "IgnoreGamelist", // --ignore-gamelist "SplashScreen", // --no-splash - "Debug", // --debug - "VSync", // --vsync [1/on or 0/off] "ForceFull", // --force-full "ForceKiosk", // --force-kiosk "ForceKid", // --force-kid - - // These command-line argument options are not shown in the --help text and are intended - // for debugging and testing purposes: - "ScreenWidth", // Set via --screensize [width] [height] - "ScreenHeight", // set via --screensize [width] [height] - "ScreenOffsetX", // Set via --screenoffset [X] [Y] - "ScreenOffsetY", // Set via --screenoffset [X] [Y] + "Debug", // --debug // These options are only used internally during the application session: "DebugGrid", @@ -137,7 +133,7 @@ void Settings::setDefaults() mStringMap["ScraperRegion"] = {"eu", "eu"}; mStringMap["ScraperLanguage"] = {"en", "en"}; - mIntMap["ScraperRetryOnErrorCount"] = {3, 3}; + mIntMap["ScraperRetryOnErrorCount"] = {5, 5}; mIntMap["ScraperRetryOnErrorTimer"] = {3, 3}; mBoolMap["ScraperOverwriteData"] = {true, true}; mBoolMap["ScraperHaltOnInvalidMedia"] = {true, true}; @@ -297,11 +293,8 @@ void Settings::setDefaults() mBoolMap["IgnoreGamelist"] = {false, false}; mBoolMap["SplashScreen"] = {true, true}; mBoolMap["VSync"] = {true, true}; - mIntMap["WindowWidth"] = {0, 0}; - mIntMap["WindowHeight"] = {0, 0}; + mBoolMap["FullscreenPadding"] = {false, false}; mIntMap["ScreenWidth"] = {0, 0}; - - // Undocumented options. mIntMap["ScreenHeight"] = {0, 0}; mIntMap["ScreenOffsetX"] = {0, 0}; mIntMap["ScreenOffsetY"] = {0, 0}; diff --git a/es-core/src/renderers/Renderer.cpp b/es-core/src/renderers/Renderer.cpp index 3d8404a51..0e319cfc6 100644 --- a/es-core/src/renderers/Renderer.cpp +++ b/es-core/src/renderers/Renderer.cpp @@ -101,26 +101,50 @@ bool Renderer::createWindow() displayMode.h = displayBounds.h; #endif - mWindowWidth = Settings::getInstance()->getInt("WindowWidth") ? - Settings::getInstance()->getInt("WindowWidth") : - displayMode.w; - mWindowHeight = Settings::getInstance()->getInt("WindowHeight") ? - Settings::getInstance()->getInt("WindowHeight") : - displayMode.h; sScreenWidth = Settings::getInstance()->getInt("ScreenWidth") ? Settings::getInstance()->getInt("ScreenWidth") : - mWindowWidth; + displayMode.w; sScreenHeight = Settings::getInstance()->getInt("ScreenHeight") ? Settings::getInstance()->getInt("ScreenHeight") : - mWindowHeight; - mScreenOffsetX = Settings::getInstance()->getInt("ScreenOffsetX") ? - Settings::getInstance()->getInt("ScreenOffsetX") : - 0; - mScreenOffsetY = Settings::getInstance()->getInt("ScreenOffsetY") ? - Settings::getInstance()->getInt("ScreenOffsetY") : - 0; + displayMode.h; + mScreenOffsetX = glm::clamp((Settings::getInstance()->getInt("ScreenOffsetX") ? + Settings::getInstance()->getInt("ScreenOffsetX") : + 0), + -(displayMode.w / 2), displayMode.w / 2); + mScreenOffsetY = glm::clamp((Settings::getInstance()->getInt("ScreenOffsetY") ? + Settings::getInstance()->getInt("ScreenOffsetY") : + 0), + -(displayMode.w / 2), displayMode.h / 2); mScreenRotation = Settings::getInstance()->getInt("ScreenRotate"); + if (mScreenOffsetX != 0 || mScreenOffsetY != 0) { + LOG(LogInfo) << "Screen offset: " << mScreenOffsetX << " horizontal, " << mScreenOffsetY + << " vertical"; + } + else { + LOG(LogInfo) << "Screen offset: disabled"; + } + + mPaddingWidth = 0; + mPaddingHeight = 0; + bool fullscreenPadding {false}; + + if (Settings::getInstance()->getBool("FullscreenPadding") && sScreenWidth <= displayMode.w && + sScreenHeight <= displayMode.h) { + mWindowWidth = displayMode.w; + mWindowHeight = displayMode.h; + mPaddingWidth = displayMode.w - sScreenWidth; + mPaddingHeight = displayMode.h - sScreenHeight; + mScreenOffsetX -= mPaddingWidth / 2.0f; + mScreenOffsetY -= mPaddingHeight / 2.0f; + fullscreenPadding = true; + } + + if (!fullscreenPadding) { + mWindowWidth = sScreenWidth; + mWindowHeight = sScreenHeight; + } + // In case someone manually added an invalid value to es_settings.xml. if (mScreenRotation != 0 && mScreenRotation != 90 && mScreenRotation != 180 && mScreenRotation != 270) { @@ -158,7 +182,7 @@ bool Renderer::createWindow() SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"); #endif - bool userResolution = false; + bool userResolution {false}; // Check if the user has changed the resolution from the command line. if (mWindowWidth != displayMode.w || mWindowHeight != displayMode.h) userResolution = true; @@ -219,17 +243,17 @@ bool Renderer::createWindow() // display so that the full application window is used for rendering. int width {0}; SDL_GL_GetDrawableSize(mSDLWindow, &width, nullptr); - int scaleFactor = static_cast(width / mWindowWidth); + int scaleFactor {static_cast(width / sScreenWidth)}; LOG(LogInfo) << "Display resolution: " << std::to_string(displayMode.w) << "x" << std::to_string(displayMode.h) << " (physical resolution " << std::to_string(displayMode.w * scaleFactor) << "x" << std::to_string(displayMode.h * scaleFactor) << ")"; LOG(LogInfo) << "Display refresh rate: " << std::to_string(displayMode.refresh_rate) << " Hz"; - LOG(LogInfo) << "EmulationStation resolution: " << std::to_string(mWindowWidth) << "x" - << std::to_string(mWindowHeight) << " (physical resolution " - << std::to_string(mWindowWidth * scaleFactor) << "x" - << std::to_string(mWindowHeight * scaleFactor) << ")"; + LOG(LogInfo) << "Application resolution: " << std::to_string(sScreenWidth) << "x" + << std::to_string(sScreenHeight) << " (physical resolution " + << std::to_string(sScreenWidth * scaleFactor) << "x" + << std::to_string(sScreenHeight * scaleFactor) << ")"; mWindowWidth *= scaleFactor; mWindowHeight *= scaleFactor; @@ -239,8 +263,8 @@ bool Renderer::createWindow() LOG(LogInfo) << "Display resolution: " << std::to_string(displayMode.w) << "x" << std::to_string(displayMode.h); LOG(LogInfo) << "Display refresh rate: " << std::to_string(displayMode.refresh_rate) << " Hz"; - LOG(LogInfo) << "EmulationStation resolution: " << std::to_string(mWindowWidth) << "x" - << std::to_string(mWindowHeight); + LOG(LogInfo) << "Application resolution: " << std::to_string(sScreenWidth) << "x" + << std::to_string(sScreenHeight); #endif sScreenHeightModifier = static_cast(sScreenHeight) / 1080.0f; @@ -252,6 +276,23 @@ bool Renderer::createWindow() else sScreenResolutionModifier = sScreenHeight / 1080.0f; + if (Settings::getInstance()->getBool("FullscreenPadding")) { + if (!fullscreenPadding) { + LOG(LogWarning) << "Fullscreen padding can't be applied when --resolution is set " + "higher than the display resolution"; + LOG(LogInfo) << "Screen mode: windowed"; + } + else { + LOG(LogInfo) << "Screen mode: fullscreen padding"; + } + } + else if (userResolution) { + LOG(LogInfo) << "Screen mode: windowed"; + } + else { + LOG(LogInfo) << "Screen mode: fullscreen"; + } + LOG(LogInfo) << "Setting up OpenGL..."; if (!createContext()) @@ -287,27 +328,30 @@ bool Renderer::init() return false; glm::mat4 projection {getIdentity()}; - Rect viewport {0, 0, 0, 0}; - - viewport.x = mWindowWidth - mScreenOffsetX - sScreenWidth; - viewport.y = mWindowHeight - mScreenOffsetY - sScreenHeight; - viewport.w = sScreenWidth; - viewport.h = sScreenHeight; - - projection = glm::ortho(0.0f, static_cast(sScreenHeight), - static_cast(sScreenWidth), 0.0f, -1.0f, 1.0f); if (mScreenRotation == 0) { + mViewport.x = mWindowWidth + mScreenOffsetX - sScreenWidth; + mViewport.y = mWindowHeight + mScreenOffsetY - sScreenHeight; + mViewport.w = sScreenWidth; + mViewport.h = sScreenHeight; mProjectionMatrix = glm::ortho(0.0f, static_cast(sScreenWidth), static_cast(sScreenHeight), 0.0f, -1.0f, 1.0f); } else if (mScreenRotation == 90) { + mViewport.x = mWindowWidth + mScreenOffsetX - sScreenHeight; + mViewport.y = mWindowHeight + mScreenOffsetY - sScreenWidth; + mViewport.w = sScreenHeight; + mViewport.h = sScreenWidth; projection = glm::ortho(0.0f, static_cast(sScreenHeight), static_cast(sScreenWidth), 0.0f, -1.0f, 1.0f); projection = glm::rotate(projection, glm::radians(90.0f), {0.0f, 0.0f, 1.0f}); mProjectionMatrix = glm::translate(projection, {0.0f, sScreenHeight * -1.0f, 0.0f}); } else if (mScreenRotation == 180) { + mViewport.x = mWindowWidth + mScreenOffsetX - sScreenWidth; + mViewport.y = mWindowHeight + mScreenOffsetY - sScreenHeight; + mViewport.w = sScreenWidth; + mViewport.h = sScreenHeight; projection = glm::ortho(0.0f, static_cast(sScreenWidth), static_cast(sScreenHeight), 0.0f, -1.0f, 1.0f); projection = glm::rotate(projection, glm::radians(180.0f), {0.0f, 0.0f, 1.0f}); @@ -315,6 +359,10 @@ bool Renderer::init() glm::translate(projection, {sScreenWidth * -1.0f, sScreenHeight * -1.0f, 0.0f}); } else if (mScreenRotation == 270) { + mViewport.x = mWindowWidth + mScreenOffsetX - sScreenHeight; + mViewport.y = mWindowHeight + mScreenOffsetY - sScreenWidth; + mViewport.w = sScreenHeight; + mViewport.h = sScreenWidth; projection = glm::ortho(0.0f, static_cast(sScreenHeight), static_cast(sScreenWidth), 0.0f, -1.0f, 1.0f); projection = glm::rotate(projection, glm::radians(270.0f), {0.0f, 0.0f, 1.0f}); @@ -323,11 +371,7 @@ bool Renderer::init() mProjectionMatrixNormal = glm::ortho(0.0f, static_cast(sScreenWidth), static_cast(sScreenHeight), 0.0f, -1.0f, 1.0f); - - viewport.x = mScreenOffsetX; - viewport.y = mScreenOffsetY; - viewport.w = sScreenWidth; - viewport.h = sScreenHeight; + setViewport(mViewport); // This is required to avoid a brief white screen flash during startup on some systems. drawRect(0.0f, 0.0f, static_cast(getScreenWidth()), @@ -353,19 +397,20 @@ void Renderer::pushClipRect(const glm::ivec2& pos, const glm::ivec2& size) box.h = sScreenHeight - box.y; if (mScreenRotation == 0) { - box = {mScreenOffsetX + box.x, mScreenOffsetY + box.y, box.w, box.h}; + box = {mScreenOffsetX + box.x + mPaddingWidth, mScreenOffsetY + box.y + mPaddingHeight, + box.w, box.h}; } else if (mScreenRotation == 90) { box = {mScreenOffsetX + mWindowWidth - (box.y + box.h), mScreenOffsetY + box.x, box.h, - box.w}; + box.w + mPaddingHeight}; } else if (mScreenRotation == 270) { - box = {mScreenOffsetX + box.y, mScreenOffsetY + mWindowHeight - (box.x + box.w), box.h, - box.w}; + box = {mScreenOffsetX + box.y + mPaddingWidth, + mScreenOffsetY + mWindowHeight - (box.x + box.w), box.h, box.w}; } else if (mScreenRotation == 180) { - box = {mWindowWidth - mScreenOffsetX - box.x - box.w, - mWindowHeight - mScreenOffsetY - box.y - box.h, box.w, box.h}; + box = {mWindowWidth + mScreenOffsetX - box.x - box.w, + mWindowHeight + mScreenOffsetY - box.y - box.h, box.w, box.h}; } // Make sure the box fits within mClipStack.top(), and clip further accordingly. @@ -400,7 +445,7 @@ void Renderer::popClipRect() mClipStack.pop(); if (mClipStack.empty()) - setScissor(Rect {0, 0, 0, 0}); + setScissor(Rect()); else setScissor(mClipStack.top()); } diff --git a/es-core/src/renderers/Renderer.h b/es-core/src/renderers/Renderer.h index 1a8a3fd9c..e1dd749b2 100644 --- a/es-core/src/renderers/Renderer.h +++ b/es-core/src/renderers/Renderer.h @@ -118,6 +118,19 @@ public: }; struct Rect { + int x; + int y; + int w; + int h; + + Rect() + : x(0) + , y(0) + , w(0) + , h(0) + { + } + Rect(const int xValue, const int yValue, const int wValue, const int hValue) : x(xValue) , y(yValue) @@ -125,10 +138,6 @@ public: , h(hValue) { } - int x; - int y; - int w; - int h; }; static Renderer* getInstance(); @@ -160,8 +169,6 @@ public: const glm::mat4& getProjectionMatrixNormal() { return mProjectionMatrixNormal; } SDL_Window* getSDLWindow() { return mSDLWindow; } const int getScreenRotation() { return mScreenRotation; } - const float getWindowWidth() { return static_cast(mWindowWidth); } - const float getWindowHeight() { return static_cast(mWindowHeight); } static const bool getIsVerticalOrientation() { return sIsVerticalOrientation; } static const float getScreenWidth() { return static_cast(sScreenWidth); } static const float getScreenHeight() { return static_cast(sScreenHeight); } @@ -204,21 +211,28 @@ public: const BlendFactor srcBlendFactor = BlendFactor::ONE, const BlendFactor dstBlendFactor = BlendFactor::ONE_MINUS_SRC_ALPHA) = 0; virtual void setMatrix(const glm::mat4& matrix) = 0; + virtual void setViewport(const Rect& viewport) = 0; virtual void setScissor(const Rect& scissor) = 0; virtual void setSwapInterval() = 0; virtual void swapBuffers() = 0; +protected: + Rect mViewport; + int mWindowWidth {0}; + int mWindowHeight {0}; + int mPaddingWidth {0}; + int mPaddingHeight {0}; + int mScreenOffsetX {0}; + int mScreenOffsetY {0}; + private: std::stack mClipStack; SDL_Window* mSDLWindow {nullptr}; glm::mat4 mProjectionMatrix {}; glm::mat4 mProjectionMatrixNormal {}; - int mWindowWidth {0}; - int mWindowHeight {0}; + static inline int sScreenWidth {0}; static inline int sScreenHeight {0}; - int mScreenOffsetX {0}; - int mScreenOffsetY {0}; int mScreenRotation {0}; bool mInitialCursorState {true}; static inline bool sIsVerticalOrientation {false}; diff --git a/es-core/src/renderers/RendererOpenGL.cpp b/es-core/src/renderers/RendererOpenGL.cpp index 8355c04fb..d60d988f2 100644 --- a/es-core/src/renderers/RendererOpenGL.cpp +++ b/es-core/src/renderers/RendererOpenGL.cpp @@ -228,15 +228,13 @@ bool RendererOpenGL::createContext() LOG(LogInfo) << "GL renderer: " << renderer; LOG(LogInfo) << "GL version: " << version; #if defined(USE_OPENGLES) - LOG(LogInfo) << "EmulationStation renderer: OpenGL ES " << mMajorGLVersion << "." - << mMinorGLVersion; + LOG(LogInfo) << "Application renderer: OpenGL ES " << mMajorGLVersion << "." << mMinorGLVersion; #else #if defined(_WIN64) - LOG(LogInfo) << "EmulationStation renderer: OpenGL " << mMajorGLVersion << "." - << mMinorGLVersion << " with GLEW"; + LOG(LogInfo) << "Application renderer: OpenGL " << mMajorGLVersion << "." << mMinorGLVersion + << " with GLEW"; #else - LOG(LogInfo) << "EmulationStation renderer: OpenGL " << mMajorGLVersion << "." - << mMinorGLVersion; + LOG(LogInfo) << "Application renderer: OpenGL " << mMajorGLVersion << "." << mMinorGLVersion; #endif #endif @@ -326,6 +324,13 @@ void RendererOpenGL::setMatrix(const glm::mat4& matrix) mTrans = getProjectionMatrix() * matrix; } +void RendererOpenGL::setViewport(const Rect& viewport) +{ + // glViewport starts at the bottom left of the window. + GL_CHECK_ERROR( + glViewport(viewport.x, mWindowHeight - viewport.y - viewport.h, viewport.w, viewport.h)); +} + void RendererOpenGL::setScissor(const Rect& scissor) { if ((scissor.x == 0) && (scissor.y == 0) && (scissor.w == 0) && (scissor.h == 0)) { @@ -334,7 +339,7 @@ void RendererOpenGL::setScissor(const Rect& scissor) else { // glScissor starts at the bottom left of the window. GL_CHECK_ERROR(glScissor(scissor.x, - static_cast(getWindowHeight()) - scissor.y - scissor.h, + static_cast(mWindowHeight) - scissor.y - scissor.h, scissor.w, scissor.h)); GL_CHECK_ERROR(glEnable(GL_SCISSOR_TEST)); } @@ -579,6 +584,15 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders, GLuint width {static_cast(widthf)}; GLuint height {static_cast(heightf)}; const int screenRotation {getScreenRotation()}; + const bool offsetOrPadding {mScreenOffsetX != 0 || mScreenOffsetY != 0 || mPaddingWidth != 0 || + mPaddingHeight != 0}; + + if (offsetOrPadding) { + Rect viewportTemp {mViewport}; + viewportTemp.x -= mScreenOffsetX + mPaddingWidth; + viewportTemp.y -= mScreenOffsetY; + setViewport(viewportTemp); + } // Set vertex positions and texture coordinates to full screen as all // post-processing is applied to the complete screen area. @@ -628,15 +642,20 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders, // Blit the screen contents to mPostProcTexture. if (screenRotation == 0) { - GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, - GL_COLOR_BUFFER_BIT, GL_NEAREST)); + GL_CHECK_ERROR(glBlitFramebuffer( + 0, 0, width + mPaddingWidth, height - mScreenOffsetY, -mScreenOffsetX - mPaddingWidth, + mScreenOffsetY, width - mScreenOffsetX, height, GL_COLOR_BUFFER_BIT, GL_NEAREST)); } else if (screenRotation == 90 || screenRotation == 270) { if (!evenBlurPasses || !textureRGBA) - GL_CHECK_ERROR(glBlitFramebuffer(0, 0, height, width, 0, 0, height, width, - GL_COLOR_BUFFER_BIT, GL_NEAREST)); + GL_CHECK_ERROR(glBlitFramebuffer(0, 0, height + mPaddingWidth, width - mScreenOffsetY, + -mScreenOffsetX - mPaddingWidth, mScreenOffsetY, + height - mScreenOffsetX, width, GL_COLOR_BUFFER_BIT, + GL_NEAREST)); else - GL_CHECK_ERROR(glBlitFramebuffer(0, 0, height, width, height, width, 0, 0, + GL_CHECK_ERROR(glBlitFramebuffer(0, 0, height + mPaddingWidth, width - mScreenOffsetY, + height + mScreenOffsetX + mPaddingWidth, + width - mScreenOffsetY, mScreenOffsetX, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST)); // If not rendering to a texture, apply shaders without any rotation applied. if (!textureRGBA) @@ -644,11 +663,15 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders, } else { if ((shaderCalls + (textureRGBA ? 1 : 0)) % 2 == 0) - GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, - GL_COLOR_BUFFER_BIT, GL_NEAREST)); + GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width + mPaddingWidth, height - mScreenOffsetY, + -mScreenOffsetX - mPaddingWidth, mScreenOffsetY, + width - mScreenOffsetX, height, GL_COLOR_BUFFER_BIT, + GL_NEAREST)); else - GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, width, height, 0, 0, - GL_COLOR_BUFFER_BIT, GL_NEAREST)); + GL_CHECK_ERROR(glBlitFramebuffer( + 0, 0, width + mPaddingWidth, height + (mPaddingHeight / 2), + width + mScreenOffsetX + mPaddingWidth, height - mScreenOffsetY, mScreenOffsetX, + -(mPaddingHeight / 2) - mScreenOffsetY, GL_COLOR_BUFFER_BIT, GL_NEAREST)); } if (shaderCalls > 1) @@ -669,6 +692,8 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders, for (int p {0}; p < shaderPasses; ++p) { if (!textureRGBA && i == shaderList.size() - 1 && p == shaderPasses - 1) { GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); + if (offsetOrPadding) + setViewport(mViewport); drawTriangleStrips(vertices, 4, BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA); break; @@ -723,4 +748,7 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders, } GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); + + if (offsetOrPadding) + setViewport(mViewport); } diff --git a/es-core/src/renderers/RendererOpenGL.h b/es-core/src/renderers/RendererOpenGL.h index dc540ad92..8c31afbcf 100644 --- a/es-core/src/renderers/RendererOpenGL.h +++ b/es-core/src/renderers/RendererOpenGL.h @@ -38,6 +38,7 @@ public: void destroyContext() override; void setMatrix(const glm::mat4& matrix) override; + void setViewport(const Rect& viewport) override; void setScissor(const Rect& scissor) override; void setSwapInterval() override; void swapBuffers() override;