mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-01-31 12:35:44 +00:00
Greatly improved the shader post processing code and fixed some related bugs.
This commit is contained in:
parent
f08b434bc6
commit
ded5b1d29b
|
@ -323,30 +323,39 @@ void Window::render()
|
||||||
// Generate a cache texture of the shaded background when opening the menu, which
|
// Generate a cache texture of the shaded background when opening the menu, which
|
||||||
// will remain valid until the menu is closed. This is way faster than having to
|
// will remain valid until the menu is closed. This is way faster than having to
|
||||||
// render the shaders for every frame.
|
// render the shaders for every frame.
|
||||||
|
// const auto backgroundStartTime = std::chrono::system_clock::now();
|
||||||
|
|
||||||
std::shared_ptr<TextureResource> mPostprocessedBackground;
|
std::shared_ptr<TextureResource> mPostprocessedBackground;
|
||||||
mPostprocessedBackground = TextureResource::get("");
|
mPostprocessedBackground = TextureResource::get("");
|
||||||
unsigned char* processedTexture = new unsigned char[Renderer::getScreenWidth() *
|
unsigned char* processedTexture = new unsigned char[Renderer::getScreenWidth() *
|
||||||
Renderer::getScreenHeight() * 4];
|
Renderer::getScreenHeight() * 4];
|
||||||
|
|
||||||
// Defocus the background using three passes of gaussian blur.
|
// Defocus the background using multiple passes of gaussian blur, with the number
|
||||||
Renderer::shaderParameters blurParameters;
|
// of iterations relative to the screen resolution.
|
||||||
blurParameters.shaderPasses = 3;
|
Renderer::shaderParameters backgroundParameters;
|
||||||
|
float heightModifier = Renderer::getScreenHeightModifier();
|
||||||
|
|
||||||
|
if (heightModifier < 1)
|
||||||
|
backgroundParameters.blurPasses = 2; // Below 1080
|
||||||
|
else if (heightModifier >= 4)
|
||||||
|
backgroundParameters.blurPasses = 12; // 8K
|
||||||
|
else if (heightModifier >= 2.9)
|
||||||
|
backgroundParameters.blurPasses = 10; // 6K
|
||||||
|
else if (heightModifier >= 2.6)
|
||||||
|
backgroundParameters.blurPasses = 8; // 5K
|
||||||
|
else if (heightModifier >= 2)
|
||||||
|
backgroundParameters.blurPasses = 5; // 4K
|
||||||
|
else if (heightModifier >= 1.3)
|
||||||
|
backgroundParameters.blurPasses = 3; // 1440
|
||||||
|
else if (heightModifier >= 1)
|
||||||
|
backgroundParameters.blurPasses = 2; // 1080
|
||||||
|
|
||||||
|
// Also dim the background slightly.
|
||||||
|
backgroundParameters.fragmentDimValue = 0.60f;
|
||||||
|
|
||||||
Renderer::shaderPostprocessing(Renderer::SHADER_BLUR_HORIZONTAL |
|
Renderer::shaderPostprocessing(Renderer::SHADER_BLUR_HORIZONTAL |
|
||||||
Renderer::SHADER_BLUR_VERTICAL, blurParameters, processedTexture);
|
Renderer::SHADER_BLUR_VERTICAL | Renderer::SHADER_DIM,
|
||||||
|
backgroundParameters, processedTexture);
|
||||||
mPostprocessedBackground->initFromPixels(processedTexture,
|
|
||||||
Renderer::getScreenWidth(), Renderer::getScreenHeight());
|
|
||||||
|
|
||||||
mBackgroundOverlay->setImage(mPostprocessedBackground);
|
|
||||||
mBackgroundOverlay->render(transform);
|
|
||||||
|
|
||||||
// Dim the background. We need to do this as a separate step as combining
|
|
||||||
// it with the blurring leads to very strange and severe artifacts.
|
|
||||||
// This is for sure a bug that needs to be resolved at some later date.
|
|
||||||
Renderer::shaderParameters blackParameters;
|
|
||||||
blackParameters.fragmentDimValue = 0.6f;
|
|
||||||
Renderer::shaderPostprocessing(Renderer::SHADER_DIM,
|
|
||||||
blackParameters, processedTexture);
|
|
||||||
|
|
||||||
mPostprocessedBackground->initFromPixels(processedTexture,
|
mPostprocessedBackground->initFromPixels(processedTexture,
|
||||||
Renderer::getScreenWidth(), Renderer::getScreenHeight());
|
Renderer::getScreenWidth(), Renderer::getScreenHeight());
|
||||||
|
@ -365,11 +374,18 @@ void Window::render()
|
||||||
|
|
||||||
delete[] processedTexture;
|
delete[] processedTexture;
|
||||||
mCachedBackground = true;
|
mCachedBackground = true;
|
||||||
|
|
||||||
|
// const auto backgroundEndTime = std::chrono::system_clock::now();
|
||||||
|
// LOG(LogDebug) << "Window::render(): Time to create cached background: " <<
|
||||||
|
// std::chrono::duration_cast<std::chrono::milliseconds>
|
||||||
|
// (backgroundEndTime - backgroundStartTime).count() << " ms";
|
||||||
}
|
}
|
||||||
// Fade in the cached background.
|
// Fade in the cached background, unless the menu is set to open without any animation.
|
||||||
|
if (Settings::getInstance()->getString("MenuOpeningEffect") != "none") {
|
||||||
mBackgroundOverlay->setOpacity(mBackgroundOverlayOpacity);
|
mBackgroundOverlay->setOpacity(mBackgroundOverlayOpacity);
|
||||||
if (mBackgroundOverlayOpacity < 255)
|
if (mBackgroundOverlayOpacity < 255)
|
||||||
mBackgroundOverlayOpacity = Math::clamp(mBackgroundOverlayOpacity + 30, 0, 255);
|
mBackgroundOverlayOpacity = Math::clamp(mBackgroundOverlayOpacity + 30, 0, 255);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mBackgroundOverlay->render(transform);
|
mBackgroundOverlay->render(transform);
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace Renderer
|
||||||
float fragmentSaturation;
|
float fragmentSaturation;
|
||||||
float fragmentDimValue;
|
float fragmentDimValue;
|
||||||
float fragmentOpacity;
|
float fragmentOpacity;
|
||||||
unsigned int shaderPasses;
|
unsigned int blurPasses;
|
||||||
|
|
||||||
shaderParameters()
|
shaderParameters()
|
||||||
: textureSize({0.0f, 0.0f}),
|
: textureSize({0.0f, 0.0f}),
|
||||||
|
@ -44,7 +44,7 @@ namespace Renderer
|
||||||
fragmentSaturation(1.0f),
|
fragmentSaturation(1.0f),
|
||||||
fragmentDimValue(0.4f),
|
fragmentDimValue(0.4f),
|
||||||
fragmentOpacity(1.0f),
|
fragmentOpacity(1.0f),
|
||||||
shaderPasses(1)
|
blurPasses(1)
|
||||||
{};
|
{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -259,7 +259,6 @@ namespace Renderer
|
||||||
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, _numVertices));
|
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, _numVertices));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (unsigned int i = 0; i < _parameters.shaderPasses; i++) {
|
|
||||||
// If saturation is set below the maximum (default) value, run the
|
// If saturation is set below the maximum (default) value, run the
|
||||||
// desaturation shader.
|
// desaturation shader.
|
||||||
if (_vertices->saturation < 1.0 || _parameters.fragmentSaturation < 1.0) {
|
if (_vertices->saturation < 1.0 || _parameters.fragmentSaturation < 1.0) {
|
||||||
|
@ -336,7 +335,6 @@ namespace Renderer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,6 +401,7 @@ namespace Renderer
|
||||||
unsigned char* textureRGBA)
|
unsigned char* textureRGBA)
|
||||||
{
|
{
|
||||||
Vertex vertices[4];
|
Vertex vertices[4];
|
||||||
|
std::vector<unsigned int>shaderList;
|
||||||
GLuint width = getScreenWidth();
|
GLuint width = getScreenWidth();
|
||||||
GLuint height = getScreenHeight();
|
GLuint height = getScreenHeight();
|
||||||
float widthf = static_cast<float>(width);
|
float widthf = static_cast<float>(width);
|
||||||
|
@ -415,7 +414,18 @@ namespace Renderer
|
||||||
vertices[2] = { { widthf, 0 }, { 1, 1 }, 0 };
|
vertices[2] = { { widthf, 0 }, { 1, 1 }, 0 };
|
||||||
vertices[3] = { { widthf, heightf }, { 1, 0 }, 0};
|
vertices[3] = { { widthf, heightf }, { 1, 0 }, 0};
|
||||||
|
|
||||||
vertices[0].shaders = shaders;
|
if (shaders & Renderer::SHADER_DESATURATE)
|
||||||
|
shaderList.push_back(Renderer::SHADER_DESATURATE);
|
||||||
|
if (shaders & Renderer::SHADER_OPACITY)
|
||||||
|
shaderList.push_back(Renderer::SHADER_OPACITY);
|
||||||
|
if (shaders & Renderer::SHADER_DIM)
|
||||||
|
shaderList.push_back(Renderer::SHADER_DIM);
|
||||||
|
if (shaders & Renderer::SHADER_BLUR_HORIZONTAL)
|
||||||
|
shaderList.push_back(Renderer::SHADER_BLUR_HORIZONTAL);
|
||||||
|
if (shaders & Renderer::SHADER_BLUR_VERTICAL)
|
||||||
|
shaderList.push_back(Renderer::SHADER_BLUR_VERTICAL);
|
||||||
|
if (shaders & Renderer::SHADER_SCANLINES)
|
||||||
|
shaderList.push_back(Renderer::SHADER_SCANLINES);
|
||||||
|
|
||||||
if (parameters.fragmentSaturation < 1.0)
|
if (parameters.fragmentSaturation < 1.0)
|
||||||
vertices[0].saturation = parameters.fragmentSaturation;
|
vertices[0].saturation = parameters.fragmentSaturation;
|
||||||
|
@ -424,6 +434,17 @@ namespace Renderer
|
||||||
GLuint screenTexture = createTexture(Texture::RGBA, false, false, width, height, nullptr);
|
GLuint screenTexture = createTexture(Texture::RGBA, false, false, width, height, nullptr);
|
||||||
|
|
||||||
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0));
|
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0));
|
||||||
|
|
||||||
|
for (int i = 0; i < shaderList.size(); i++) {
|
||||||
|
vertices[0].shaders = shaderList[i];
|
||||||
|
int shaderPasses = 1;
|
||||||
|
// For the blur shaders there is an optional variable to set the number of passes
|
||||||
|
// to execute, which proportionally affects the blur amount.
|
||||||
|
if (shaderList[i] == Renderer::SHADER_BLUR_HORIZONTAL ||
|
||||||
|
shaderList[i] == Renderer::SHADER_BLUR_VERTICAL)
|
||||||
|
shaderPasses = parameters.blurPasses;
|
||||||
|
|
||||||
|
for (int p = 0; p < shaderPasses; p++) {
|
||||||
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO));
|
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO));
|
||||||
|
|
||||||
// Attach the texture to the shader framebuffer.
|
// Attach the texture to the shader framebuffer.
|
||||||
|
@ -442,10 +463,10 @@ namespace Renderer
|
||||||
drawTriangleStrips(vertices, 4, Transform4x4f::Identity(),
|
drawTriangleStrips(vertices, 4, Transform4x4f::Identity(),
|
||||||
Blend::SRC_ALPHA, Blend::ONE_MINUS_SRC_ALPHA, parameters);
|
Blend::SRC_ALPHA, Blend::ONE_MINUS_SRC_ALPHA, parameters);
|
||||||
|
|
||||||
// If textureRGBA has an address, it means that the output should go to this texture
|
// If textureRGBA has an address, it means that the output should go to this
|
||||||
// rather than to the screen. The glReadPixels() function is slow, but since this would
|
// texture rather than to the screen. The glReadPixels() function is slow, but
|
||||||
// typically only run every now and then to create a cached screen texture, it doesn't
|
// since this will typically only run every now and then to create a cached
|
||||||
// really matter.
|
// screen texture, it doesn't really matter.
|
||||||
if (textureRGBA) {
|
if (textureRGBA) {
|
||||||
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO));
|
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO));
|
||||||
GL_CHECK_ERROR(glReadPixels(0, 0, width, height,
|
GL_CHECK_ERROR(glReadPixels(0, 0, width, height,
|
||||||
|
@ -459,6 +480,8 @@ namespace Renderer
|
||||||
GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
|
GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
|
||||||
GL_COLOR_BUFFER_BIT, GL_NEAREST));
|
GL_COLOR_BUFFER_BIT, GL_NEAREST));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0));
|
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0));
|
||||||
destroyTexture(screenTexture);
|
destroyTexture(screenTexture);
|
||||||
|
|
Loading…
Reference in a new issue