Added support for rotating the application screen contents 0, 90, 180 or 270 degrees.

Also improved post processing shader rendering when running in vertical orientation.
This commit is contained in:
Leon Styhre 2023-02-06 23:38:35 +01:00
parent b3c997600c
commit b33c7603bb
13 changed files with 304 additions and 123 deletions

View file

@ -71,21 +71,21 @@ void MediaViewer::render(const glm::mat4& /*parentTrans*/)
shaders = Renderer::Shader::SCANLINES;
if (Settings::getInstance()->getBool("MediaViewerVideoBlur")) {
shaders |= Renderer::Shader::BLUR_HORIZONTAL;
float heightModifier {Renderer::getScreenHeightModifier()};
const float resolutionModifier {mRenderer->getScreenResolutionModifier()};
// clang-format off
if (heightModifier < 1)
if (resolutionModifier < 1)
videoParameters.blurPasses = 2; // Below 1080
else if (heightModifier >= 4)
else if (resolutionModifier >= 4)
videoParameters.blurPasses = 12; // 8K
else if (heightModifier >= 2.9)
else if (resolutionModifier >= 2.9)
videoParameters.blurPasses = 10; // 6K
else if (heightModifier >= 2.6)
else if (resolutionModifier >= 2.6)
videoParameters.blurPasses = 8; // 5K
else if (heightModifier >= 2)
else if (resolutionModifier >= 2)
videoParameters.blurPasses = 5; // 4K
else if (heightModifier >= 1.3)
else if (resolutionModifier >= 1.3)
videoParameters.blurPasses = 3; // 1440
else if (heightModifier >= 1)
else if (resolutionModifier >= 1)
videoParameters.blurPasses = 2; // 1080
// clang-format on
}

View file

@ -327,21 +327,21 @@ void Screensaver::renderScreensaver()
shaders = Renderer::Shader::SCANLINES;
if (Settings::getInstance()->getBool("ScreensaverVideoBlur")) {
shaders |= Renderer::Shader::BLUR_HORIZONTAL;
float heightModifier {Renderer::getScreenHeightModifier()};
const float resolutionModifier {mRenderer->getScreenResolutionModifier()};
// clang-format off
if (heightModifier < 1)
if (resolutionModifier < 1)
videoParameters.blurPasses = 2; // Below 1080
else if (heightModifier >= 4)
else if (resolutionModifier >= 4)
videoParameters.blurPasses = 12; // 8K
else if (heightModifier >= 2.9)
else if (resolutionModifier >= 2.9)
videoParameters.blurPasses = 10; // 6K
else if (heightModifier >= 2.6)
else if (resolutionModifier >= 2.6)
videoParameters.blurPasses = 8; // 5K
else if (heightModifier >= 2)
else if (resolutionModifier >= 2)
videoParameters.blurPasses = 5; // 4K
else if (heightModifier >= 1.3)
else if (resolutionModifier >= 1.3)
videoParameters.blurPasses = 3; // 1440
else if (heightModifier >= 1)
else if (resolutionModifier >= 1)
videoParameters.blurPasses = 2; // 1080
// clang-format on
}

View file

@ -1303,6 +1303,29 @@ void GuiMenu::openOtherOptions()
}
});
// Screen contents rotation.
auto screenRotate =
std::make_shared<OptionListComponent<std::string>>(getHelpStyle(), "ROTATE SCREEN", false);
const std::string& selectedScreenRotate {
std::to_string(Settings::getInstance()->getInt("ScreenRotate"))};
screenRotate->add("DISABLED", "0", selectedScreenRotate == "0");
screenRotate->add("90 DEGREES", "90", selectedScreenRotate == "90");
screenRotate->add("180 DEGREES", "180", selectedScreenRotate == "180");
screenRotate->add("270 DEGREES", "270", selectedScreenRotate == "270");
// If there are no objects returned, then there must be a manually modified entry in the
// configuration file. Simply set screen rotation to "0" in this case.
if (screenRotate->getSelectedObjects().size() == 0)
screenRotate->selectEntry(0);
s->addWithLabel("ROTATE SCREEN (REQUIRES RESTART)", screenRotate);
s->addSaveFunc([screenRotate, s] {
if (screenRotate->getSelected() !=
std::to_string(Settings::getInstance()->getInt("ScreenRotate"))) {
Settings::getInstance()->setInt("ScreenRotate",
atoi(screenRotate->getSelected().c_str()));
s->setNeedsSaving();
}
});
// Keyboard quit shortcut.
auto keyboardQuitShortcut = std::make_shared<OptionListComponent<std::string>>(
getHelpStyle(), "KEYBOARD QUIT SHORTCUT", false);

View file

@ -297,14 +297,14 @@ bool parseArgs(int argc, char* argv[])
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") {
const std::string rotateValue {argv[i + 1]};
if (rotateValue != "0" && rotateValue != "90" && rotateValue != "180" &&
rotateValue != "270") {
std::cerr << "Error: Invalid screenrotate value supplied\n";
return false;
}
bool screenRotate {(rotateValue == "on" || rotateValue == "1") ? true : false};
Settings::getInstance()->setBool("ScreenRotate", screenRotate);
Settings::getInstance()->setInt("ScreenRotate", atoi(argv[i + 1]));
settingsNeedSaving = true;
++i;
}
else if (strcmp(argv[i], "--vsync") == 0) {
@ -401,28 +401,28 @@ bool parseArgs(int argc, char* argv[])
"Usage: emulationstation [options]\n"
"EmulationStation Desktop Edition, Emulator Frontend\n\n"
"Options:\n"
" --display [index 1-4] Display/monitor to use\n"
" --resolution [width] [height] Application resolution\n"
" --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"
" --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"
#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 device\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 (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";
// clang-format on
return false; // Exit after printing help.
}

View file

@ -31,7 +31,6 @@ namespace
"IgnoreGamelist", // --ignore-gamelist
"SplashScreen", // --no-splash
"Debug", // --debug
"ScreenRotate", // --screenrotate [1/on or 0/off]
"VSync", // --vsync [1/on or 0/off]
"ForceFull", // --force-full
"ForceKiosk", // --force-kiosk
@ -246,10 +245,11 @@ void Settings::setDefaults()
#else
mIntMap["MaxVRAM"] = {512, 512};
#endif
mIntMap["DisplayIndex"] = {1, 1};
#if !defined(USE_OPENGLES)
mIntMap["AntiAliasing"] = {0, 0};
#endif
mIntMap["DisplayIndex"] = {1, 1};
mIntMap["ScreenRotate"] = {0, 0};
#if defined(__APPLE__)
mStringMap["KeyboardQuitShortcut"] = {"CmdQ", "CmdQ"};
#else
@ -295,7 +295,6 @@ void Settings::setDefaults()
mBoolMap["ForceKiosk"] = {false, false};
mBoolMap["IgnoreGamelist"] = {false, false};
mBoolMap["SplashScreen"] = {true, true};
mBoolMap["ScreenRotate"] = {false, false};
mBoolMap["VSync"] = {true, true};
mIntMap["WindowWidth"] = {0, 0};
mIntMap["WindowHeight"] = {0, 0};

View file

@ -160,7 +160,7 @@ bool Window::init()
progressBarRect.color = DEFAULT_TEXTCOLOR;
mProgressBarRectangles.emplace_back(progressBarRect);
const float borderThickness {std::ceil(2.0f * mRenderer->getScreenHeightModifier())};
const float borderThickness {std::ceil(2.0f * mRenderer->getScreenResolutionModifier())};
progressBarRect.barWidth -= borderThickness * 2.0f;
progressBarRect.barHeight -= borderThickness * 2.0f;
@ -502,21 +502,21 @@ void Window::render()
Renderer::postProcessingParams backgroundParameters;
if (Settings::getInstance()->getBool("MenuBlurBackground")) {
float heightModifier {mRenderer->getScreenHeightModifier()};
const float resolutionModifier {mRenderer->getScreenResolutionModifier()};
// clang-format off
if (heightModifier < 1)
if (resolutionModifier < 1)
backgroundParameters.blurPasses = 2; // Below 1080
else if (heightModifier >= 4)
else if (resolutionModifier >= 4)
backgroundParameters.blurPasses = 12; // 8K
else if (heightModifier >= 2.9)
else if (resolutionModifier >= 2.9)
backgroundParameters.blurPasses = 10; // 6K
else if (heightModifier >= 2.6)
else if (resolutionModifier >= 2.6)
backgroundParameters.blurPasses = 8; // 5K
else if (heightModifier >= 2)
else if (resolutionModifier >= 2)
backgroundParameters.blurPasses = 5; // 4K
else if (heightModifier >= 1.3)
else if (resolutionModifier >= 1.3)
backgroundParameters.blurPasses = 3; // 1440
else if (heightModifier >= 1)
else if (resolutionModifier >= 1)
backgroundParameters.blurPasses = 2; // 1080
// clang-format on
@ -535,9 +535,16 @@ void Window::render()
&processedTexture[0]);
}
mPostprocessedBackground->initFromPixels(
&processedTexture[0], static_cast<size_t>(mRenderer->getScreenWidth()),
static_cast<size_t>(mRenderer->getScreenHeight()));
if (mRenderer->getScreenRotation() == 0 || mRenderer->getScreenRotation() == 180) {
mPostprocessedBackground->initFromPixels(
&processedTexture[0], static_cast<size_t>(mRenderer->getScreenWidth()),
static_cast<size_t>(mRenderer->getScreenHeight()));
}
else {
mPostprocessedBackground->initFromPixels(
&processedTexture[0], static_cast<size_t>(mRenderer->getScreenHeight()),
static_cast<size_t>(mRenderer->getScreenWidth()));
}
mBackgroundOverlay->setImage(mPostprocessedBackground);

View file

@ -119,7 +119,30 @@ bool Renderer::createWindow()
mScreenOffsetY = Settings::getInstance()->getInt("ScreenOffsetY") ?
Settings::getInstance()->getInt("ScreenOffsetY") :
0;
mScreenRotated = Settings::getInstance()->getBool("ScreenRotate");
mScreenRotation = Settings::getInstance()->getInt("ScreenRotate");
// In case someone manually added an invalid value to es_settings.xml.
if (mScreenRotation != 0 && mScreenRotation != 90 && mScreenRotation != 180 &&
mScreenRotation != 270) {
LOG(LogWarning) << "Invalid screen rotation value " << mScreenRotation
<< " defined, changing it to 0/disabled";
mScreenRotation = 0;
}
LOG(LogInfo) << "Screen rotation: "
<< (mScreenRotation == 0 ? "disabled" :
std::to_string(mScreenRotation) + " degrees");
if (mScreenRotation == 90 || mScreenRotation == 270) {
const int tempVal {sScreenWidth};
sScreenWidth = sScreenHeight;
sScreenHeight = tempVal;
}
if (sScreenHeight > sScreenWidth)
sIsVerticalOrientation = true;
else
sIsVerticalOrientation = false;
// Prevent the application window from minimizing when switching windows (when launching
// games or when manually switching windows using the task switcher).
@ -224,6 +247,11 @@ bool Renderer::createWindow()
sScreenWidthModifier = static_cast<float>(sScreenWidth) / 1920.0f;
sScreenAspectRatio = static_cast<float>(sScreenWidth) / static_cast<float>(sScreenHeight);
if (sIsVerticalOrientation)
sScreenResolutionModifier = sScreenWidth / 1080.0f;
else
sScreenResolutionModifier = sScreenHeight / 1080.0f;
LOG(LogInfo) << "Setting up OpenGL...";
if (!createContext())
@ -265,18 +293,41 @@ bool Renderer::init()
viewport.y = mWindowHeight - mScreenOffsetY - sScreenHeight;
viewport.w = sScreenWidth;
viewport.h = sScreenHeight;
projection = glm::ortho(0.0f, static_cast<float>(sScreenWidth),
static_cast<float>(sScreenHeight), 0.0f, -1.0f, 1.0f);
projection = glm::rotate(projection, glm::radians(180.0f), {0.0f, 0.0f, 1.0f});
mProjectionMatrixRotated =
glm::translate(projection, {sScreenWidth * -1.0f, sScreenHeight * -1.0f, 0.0f});
projection = glm::ortho(0.0f, static_cast<float>(sScreenHeight),
static_cast<float>(sScreenWidth), 0.0f, -1.0f, 1.0f);
if (mScreenRotation == 0) {
mProjectionMatrix = glm::ortho(0.0f, static_cast<float>(sScreenWidth),
static_cast<float>(sScreenHeight), 0.0f, -1.0f, 1.0f);
}
else if (mScreenRotation == 90) {
projection = glm::ortho(0.0f, static_cast<float>(sScreenHeight),
static_cast<float>(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) {
projection = glm::ortho(0.0f, static_cast<float>(sScreenWidth),
static_cast<float>(sScreenHeight), 0.0f, -1.0f, 1.0f);
projection = glm::rotate(projection, glm::radians(180.0f), {0.0f, 0.0f, 1.0f});
mProjectionMatrix =
glm::translate(projection, {sScreenWidth * -1.0f, sScreenHeight * -1.0f, 0.0f});
}
else if (mScreenRotation == 270) {
projection = glm::ortho(0.0f, static_cast<float>(sScreenHeight),
static_cast<float>(sScreenWidth), 0.0f, -1.0f, 1.0f);
projection = glm::rotate(projection, glm::radians(270.0f), {0.0f, 0.0f, 1.0f});
mProjectionMatrix = glm::translate(projection, {sScreenWidth * -1.0f, 0.0f, 0.0f});
}
mProjectionMatrixNormal = glm::ortho(0.0f, static_cast<float>(sScreenWidth),
static_cast<float>(sScreenHeight), 0.0f, -1.0f, 1.0f);
viewport.x = mScreenOffsetX;
viewport.y = mScreenOffsetY;
viewport.w = sScreenWidth;
viewport.h = sScreenHeight;
mProjectionMatrix = glm::ortho(0.0f, static_cast<float>(sScreenWidth),
static_cast<float>(sScreenHeight), 0.0f, -1.0f, 1.0f);
// This is required to avoid a brief white screen flash during startup on some systems.
drawRect(0.0f, 0.0f, static_cast<float>(getScreenWidth()),
@ -301,12 +352,20 @@ void Renderer::pushClipRect(const glm::ivec2& pos, const glm::ivec2& size)
if (box.h == 0)
box.h = sScreenHeight - box.y;
if (mScreenRotated) {
box = Rect {mWindowWidth - mScreenOffsetX - box.x - box.w,
mWindowHeight - mScreenOffsetY - box.y - box.h, box.w, box.h};
if (mScreenRotation == 0) {
box = {mScreenOffsetX + box.x, mScreenOffsetY + box.y, box.w, box.h};
}
else {
box = Rect {mScreenOffsetX + box.x, mScreenOffsetY + box.y, box.w, box.h};
else if (mScreenRotation == 90) {
box = {mScreenOffsetX + mWindowWidth - (box.y + box.h), mScreenOffsetY + box.x, box.h,
box.w};
}
else if (mScreenRotation == 270) {
box = {mScreenOffsetX + box.y, 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};
}
// Make sure the box fits within mClipStack.top(), and clip further accordingly.
@ -328,7 +387,6 @@ void Renderer::pushClipRect(const glm::ivec2& pos, const glm::ivec2& size)
box.h = 0;
mClipStack.push(box);
setScissor(box);
}

View file

@ -52,7 +52,8 @@ public:
PREMULTIPLIED = 0x00000001,
FONT_TEXTURE = 0x00000002,
POST_PROCESSING = 0x00000004,
CLIPPING = 0x00000008
CLIPPING = 0x00000008,
ROTATED = 0x00000010 // Screen rotated 90 or 270 degrees.
};
// clang-format on
@ -155,16 +156,11 @@ public:
const BlendFactor srcBlendFactor = BlendFactor::SRC_ALPHA,
const BlendFactor dstBlendFactor = BlendFactor::ONE_MINUS_SRC_ALPHA);
const glm::mat4& getProjectionMatrix()
{
if (mScreenRotated)
return mProjectionMatrixRotated;
else
return mProjectionMatrix;
}
const glm::mat4& getProjectionMatrixNormal() { return mProjectionMatrix; }
const glm::mat4& getProjectionMatrix() { return mProjectionMatrix; }
const glm::mat4& getProjectionMatrixNormal() { return mProjectionMatrixNormal; }
SDL_Window* getSDLWindow() { return mSDLWindow; }
const bool getScreenRotated() { return mScreenRotated; }
const int getScreenRotation() { return mScreenRotation; }
const bool getIsVerticalOrientation() { return sIsVerticalOrientation; }
const float getWindowWidth() { return static_cast<float>(mWindowWidth); }
const float getWindowHeight() { return static_cast<float>(mWindowHeight); }
static const float getScreenWidth() { return static_cast<float>(sScreenWidth); }
@ -172,6 +168,7 @@ public:
static const float getScreenWidthModifier() { return sScreenWidthModifier; }
static const float getScreenHeightModifier() { return sScreenHeightModifier; }
static const float getScreenAspectRatio() { return sScreenAspectRatio; }
static const float getScreenResolutionModifier() { return sScreenResolutionModifier; }
static constexpr glm::mat4 getIdentity() { return glm::mat4 {1.0f}; }
glm::mat4 mTrans {getIdentity()};
@ -215,19 +212,21 @@ private:
std::stack<Rect> mClipStack;
SDL_Window* mSDLWindow {nullptr};
glm::mat4 mProjectionMatrix {};
glm::mat4 mProjectionMatrixRotated {};
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};
bool mScreenRotated {0};
bool mInitialCursorState {1};
int mScreenRotation {0};
bool mInitialCursorState {true};
static inline bool sIsVerticalOrientation {false};
// Screen resolution modifiers relative to the 1920x1080 reference.
static inline float sScreenHeightModifier {0.0f};
static inline float sScreenWidthModifier {0.0f};
static inline float sScreenAspectRatio {0.0f};
static inline float sScreenResolutionModifier {0.0f};
};
#endif // ES_CORE_RENDERER_RENDERER_H

View file

@ -269,13 +269,22 @@ bool RendererOpenGL::createContext()
uint8_t data[4] {255, 255, 255, 255};
mWhiteTexture = createTexture(TextureType::BGRA, false, false, false, true, 1, 1, data);
mPostProcTexture1 = createTexture(TextureType::BGRA, false, false, false, false,
static_cast<unsigned int>(getScreenWidth()),
static_cast<unsigned int>(getScreenHeight()), nullptr);
unsigned int textureWidth {0};
unsigned int textureHeight {0};
mPostProcTexture2 = createTexture(TextureType::BGRA, false, false, false, false,
static_cast<unsigned int>(getScreenWidth()),
static_cast<unsigned int>(getScreenHeight()), nullptr);
if (getScreenRotation() == 0 || getScreenRotation() == 180) {
textureWidth = static_cast<unsigned int>(getScreenWidth());
textureHeight = static_cast<unsigned int>(getScreenHeight());
}
else {
textureWidth = static_cast<unsigned int>(getScreenHeight());
textureHeight = static_cast<unsigned int>(getScreenWidth());
}
mPostProcTexture1 = createTexture(TextureType::BGRA, false, false, false, false, textureWidth,
textureHeight, nullptr);
mPostProcTexture2 = createTexture(TextureType::BGRA, false, false, false, false, textureWidth,
textureHeight, nullptr);
// Attach textures to the shader framebuffers.
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO1));
@ -494,6 +503,7 @@ void RendererOpenGL::drawTriangleStrips(const Vertex* vertices,
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices,
GL_DYNAMIC_DRAW));
mBlurHorizontalShader->setTextureSize({width, height});
mBlurHorizontalShader->setFlags(vertices->shaderFlags);
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
mLastShader = mBlurHorizontalShader;
}
@ -511,6 +521,7 @@ void RendererOpenGL::drawTriangleStrips(const Vertex* vertices,
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices,
GL_DYNAMIC_DRAW));
mBlurVerticalShader->setTextureSize({width, height});
mBlurVerticalShader->setFlags(vertices->shaderFlags);
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
mLastShader = mBlurVerticalShader;
}
@ -521,12 +532,12 @@ void RendererOpenGL::drawTriangleStrips(const Vertex* vertices,
mScanlinelShader = getShaderProgram(Shader::SCANLINES);
float shaderWidth {width * 1.2f};
// Scale the scanlines relative to screen resolution.
float screenHeightModifier {getScreenHeightModifier()};
float resolutionModifier {getScreenResolutionModifier()};
float relativeHeight {height / getScreenHeight()};
float shaderHeight {0.0f};
if (relativeHeight == 1.0f) {
// Full screen.
float modifier {1.30f - (0.1f * screenHeightModifier)};
float modifier {1.30f - (0.1f * resolutionModifier)};
shaderHeight = height * modifier;
}
else {
@ -535,7 +546,7 @@ void RendererOpenGL::drawTriangleStrips(const Vertex* vertices,
// scanlines to videos with non-standard aspect ratios.
float relativeWidth {width / getScreenWidth()};
float relativeAdjustment {(relativeWidth + relativeHeight) / 2.0f};
float modifier {1.41f + relativeAdjustment / 7.0f - (0.14f * screenHeightModifier)};
float modifier {1.41f + relativeAdjustment / 7.0f - (0.14f * resolutionModifier)};
shaderHeight = height * modifier;
}
if (mScanlinelShader) {
@ -550,6 +561,7 @@ void RendererOpenGL::drawTriangleStrips(const Vertex* vertices,
mScanlinelShader->setBrightness(vertices->brightness);
mScanlinelShader->setSaturation(vertices->saturation);
mScanlinelShader->setTextureSize({shaderWidth, shaderHeight});
mScanlinelShader->setFlags(vertices->shaderFlags);
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
mLastShader = mScanlinelShader;
}
@ -566,6 +578,7 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
float heightf {getScreenHeight()};
GLuint width {static_cast<GLuint>(widthf)};
GLuint height {static_cast<GLuint>(heightf)};
const int screenRotation {getScreenRotation()};
// Set vertex positions and texture coordinates to full screen as all
// post-processing is applied to the complete screen area.
@ -581,6 +594,9 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
vertices->dimming = parameters.dimming;
vertices->shaderFlags = ShaderFlags::POST_PROCESSING | ShaderFlags::PREMULTIPLIED;
if (screenRotation == 90 || screenRotation == 270)
vertices->shaderFlags |= ShaderFlags::ROTATED;
if (shaders & Shader::CORE)
shaderList.push_back(Shader::CORE);
if (shaders & Shader::BLUR_HORIZONTAL)
@ -595,16 +611,52 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO1));
// Blit the screen contents to mPostProcTexture.
GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT,
GL_NEAREST));
int shaderCalls {0};
bool evenBlurPasses {true};
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO2));
for (size_t i {0}; i < shaderList.size(); ++i) {
if (shaderList[i] == Renderer::Shader::BLUR_HORIZONTAL ||
shaderList[i] == Renderer::Shader::BLUR_VERTICAL) {
shaderCalls += parameters.blurPasses;
if (parameters.blurPasses % 2 != 0)
evenBlurPasses = false;
}
else {
++shaderCalls;
}
}
// 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));
}
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));
else
GL_CHECK_ERROR(glBlitFramebuffer(0, 0, height, width, height, width, 0, 0,
GL_COLOR_BUFFER_BIT, GL_NEAREST));
// If not rendering to a texture, apply shaders without any rotation applied.
if (!textureRGBA)
mTrans = getProjectionMatrixNormal() * getIdentity();
}
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));
else
GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, width, height, 0, 0,
GL_COLOR_BUFFER_BIT, GL_NEAREST));
}
if (shaderCalls > 1)
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO2));
bool firstFBO {true};
int drawCalls {0};
for (size_t i = 0; i < shaderList.size(); ++i) {
for (size_t i {0}; i < shaderList.size(); ++i) {
vertices->shaders = shaderList[i];
int shaderPasses {1};
// For the blur shaders there is an optional variable to set the number of passes
@ -614,27 +666,17 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
shaderPasses = parameters.blurPasses;
}
for (int p = 0; p < shaderPasses; ++p) {
if (textureRGBA == nullptr && i == shaderList.size() - 1 && p == shaderPasses - 1) {
// If the screen is rotated and we're at an even number of drawcalls, then
// set the projection to a non-rotated state before making the last drawcall
// as the image would otherwise get rendered upside down.
if (getScreenRotated() && drawCalls % 2 == 0) {
mTrans = getIdentity();
mTrans[3] = glm::round(mTrans[3]);
mTrans = getProjectionMatrixNormal() * mTrans;
}
// If it's the last shader pass, then render directly to the default framebuffer
// to avoid having to make an expensive glBlitFramebuffer() call.
for (int p {0}; p < shaderPasses; ++p) {
if (!textureRGBA && i == shaderList.size() - 1 && p == shaderPasses - 1) {
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
drawTriangleStrips(vertices, 4, BlendFactor::SRC_ALPHA,
BlendFactor::ONE_MINUS_SRC_ALPHA);
break;
}
// Apply/render the shaders.
drawTriangleStrips(vertices, 4, BlendFactor::SRC_ALPHA,
BlendFactor::ONE_MINUS_SRC_ALPHA);
++drawCalls;
if (firstFBO) {
bindTexture(mPostProcTexture2);
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mShaderFBO2));
@ -663,16 +705,22 @@ void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mShaderFBO2));
#if defined(USE_OPENGLES)
GL_CHECK_ERROR(
glReadPixels(0, 0, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, textureRGBA));
if (screenRotation == 0 || screenRotation == 180)
GL_CHECK_ERROR(
glReadPixels(0, 0, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, textureRGBA));
else
GL_CHECK_ERROR(
glReadPixels(0, 0, height, width, GL_BGRA_EXT, GL_UNSIGNED_BYTE, textureRGBA));
#else
GL_CHECK_ERROR(glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, textureRGBA));
if (screenRotation == 0 || screenRotation == 180)
GL_CHECK_ERROR(
glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, textureRGBA));
else
GL_CHECK_ERROR(
glReadPixels(0, 0, height, width, GL_BGRA, GL_UNSIGNED_BYTE, textureRGBA));
#endif
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
}
if (getScreenRotated())
setMatrix(getIdentity());
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0));
}

View file

@ -30,15 +30,28 @@ void main()
precision mediump float;
#endif
uniform uint shaderFlags;
uniform vec2 textureSize;
uniform sampler2D textureSampler;
in vec2 texCoord;
out vec4 FragColor;
#define SourceSize vec4(textureSize, 1.0 / textureSize)
// shaderFlags:
// 0x00000001 - Premultiplied alpha (BGRA)
// 0x00000002 - Font texture
// 0x00000004 - Post processing
// 0x00000008 - Clipping
// 0x00000010 - Screen rotated 90 or 270 degrees
void main()
{
vec4 SourceSize;
if (0x0u != (shaderFlags & 0x10u))
SourceSize = vec4(textureSize.yx, 1.0 / textureSize.yx);
else
SourceSize = vec4(textureSize.xy, 1.0 / textureSize.xy);
vec2 PIXEL_SIZE = vec2(SourceSize.z, SourceSize.w);
float sampleOffsets[5] = float[5](0.0, 1.4347826, 3.3478260, 5.2608695, 7.1739130);

View file

@ -30,15 +30,28 @@ void main()
precision mediump float;
#endif
uniform uint shaderFlags;
uniform vec2 textureSize;
uniform sampler2D textureSampler;
in vec2 texCoord;
out vec4 FragColor;
#define SourceSize vec4(textureSize, 1.0 / textureSize)
// shaderFlags:
// 0x00000001 - Premultiplied alpha (BGRA)
// 0x00000002 - Font texture
// 0x00000004 - Post processing
// 0x00000008 - Clipping
// 0x00000010 - Screen rotated 90 or 270 degrees
void main()
{
vec4 SourceSize;
if (0x0u != (shaderFlags & 0x10u))
SourceSize = vec4(textureSize.yx, 1.0 / textureSize.yx);
else
SourceSize = vec4(textureSize.xy, 1.0 / textureSize.xy);
vec2 PIXEL_SIZE = vec2(SourceSize.z, SourceSize.w);
float sampleOffsets[5] = float[5](0.0, 1.4347826, 3.3478260, 5.2608695, 7.1739130);

View file

@ -54,6 +54,7 @@ out vec4 FragColor;
// 0x00000002 - Font texture
// 0x00000004 - Post processing
// 0x00000008 - Clipping
// 0x00000010 - Screen rotated 90 or 270 degrees
void main()
{

View file

@ -60,6 +60,7 @@ uniform vec2 textureSize;
uniform float opacity;
uniform float brightness;
uniform float saturation;
uniform uint shaderFlags;
uniform sampler2D textureSampler;
in vec2 texCoord;
in vec2 onex;
@ -67,8 +68,6 @@ in vec2 oney;
in vec4 colorShift;
out vec4 FragColor;
#define SourceSize vec4(textureSize, 1.0 / textureSize)
#ifdef PARAMETER_UNIFORM
uniform float SPOT_WIDTH;
uniform float SPOT_HEIGHT;
@ -95,8 +94,25 @@ uniform float OutputGamma;
w = 1.0 - w * w; \
w = w * w;
// shaderFlags:
// 0x00000001 - Premultiplied alpha (BGRA)
// 0x00000002 - Font texture
// 0x00000004 - Post processing
// 0x00000008 - Clipping
// 0x00000010 - Screen rotated 90 or 270 degrees
void main()
{
bool rotated = false;
if (0x0u != (shaderFlags & 0x10u))
rotated = true;
vec4 SourceSize;
if (rotated)
SourceSize = vec4(textureSize.yx, 1.0 / textureSize.yx);
else
SourceSize = vec4(textureSize.xy, 1.0 / textureSize.xy);
vec2 coords = (texCoord * SourceSize.xy);
vec2 pixel_center = floor(coords) + vec2(0.5, 0.5);
vec2 texture_coords = pixel_center * SourceSize.zw;
@ -127,7 +143,11 @@ void main()
color = color + colorNB * vec4(h_weight_01);
// Vertical blending.
float dy = coords.y - pixel_center.y;
float dy;
if (rotated)
dy = coords.x - pixel_center.x;
else
dy = coords.y - pixel_center.y;
float v_weight_00 = dy / SPOT_HEIGHT;
WEIGHT(v_weight_00);
color *= vec4(v_weight_00);