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.
This commit is contained in:
Leon Styhre 2023-02-12 22:14:09 +01:00
parent 047ab9111e
commit 5be55d38ed
7 changed files with 213 additions and 125 deletions

View file

@ -601,8 +601,8 @@ void Screensaver::generateOverlayInfo()
if (mGameName == "" || mSystemName == "") if (mGameName == "" || mSystemName == "")
return; return;
float posX {mRenderer->getWindowWidth() * 0.023f}; float posX {mRenderer->getScreenWidth() * 0.023f};
float posY {mRenderer->getWindowHeight() * 0.02f}; float posY {mRenderer->getScreenHeight() * 0.02f};
std::string favoriteChar; std::string favoriteChar;
if (mCurrentGame && mCurrentGame->getFavorite()) if (mCurrentGame && mCurrentGame->getFavorite())
@ -629,7 +629,7 @@ void Screensaver::generateOverlayInfo()
else else
textSizeX = mGameOverlayFont[0].get()->sizeText(systemName).x; textSizeX = mGameOverlayFont[0].get()->sizeText(systemName).x;
float marginX {mRenderer->getWindowWidth() * 0.01f}; float marginX {mRenderer->getScreenWidth() * 0.01f};
mGameOverlayRectangleCoords.clear(); mGameOverlayRectangleCoords.clear();
mGameOverlayRectangleCoords.push_back(posX - marginX); mGameOverlayRectangleCoords.push_back(posX - marginX);

View file

@ -266,17 +266,6 @@ bool parseArgs(int argc, char* argv[])
<< " supplied\n"; << " supplied\n";
return false; 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("ScreenWidth", width);
Settings::getInstance()->setInt("ScreenHeight", height); Settings::getInstance()->setInt("ScreenHeight", height);
i += 2; i += 2;
@ -307,18 +296,34 @@ bool parseArgs(int argc, char* argv[])
settingsNeedSaving = true; settingsNeedSaving = true;
++i; ++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) { else if (strcmp(argv[i], "--vsync") == 0) {
if (i >= argc - 1) { if (i >= argc - 1) {
std::cerr << "Error: No VSync value supplied\n"; std::cerr << "Error: No VSync value supplied\n";
return false; return false;
} }
std::string vSyncValue = argv[i + 1]; std::string vSyncValue {argv[i + 1]};
if (vSyncValue != "on" && vSyncValue != "off" && vSyncValue != "1" && if (vSyncValue != "on" && vSyncValue != "off" && vSyncValue != "1" &&
vSyncValue != "0") { vSyncValue != "0") {
std::cerr << "Error: Invalid VSync value supplied\n"; std::cerr << "Error: Invalid VSync value supplied\n";
return false; return false;
} }
bool vSync {(vSyncValue == "on" || vSyncValue == "1") ? true : false}; const bool vSync {(vSyncValue == "on" || vSyncValue == "1") ? true : false};
Settings::getInstance()->setBool("VSync", vSync); Settings::getInstance()->setBool("VSync", vSync);
++i; ++i;
} }
@ -327,7 +332,7 @@ bool parseArgs(int argc, char* argv[])
std::cerr << "Error: Invalid VRAM value supplied\n"; std::cerr << "Error: Invalid VRAM value supplied\n";
return false; return false;
} }
int maxVRAM {atoi(argv[i + 1])}; const int maxVRAM {atoi(argv[i + 1])};
Settings::getInstance()->setInt("MaxVRAM", maxVRAM); Settings::getInstance()->setInt("MaxVRAM", maxVRAM);
settingsNeedSaving = true; settingsNeedSaving = true;
++i; ++i;
@ -403,7 +408,9 @@ bool parseArgs(int argc, char* argv[])
"Options:\n" "Options:\n"
" --display [1 to 4] Display/monitor to use\n" " --display [1 to 4] Display/monitor to use\n"
" --resolution [width] [height] Application resolution\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" " --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" " --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" " --max-vram [size] Max VRAM to use (in mebibytes) before swapping\n"
#if !defined(USE_OPENGLES) #if !defined(USE_OPENGLES)
@ -411,7 +418,7 @@ bool parseArgs(int argc, char* argv[])
#endif #endif
" --no-splash Don't show the splash screen during startup\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" " --gamelist-only Skip automatic game ROM search, only read from gamelist.xml\n"
" --ignore-gamelist Ignore the gamelist.xml files (useful for troubleshooting)\n" " --ignore-gamelist Ignore the gamelist.xml files\n"
" --show-hidden-files Show hidden files and folders\n" " --show-hidden-files Show hidden files and folders\n"
" --show-hidden-games Show hidden games\n" " --show-hidden-games Show hidden games\n"
" --force-full Force the UI mode to Full\n" " --force-full Force the UI mode to Full\n"
@ -601,8 +608,8 @@ int main(int argc, char* argv[])
// TODO: Remove when application window resizing has been implemented. // TODO: Remove when application window resizing has been implemented.
Settings::getInstance()->setBool("Debug", true); Settings::getInstance()->setBool("Debug", true);
Log::setReportingLevel(LogDebug); Log::setReportingLevel(LogDebug);
Settings::getInstance()->setInt("WindowWidth", 1280); Settings::getInstance()->setInt("ScreenWidth", 1280);
Settings::getInstance()->setInt("WindowHeight", 720); Settings::getInstance()->setInt("ScreenHeight", 720);
#endif #endif
// Check if the configuration file exists, and if not, create it. // Check if the configuration file exists, and if not, create it.
@ -613,7 +620,7 @@ int main(int argc, char* argv[])
Settings::getInstance()->saveFile(); Settings::getInstance()->saveFile();
} }
else if (settingsNeedSaving) { 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(); Settings::getInstance()->saveFile();
} }

View file

@ -26,22 +26,18 @@ namespace
std::vector<std::string> settingsSkipSaving { std::vector<std::string> settingsSkipSaving {
// clang-format off // clang-format off
// These options can be set using command-line arguments: // These options can be set using command-line arguments:
"WindowWidth", // Set via --resolution [width] [height] "ScreenWidth", // Set via --resolution [width] [height]
"WindowHeight", // 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 "IgnoreGamelist", // --ignore-gamelist
"SplashScreen", // --no-splash "SplashScreen", // --no-splash
"Debug", // --debug
"VSync", // --vsync [1/on or 0/off]
"ForceFull", // --force-full "ForceFull", // --force-full
"ForceKiosk", // --force-kiosk "ForceKiosk", // --force-kiosk
"ForceKid", // --force-kid "ForceKid", // --force-kid
"Debug", // --debug
// 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]
// These options are only used internally during the application session: // These options are only used internally during the application session:
"DebugGrid", "DebugGrid",
@ -137,7 +133,7 @@ void Settings::setDefaults()
mStringMap["ScraperRegion"] = {"eu", "eu"}; mStringMap["ScraperRegion"] = {"eu", "eu"};
mStringMap["ScraperLanguage"] = {"en", "en"}; mStringMap["ScraperLanguage"] = {"en", "en"};
mIntMap["ScraperRetryOnErrorCount"] = {3, 3}; mIntMap["ScraperRetryOnErrorCount"] = {5, 5};
mIntMap["ScraperRetryOnErrorTimer"] = {3, 3}; mIntMap["ScraperRetryOnErrorTimer"] = {3, 3};
mBoolMap["ScraperOverwriteData"] = {true, true}; mBoolMap["ScraperOverwriteData"] = {true, true};
mBoolMap["ScraperHaltOnInvalidMedia"] = {true, true}; mBoolMap["ScraperHaltOnInvalidMedia"] = {true, true};
@ -297,11 +293,8 @@ void Settings::setDefaults()
mBoolMap["IgnoreGamelist"] = {false, false}; mBoolMap["IgnoreGamelist"] = {false, false};
mBoolMap["SplashScreen"] = {true, true}; mBoolMap["SplashScreen"] = {true, true};
mBoolMap["VSync"] = {true, true}; mBoolMap["VSync"] = {true, true};
mIntMap["WindowWidth"] = {0, 0}; mBoolMap["FullscreenPadding"] = {false, false};
mIntMap["WindowHeight"] = {0, 0};
mIntMap["ScreenWidth"] = {0, 0}; mIntMap["ScreenWidth"] = {0, 0};
// Undocumented options.
mIntMap["ScreenHeight"] = {0, 0}; mIntMap["ScreenHeight"] = {0, 0};
mIntMap["ScreenOffsetX"] = {0, 0}; mIntMap["ScreenOffsetX"] = {0, 0};
mIntMap["ScreenOffsetY"] = {0, 0}; mIntMap["ScreenOffsetY"] = {0, 0};

View file

@ -101,26 +101,50 @@ bool Renderer::createWindow()
displayMode.h = displayBounds.h; displayMode.h = displayBounds.h;
#endif #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") ? sScreenWidth = Settings::getInstance()->getInt("ScreenWidth") ?
Settings::getInstance()->getInt("ScreenWidth") : Settings::getInstance()->getInt("ScreenWidth") :
mWindowWidth; displayMode.w;
sScreenHeight = Settings::getInstance()->getInt("ScreenHeight") ? sScreenHeight = Settings::getInstance()->getInt("ScreenHeight") ?
Settings::getInstance()->getInt("ScreenHeight") : Settings::getInstance()->getInt("ScreenHeight") :
mWindowHeight; displayMode.h;
mScreenOffsetX = Settings::getInstance()->getInt("ScreenOffsetX") ? mScreenOffsetX = glm::clamp((Settings::getInstance()->getInt("ScreenOffsetX") ?
Settings::getInstance()->getInt("ScreenOffsetX") : Settings::getInstance()->getInt("ScreenOffsetX") :
0; 0),
mScreenOffsetY = Settings::getInstance()->getInt("ScreenOffsetY") ? -(displayMode.w / 2), displayMode.w / 2);
mScreenOffsetY = glm::clamp((Settings::getInstance()->getInt("ScreenOffsetY") ?
Settings::getInstance()->getInt("ScreenOffsetY") : Settings::getInstance()->getInt("ScreenOffsetY") :
0; 0),
-(displayMode.w / 2), displayMode.h / 2);
mScreenRotation = Settings::getInstance()->getInt("ScreenRotate"); 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. // In case someone manually added an invalid value to es_settings.xml.
if (mScreenRotation != 0 && mScreenRotation != 90 && mScreenRotation != 180 && if (mScreenRotation != 0 && mScreenRotation != 90 && mScreenRotation != 180 &&
mScreenRotation != 270) { mScreenRotation != 270) {
@ -158,7 +182,7 @@ bool Renderer::createWindow()
SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"); SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
#endif #endif
bool userResolution = false; bool userResolution {false};
// Check if the user has changed the resolution from the command line. // Check if the user has changed the resolution from the command line.
if (mWindowWidth != displayMode.w || mWindowHeight != displayMode.h) if (mWindowWidth != displayMode.w || mWindowHeight != displayMode.h)
userResolution = true; userResolution = true;
@ -219,17 +243,17 @@ bool Renderer::createWindow()
// display so that the full application window is used for rendering. // display so that the full application window is used for rendering.
int width {0}; int width {0};
SDL_GL_GetDrawableSize(mSDLWindow, &width, nullptr); SDL_GL_GetDrawableSize(mSDLWindow, &width, nullptr);
int scaleFactor = static_cast<int>(width / mWindowWidth); int scaleFactor {static_cast<int>(width / sScreenWidth)};
LOG(LogInfo) << "Display resolution: " << std::to_string(displayMode.w) << "x" LOG(LogInfo) << "Display resolution: " << std::to_string(displayMode.w) << "x"
<< std::to_string(displayMode.h) << " (physical resolution " << std::to_string(displayMode.h) << " (physical resolution "
<< std::to_string(displayMode.w * scaleFactor) << "x" << std::to_string(displayMode.w * scaleFactor) << "x"
<< std::to_string(displayMode.h * scaleFactor) << ")"; << std::to_string(displayMode.h * scaleFactor) << ")";
LOG(LogInfo) << "Display refresh rate: " << std::to_string(displayMode.refresh_rate) << " Hz"; LOG(LogInfo) << "Display refresh rate: " << std::to_string(displayMode.refresh_rate) << " Hz";
LOG(LogInfo) << "EmulationStation resolution: " << std::to_string(mWindowWidth) << "x" LOG(LogInfo) << "Application resolution: " << std::to_string(sScreenWidth) << "x"
<< std::to_string(mWindowHeight) << " (physical resolution " << std::to_string(sScreenHeight) << " (physical resolution "
<< std::to_string(mWindowWidth * scaleFactor) << "x" << std::to_string(sScreenWidth * scaleFactor) << "x"
<< std::to_string(mWindowHeight * scaleFactor) << ")"; << std::to_string(sScreenHeight * scaleFactor) << ")";
mWindowWidth *= scaleFactor; mWindowWidth *= scaleFactor;
mWindowHeight *= scaleFactor; mWindowHeight *= scaleFactor;
@ -239,8 +263,8 @@ bool Renderer::createWindow()
LOG(LogInfo) << "Display resolution: " << std::to_string(displayMode.w) << "x" LOG(LogInfo) << "Display resolution: " << std::to_string(displayMode.w) << "x"
<< std::to_string(displayMode.h); << std::to_string(displayMode.h);
LOG(LogInfo) << "Display refresh rate: " << std::to_string(displayMode.refresh_rate) << " Hz"; LOG(LogInfo) << "Display refresh rate: " << std::to_string(displayMode.refresh_rate) << " Hz";
LOG(LogInfo) << "EmulationStation resolution: " << std::to_string(mWindowWidth) << "x" LOG(LogInfo) << "Application resolution: " << std::to_string(sScreenWidth) << "x"
<< std::to_string(mWindowHeight); << std::to_string(sScreenHeight);
#endif #endif
sScreenHeightModifier = static_cast<float>(sScreenHeight) / 1080.0f; sScreenHeightModifier = static_cast<float>(sScreenHeight) / 1080.0f;
@ -252,6 +276,23 @@ bool Renderer::createWindow()
else else
sScreenResolutionModifier = sScreenHeight / 1080.0f; 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..."; LOG(LogInfo) << "Setting up OpenGL...";
if (!createContext()) if (!createContext())
@ -287,27 +328,30 @@ bool Renderer::init()
return false; return false;
glm::mat4 projection {getIdentity()}; 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<float>(sScreenHeight),
static_cast<float>(sScreenWidth), 0.0f, -1.0f, 1.0f);
if (mScreenRotation == 0) { 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<float>(sScreenWidth), mProjectionMatrix = glm::ortho(0.0f, static_cast<float>(sScreenWidth),
static_cast<float>(sScreenHeight), 0.0f, -1.0f, 1.0f); static_cast<float>(sScreenHeight), 0.0f, -1.0f, 1.0f);
} }
else if (mScreenRotation == 90) { 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<float>(sScreenHeight), projection = glm::ortho(0.0f, static_cast<float>(sScreenHeight),
static_cast<float>(sScreenWidth), 0.0f, -1.0f, 1.0f); static_cast<float>(sScreenWidth), 0.0f, -1.0f, 1.0f);
projection = glm::rotate(projection, glm::radians(90.0f), {0.0f, 0.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}); mProjectionMatrix = glm::translate(projection, {0.0f, sScreenHeight * -1.0f, 0.0f});
} }
else if (mScreenRotation == 180) { 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<float>(sScreenWidth), projection = glm::ortho(0.0f, static_cast<float>(sScreenWidth),
static_cast<float>(sScreenHeight), 0.0f, -1.0f, 1.0f); static_cast<float>(sScreenHeight), 0.0f, -1.0f, 1.0f);
projection = glm::rotate(projection, glm::radians(180.0f), {0.0f, 0.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}); glm::translate(projection, {sScreenWidth * -1.0f, sScreenHeight * -1.0f, 0.0f});
} }
else if (mScreenRotation == 270) { 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<float>(sScreenHeight), projection = glm::ortho(0.0f, static_cast<float>(sScreenHeight),
static_cast<float>(sScreenWidth), 0.0f, -1.0f, 1.0f); static_cast<float>(sScreenWidth), 0.0f, -1.0f, 1.0f);
projection = glm::rotate(projection, glm::radians(270.0f), {0.0f, 0.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<float>(sScreenWidth), mProjectionMatrixNormal = glm::ortho(0.0f, static_cast<float>(sScreenWidth),
static_cast<float>(sScreenHeight), 0.0f, -1.0f, 1.0f); static_cast<float>(sScreenHeight), 0.0f, -1.0f, 1.0f);
setViewport(mViewport);
viewport.x = mScreenOffsetX;
viewport.y = mScreenOffsetY;
viewport.w = sScreenWidth;
viewport.h = sScreenHeight;
// This is required to avoid a brief white screen flash during startup on some systems. // This is required to avoid a brief white screen flash during startup on some systems.
drawRect(0.0f, 0.0f, static_cast<float>(getScreenWidth()), drawRect(0.0f, 0.0f, static_cast<float>(getScreenWidth()),
@ -353,19 +397,20 @@ void Renderer::pushClipRect(const glm::ivec2& pos, const glm::ivec2& size)
box.h = sScreenHeight - box.y; box.h = sScreenHeight - box.y;
if (mScreenRotation == 0) { 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) { else if (mScreenRotation == 90) {
box = {mScreenOffsetX + mWindowWidth - (box.y + box.h), mScreenOffsetY + box.x, box.h, box = {mScreenOffsetX + mWindowWidth - (box.y + box.h), mScreenOffsetY + box.x, box.h,
box.w}; box.w + mPaddingHeight};
} }
else if (mScreenRotation == 270) { else if (mScreenRotation == 270) {
box = {mScreenOffsetX + box.y, mScreenOffsetY + mWindowHeight - (box.x + box.w), box.h, box = {mScreenOffsetX + box.y + mPaddingWidth,
box.w}; mScreenOffsetY + mWindowHeight - (box.x + box.w), box.h, box.w};
} }
else if (mScreenRotation == 180) { else if (mScreenRotation == 180) {
box = {mWindowWidth - mScreenOffsetX - box.x - box.w, box = {mWindowWidth + mScreenOffsetX - box.x - box.w,
mWindowHeight - mScreenOffsetY - box.y - box.h, box.w, box.h}; mWindowHeight + mScreenOffsetY - box.y - box.h, box.w, box.h};
} }
// Make sure the box fits within mClipStack.top(), and clip further accordingly. // Make sure the box fits within mClipStack.top(), and clip further accordingly.
@ -400,7 +445,7 @@ void Renderer::popClipRect()
mClipStack.pop(); mClipStack.pop();
if (mClipStack.empty()) if (mClipStack.empty())
setScissor(Rect {0, 0, 0, 0}); setScissor(Rect());
else else
setScissor(mClipStack.top()); setScissor(mClipStack.top());
} }

View file

@ -118,6 +118,19 @@ public:
}; };
struct Rect { 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) Rect(const int xValue, const int yValue, const int wValue, const int hValue)
: x(xValue) : x(xValue)
, y(yValue) , y(yValue)
@ -125,10 +138,6 @@ public:
, h(hValue) , h(hValue)
{ {
} }
int x;
int y;
int w;
int h;
}; };
static Renderer* getInstance(); static Renderer* getInstance();
@ -160,8 +169,6 @@ public:
const glm::mat4& getProjectionMatrixNormal() { return mProjectionMatrixNormal; } const glm::mat4& getProjectionMatrixNormal() { return mProjectionMatrixNormal; }
SDL_Window* getSDLWindow() { return mSDLWindow; } SDL_Window* getSDLWindow() { return mSDLWindow; }
const int getScreenRotation() { return mScreenRotation; } const int getScreenRotation() { return mScreenRotation; }
const float getWindowWidth() { return static_cast<float>(mWindowWidth); }
const float getWindowHeight() { return static_cast<float>(mWindowHeight); }
static const bool getIsVerticalOrientation() { return sIsVerticalOrientation; } static const bool getIsVerticalOrientation() { return sIsVerticalOrientation; }
static const float getScreenWidth() { return static_cast<float>(sScreenWidth); } static const float getScreenWidth() { return static_cast<float>(sScreenWidth); }
static const float getScreenHeight() { return static_cast<float>(sScreenHeight); } static const float getScreenHeight() { return static_cast<float>(sScreenHeight); }
@ -204,21 +211,28 @@ public:
const BlendFactor srcBlendFactor = BlendFactor::ONE, const BlendFactor srcBlendFactor = BlendFactor::ONE,
const BlendFactor dstBlendFactor = BlendFactor::ONE_MINUS_SRC_ALPHA) = 0; const BlendFactor dstBlendFactor = BlendFactor::ONE_MINUS_SRC_ALPHA) = 0;
virtual void setMatrix(const glm::mat4& matrix) = 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 setScissor(const Rect& scissor) = 0;
virtual void setSwapInterval() = 0; virtual void setSwapInterval() = 0;
virtual void swapBuffers() = 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: private:
std::stack<Rect> mClipStack; std::stack<Rect> mClipStack;
SDL_Window* mSDLWindow {nullptr}; SDL_Window* mSDLWindow {nullptr};
glm::mat4 mProjectionMatrix {}; glm::mat4 mProjectionMatrix {};
glm::mat4 mProjectionMatrixNormal {}; glm::mat4 mProjectionMatrixNormal {};
int mWindowWidth {0};
int mWindowHeight {0};
static inline int sScreenWidth {0}; static inline int sScreenWidth {0};
static inline int sScreenHeight {0}; static inline int sScreenHeight {0};
int mScreenOffsetX {0};
int mScreenOffsetY {0};
int mScreenRotation {0}; int mScreenRotation {0};
bool mInitialCursorState {true}; bool mInitialCursorState {true};
static inline bool sIsVerticalOrientation {false}; static inline bool sIsVerticalOrientation {false};

View file

@ -228,15 +228,13 @@ bool RendererOpenGL::createContext()
LOG(LogInfo) << "GL renderer: " << renderer; LOG(LogInfo) << "GL renderer: " << renderer;
LOG(LogInfo) << "GL version: " << version; LOG(LogInfo) << "GL version: " << version;
#if defined(USE_OPENGLES) #if defined(USE_OPENGLES)
LOG(LogInfo) << "EmulationStation renderer: OpenGL ES " << mMajorGLVersion << "." LOG(LogInfo) << "Application renderer: OpenGL ES " << mMajorGLVersion << "." << mMinorGLVersion;
<< mMinorGLVersion;
#else #else
#if defined(_WIN64) #if defined(_WIN64)
LOG(LogInfo) << "EmulationStation renderer: OpenGL " << mMajorGLVersion << "." LOG(LogInfo) << "Application renderer: OpenGL " << mMajorGLVersion << "." << mMinorGLVersion
<< mMinorGLVersion << " with GLEW"; << " with GLEW";
#else #else
LOG(LogInfo) << "EmulationStation renderer: OpenGL " << mMajorGLVersion << "." LOG(LogInfo) << "Application renderer: OpenGL " << mMajorGLVersion << "." << mMinorGLVersion;
<< mMinorGLVersion;
#endif #endif
#endif #endif
@ -326,6 +324,13 @@ void RendererOpenGL::setMatrix(const glm::mat4& matrix)
mTrans = getProjectionMatrix() * 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) void RendererOpenGL::setScissor(const Rect& scissor)
{ {
if ((scissor.x == 0) && (scissor.y == 0) && (scissor.w == 0) && (scissor.h == 0)) { if ((scissor.x == 0) && (scissor.y == 0) && (scissor.w == 0) && (scissor.h == 0)) {
@ -334,7 +339,7 @@ void RendererOpenGL::setScissor(const Rect& scissor)
else { else {
// glScissor starts at the bottom left of the window. // glScissor starts at the bottom left of the window.
GL_CHECK_ERROR(glScissor(scissor.x, GL_CHECK_ERROR(glScissor(scissor.x,
static_cast<GLint>(getWindowHeight()) - scissor.y - scissor.h, static_cast<GLint>(mWindowHeight) - scissor.y - scissor.h,
scissor.w, scissor.h)); scissor.w, scissor.h));
GL_CHECK_ERROR(glEnable(GL_SCISSOR_TEST)); GL_CHECK_ERROR(glEnable(GL_SCISSOR_TEST));
} }
@ -579,6 +584,15 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
GLuint width {static_cast<GLuint>(widthf)}; GLuint width {static_cast<GLuint>(widthf)};
GLuint height {static_cast<GLuint>(heightf)}; GLuint height {static_cast<GLuint>(heightf)};
const int screenRotation {getScreenRotation()}; 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 // Set vertex positions and texture coordinates to full screen as all
// post-processing is applied to the complete screen area. // 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. // Blit the screen contents to mPostProcTexture.
if (screenRotation == 0) { if (screenRotation == 0) {
GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_CHECK_ERROR(glBlitFramebuffer(
GL_COLOR_BUFFER_BIT, GL_NEAREST)); 0, 0, width + mPaddingWidth, height - mScreenOffsetY, -mScreenOffsetX - mPaddingWidth,
mScreenOffsetY, width - mScreenOffsetX, height, GL_COLOR_BUFFER_BIT, GL_NEAREST));
} }
else if (screenRotation == 90 || screenRotation == 270) { else if (screenRotation == 90 || screenRotation == 270) {
if (!evenBlurPasses || !textureRGBA) if (!evenBlurPasses || !textureRGBA)
GL_CHECK_ERROR(glBlitFramebuffer(0, 0, height, width, 0, 0, height, width, GL_CHECK_ERROR(glBlitFramebuffer(0, 0, height + mPaddingWidth, width - mScreenOffsetY,
GL_COLOR_BUFFER_BIT, GL_NEAREST)); -mScreenOffsetX - mPaddingWidth, mScreenOffsetY,
height - mScreenOffsetX, width, GL_COLOR_BUFFER_BIT,
GL_NEAREST));
else 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)); GL_COLOR_BUFFER_BIT, GL_NEAREST));
// If not rendering to a texture, apply shaders without any rotation applied. // If not rendering to a texture, apply shaders without any rotation applied.
if (!textureRGBA) if (!textureRGBA)
@ -644,11 +663,15 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
} }
else { else {
if ((shaderCalls + (textureRGBA ? 1 : 0)) % 2 == 0) if ((shaderCalls + (textureRGBA ? 1 : 0)) % 2 == 0)
GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width + mPaddingWidth, height - mScreenOffsetY,
GL_COLOR_BUFFER_BIT, GL_NEAREST)); -mScreenOffsetX - mPaddingWidth, mScreenOffsetY,
width - mScreenOffsetX, height, GL_COLOR_BUFFER_BIT,
GL_NEAREST));
else else
GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, width, height, 0, 0, GL_CHECK_ERROR(glBlitFramebuffer(
GL_COLOR_BUFFER_BIT, GL_NEAREST)); 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) if (shaderCalls > 1)
@ -669,6 +692,8 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
for (int p {0}; p < shaderPasses; ++p) { for (int p {0}; p < shaderPasses; ++p) {
if (!textureRGBA && i == shaderList.size() - 1 && p == shaderPasses - 1) { if (!textureRGBA && i == shaderList.size() - 1 && p == shaderPasses - 1) {
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
if (offsetOrPadding)
setViewport(mViewport);
drawTriangleStrips(vertices, 4, BlendFactor::SRC_ALPHA, drawTriangleStrips(vertices, 4, BlendFactor::SRC_ALPHA,
BlendFactor::ONE_MINUS_SRC_ALPHA); BlendFactor::ONE_MINUS_SRC_ALPHA);
break; break;
@ -723,4 +748,7 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
} }
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0));
if (offsetOrPadding)
setViewport(mViewport);
} }

View file

@ -38,6 +38,7 @@ public:
void destroyContext() override; void destroyContext() override;
void setMatrix(const glm::mat4& matrix) override; void setMatrix(const glm::mat4& matrix) override;
void setViewport(const Rect& viewport) override;
void setScissor(const Rect& scissor) override; void setScissor(const Rect& scissor) override;
void setSwapInterval() override; void setSwapInterval() override;
void swapBuffers() override; void swapBuffers() override;