2020-09-16 20:14:35 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2020-06-26 15:17:35 +00:00
|
|
|
//
|
2020-09-16 20:14:35 +00:00
|
|
|
// EmulationStation Desktop Edition
|
2022-03-14 19:14:18 +00:00
|
|
|
// RendererOpenGL.cpp
|
2020-06-26 15:17:35 +00:00
|
|
|
//
|
2022-03-14 18:51:48 +00:00
|
|
|
// OpenGL / OpenGL ES renderering functions.
|
2020-06-26 15:17:35 +00:00
|
|
|
//
|
|
|
|
|
2022-03-14 19:14:18 +00:00
|
|
|
#include "renderers/RendererOpenGL.h"
|
2022-03-14 18:51:48 +00:00
|
|
|
|
2019-08-08 20:16:11 +00:00
|
|
|
#include "Settings.h"
|
|
|
|
|
2021-11-12 18:49:24 +00:00
|
|
|
#if defined(__APPLE__)
|
|
|
|
#include <chrono>
|
|
|
|
#endif
|
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
RendererOpenGL::RendererOpenGL() noexcept
|
|
|
|
: mShaderFBO1 {0}
|
|
|
|
, mShaderFBO2 {0}
|
|
|
|
, mVertexBuffer1 {0}
|
|
|
|
, mVertexBuffer2 {0}
|
|
|
|
, mSDLContext {nullptr}
|
|
|
|
, mWhiteTexture {0}
|
|
|
|
, mPostProcTexture1 {0}
|
|
|
|
, mPostProcTexture2 {0}
|
|
|
|
, mCoreShader {nullptr}
|
|
|
|
, mBlurHorizontalShader {nullptr}
|
|
|
|
, mBlurVerticalShader {nullptr}
|
|
|
|
, mScanlinelShader {nullptr}
|
|
|
|
, mLastShader {nullptr}
|
2022-04-10 12:54:21 +00:00
|
|
|
, mMajorGLVersion {0}
|
|
|
|
, mMinorGLVersion {0}
|
2022-03-14 18:51:48 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
RendererOpenGL* RendererOpenGL::getInstance()
|
|
|
|
{
|
|
|
|
static RendererOpenGL instance;
|
|
|
|
return &instance;
|
|
|
|
}
|
|
|
|
|
2022-10-11 16:11:36 +00:00
|
|
|
std::shared_ptr<ShaderOpenGL> RendererOpenGL::getShaderProgram(unsigned int shaderID)
|
2019-08-08 20:16:11 +00:00
|
|
|
{
|
2022-03-14 18:51:48 +00:00
|
|
|
unsigned int index {0};
|
|
|
|
|
|
|
|
// Find the index in mShaderProgramVector by counting the number
|
|
|
|
// of shifts required to reach 0.
|
|
|
|
while (shaderID > 0) {
|
|
|
|
shaderID = shaderID >> 1;
|
|
|
|
++index;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mShaderProgramVector.size() > index - 1)
|
|
|
|
return mShaderProgramVector[index - 1];
|
|
|
|
else
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RendererOpenGL::loadShaders()
|
|
|
|
{
|
|
|
|
LOG(LogInfo) << "Loading shaders...";
|
|
|
|
|
|
|
|
std::vector<std::string> shaderFiles;
|
2022-10-11 16:11:36 +00:00
|
|
|
shaderFiles.emplace_back(":/shaders/glsl/core.glsl");
|
|
|
|
shaderFiles.emplace_back(":/shaders/glsl/blur_horizontal.glsl");
|
|
|
|
shaderFiles.emplace_back(":/shaders/glsl/blur_vertical.glsl");
|
|
|
|
shaderFiles.emplace_back(":/shaders/glsl/scanlines.glsl");
|
2022-03-14 18:51:48 +00:00
|
|
|
|
|
|
|
for (auto it = shaderFiles.cbegin(); it != shaderFiles.cend(); ++it) {
|
2022-10-11 16:11:36 +00:00
|
|
|
auto loadShader = std::make_shared<ShaderOpenGL>();
|
2022-03-14 18:51:48 +00:00
|
|
|
|
|
|
|
loadShader->loadShaderFile(*it, GL_VERTEX_SHADER);
|
|
|
|
loadShader->loadShaderFile(*it, GL_FRAGMENT_SHADER);
|
|
|
|
|
|
|
|
if (!loadShader->createProgram()) {
|
|
|
|
LOG(LogError) << "Could not create shader program.";
|
|
|
|
return false;
|
2020-06-26 15:17:35 +00:00
|
|
|
}
|
2022-03-14 18:51:48 +00:00
|
|
|
|
2022-10-11 16:11:36 +00:00
|
|
|
mShaderProgramVector.emplace_back(std::move(loadShader));
|
2020-06-26 15:17:35 +00:00
|
|
|
}
|
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-03-15 16:14:55 +00:00
|
|
|
GLenum RendererOpenGL::convertBlendFactor(const BlendFactor BlendFactor)
|
2022-03-14 18:51:48 +00:00
|
|
|
{
|
|
|
|
// clang-format off
|
2022-03-15 16:14:55 +00:00
|
|
|
switch (BlendFactor) {
|
2022-03-14 18:51:48 +00:00
|
|
|
case BlendFactor::SRC_ALPHA: { return GL_SRC_ALPHA; } break;
|
|
|
|
case BlendFactor::ONE_MINUS_SRC_ALPHA: { return GL_ONE_MINUS_SRC_ALPHA; } break;
|
|
|
|
case BlendFactor::DST_COLOR: { return GL_DST_COLOR; } break;
|
|
|
|
case BlendFactor::ONE_MINUS_DST_COLOR: { return GL_ONE_MINUS_DST_COLOR; } break;
|
2022-03-16 19:26:13 +00:00
|
|
|
case BlendFactor::ZERO: { return GL_ZERO; } break;
|
|
|
|
case BlendFactor::ONE: { return GL_ONE; } break;
|
|
|
|
case BlendFactor::SRC_COLOR: { return GL_SRC_COLOR; } break;
|
|
|
|
case BlendFactor::ONE_MINUS_SRC_COLOR: { return GL_ONE_MINUS_SRC_COLOR; } break;
|
2022-03-14 18:51:48 +00:00
|
|
|
case BlendFactor::DST_ALPHA: { return GL_DST_ALPHA; } break;
|
|
|
|
case BlendFactor::ONE_MINUS_DST_ALPHA: { return GL_ONE_MINUS_DST_ALPHA; } break;
|
|
|
|
default: { return GL_ZERO; }
|
|
|
|
}
|
|
|
|
// clang-format on
|
|
|
|
}
|
|
|
|
|
|
|
|
GLenum RendererOpenGL::convertTextureType(const TextureType type)
|
|
|
|
{
|
|
|
|
// clang-format off
|
|
|
|
switch (type) {
|
|
|
|
case TextureType::RGBA: { return GL_RGBA; } break;
|
2022-03-13 22:52:32 +00:00
|
|
|
#if defined(USE_OPENGLES)
|
2022-03-14 18:51:48 +00:00
|
|
|
case TextureType::BGRA: { return GL_BGRA_EXT; } break;
|
2022-03-13 22:52:32 +00:00
|
|
|
#else
|
2022-03-14 18:51:48 +00:00
|
|
|
case TextureType::BGRA: { return GL_BGRA; } break;
|
2022-03-13 22:52:32 +00:00
|
|
|
#endif
|
2022-03-15 16:17:56 +00:00
|
|
|
#if defined(__EMSCRIPTEN__)
|
|
|
|
case TextureType::RED: { return GL_LUMINANCE; } break;
|
|
|
|
#else
|
2022-03-14 18:51:48 +00:00
|
|
|
case TextureType::RED: { return GL_RED; } break;
|
2022-03-15 16:17:56 +00:00
|
|
|
#endif
|
2022-03-14 18:51:48 +00:00
|
|
|
default: { return GL_ZERO; }
|
2020-06-26 15:17:35 +00:00
|
|
|
}
|
2022-03-14 18:51:48 +00:00
|
|
|
// clang-format on
|
|
|
|
}
|
2020-06-26 15:17:35 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
void RendererOpenGL::setup()
|
|
|
|
{
|
2022-04-10 12:54:21 +00:00
|
|
|
std::string glVersion {Settings::getInstance()->getString("OpenGLVersion")};
|
|
|
|
|
2022-03-13 22:52:32 +00:00
|
|
|
#if defined(USE_OPENGLES)
|
2022-04-10 12:54:21 +00:00
|
|
|
if (glVersion == "" || glVersion == "3.0") {
|
|
|
|
mMajorGLVersion = 3;
|
|
|
|
mMinorGLVersion = 0;
|
|
|
|
}
|
|
|
|
else if (glVersion == "3.1") {
|
|
|
|
mMajorGLVersion = 3;
|
|
|
|
mMinorGLVersion = 1;
|
|
|
|
}
|
|
|
|
else if (glVersion == "3.2") {
|
|
|
|
mMajorGLVersion = 3;
|
|
|
|
mMinorGLVersion = 2;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
LOG(LogWarning) << "Unsupported OpenGL ES version \"" << glVersion
|
|
|
|
<< "\" requested, defaulting to 3.0 (valid versions are 3.0, 3.1 and 3.2)";
|
|
|
|
mMajorGLVersion = 3;
|
|
|
|
mMinorGLVersion = 0;
|
|
|
|
}
|
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
2022-09-27 15:47:10 +00:00
|
|
|
#else
|
|
|
|
#if defined(STEAM_DECK) || defined(RETRODECK)
|
|
|
|
if (glVersion == "3.3") {
|
2021-07-07 18:31:46 +00:00
|
|
|
#else
|
2022-04-10 12:54:21 +00:00
|
|
|
if (glVersion == "" || glVersion == "3.3") {
|
2022-09-27 15:47:10 +00:00
|
|
|
#endif
|
2022-04-10 12:54:21 +00:00
|
|
|
mMajorGLVersion = 3;
|
|
|
|
mMinorGLVersion = 3;
|
|
|
|
}
|
|
|
|
else if (glVersion == "4.2") {
|
|
|
|
mMajorGLVersion = 4;
|
|
|
|
mMinorGLVersion = 2;
|
|
|
|
}
|
2022-09-27 15:47:10 +00:00
|
|
|
#if defined(STEAM_DECK) || defined(RETRODECK)
|
|
|
|
else if (glVersion == "" || glVersion == "4.6") {
|
|
|
|
#else
|
2022-04-10 12:54:21 +00:00
|
|
|
else if (glVersion == "4.6") {
|
2022-09-27 15:47:10 +00:00
|
|
|
#endif
|
2022-04-10 12:54:21 +00:00
|
|
|
mMajorGLVersion = 4;
|
|
|
|
mMinorGLVersion = 6;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
LOG(LogWarning) << "Unsupported OpenGL version \"" << glVersion
|
2022-09-27 15:47:10 +00:00
|
|
|
#if defined(STEAM_DECK) || defined(RETRODECK)
|
|
|
|
<< "\" requested, defaulting to 4.6 (valid versions are 3.3, 4.2 and 4.6)";
|
|
|
|
mMajorGLVersion = 4;
|
|
|
|
mMinorGLVersion = 6;
|
|
|
|
#else
|
2022-04-10 12:54:21 +00:00
|
|
|
<< "\" requested, defaulting to 3.3 (valid versions are 3.3, 4.2 and 4.6)";
|
|
|
|
mMajorGLVersion = 3;
|
|
|
|
mMinorGLVersion = 3;
|
2022-09-27 15:47:10 +00:00
|
|
|
#endif
|
2022-04-10 12:54:21 +00:00
|
|
|
}
|
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
2021-07-07 18:31:46 +00:00
|
|
|
#endif
|
2020-06-26 15:17:35 +00:00
|
|
|
|
2022-04-10 12:54:21 +00:00
|
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, mMajorGLVersion);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, mMinorGLVersion);
|
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
2023-01-09 16:55:54 +00:00
|
|
|
|
|
|
|
#if !defined(USE_OPENGLES)
|
|
|
|
const int antiAliasing {Settings::getInstance()->getInt("AntiAliasing")};
|
|
|
|
if (antiAliasing == 2 || antiAliasing == 4) {
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antiAliasing);
|
|
|
|
}
|
|
|
|
#endif
|
2022-03-14 18:51:48 +00:00
|
|
|
}
|
2020-06-26 15:17:35 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
bool RendererOpenGL::createContext()
|
|
|
|
{
|
|
|
|
mSDLContext = SDL_GL_CreateContext(getSDLWindow());
|
2020-08-18 15:48:21 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
if (!mSDLContext) {
|
|
|
|
LOG(LogError) << "Error creating OpenGL context. " << SDL_GetError();
|
|
|
|
return false;
|
|
|
|
}
|
2020-08-18 15:48:21 +00:00
|
|
|
|
2021-07-07 18:31:46 +00:00
|
|
|
#if defined(_WIN64)
|
2022-03-14 18:51:48 +00:00
|
|
|
glewInit();
|
2021-07-07 18:31:46 +00:00
|
|
|
#endif
|
2020-09-16 20:14:35 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
SDL_GL_MakeCurrent(getSDLWindow(), mSDLContext);
|
|
|
|
|
|
|
|
std::string vendor {
|
|
|
|
glGetString(GL_VENDOR) ? reinterpret_cast<const char*>(glGetString(GL_VENDOR)) : ""};
|
|
|
|
std::string renderer {
|
|
|
|
glGetString(GL_RENDERER) ? reinterpret_cast<const char*>(glGetString(GL_RENDERER)) : ""};
|
|
|
|
std::string version {
|
|
|
|
glGetString(GL_VERSION) ? reinterpret_cast<const char*>(glGetString(GL_VERSION)) : ""};
|
|
|
|
|
|
|
|
LOG(LogInfo) << "GL vendor: " << vendor;
|
|
|
|
LOG(LogInfo) << "GL renderer: " << renderer;
|
|
|
|
LOG(LogInfo) << "GL version: " << version;
|
2022-04-10 12:54:21 +00:00
|
|
|
#if defined(USE_OPENGLES)
|
2023-02-12 21:14:09 +00:00
|
|
|
LOG(LogInfo) << "Application renderer: OpenGL ES " << mMajorGLVersion << "." << mMinorGLVersion;
|
2022-04-10 12:54:21 +00:00
|
|
|
#else
|
2021-07-07 18:31:46 +00:00
|
|
|
#if defined(_WIN64)
|
2023-02-12 21:14:09 +00:00
|
|
|
LOG(LogInfo) << "Application renderer: OpenGL " << mMajorGLVersion << "." << mMinorGLVersion
|
|
|
|
<< " with GLEW";
|
2022-03-13 22:52:32 +00:00
|
|
|
#else
|
2023-02-12 21:14:09 +00:00
|
|
|
LOG(LogInfo) << "Application renderer: OpenGL " << mMajorGLVersion << "." << mMinorGLVersion;
|
2022-04-10 12:54:21 +00:00
|
|
|
#endif
|
2021-07-07 18:31:46 +00:00
|
|
|
#endif
|
2022-03-13 22:52:32 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
GL_CHECK_ERROR(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
|
|
|
|
GL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0));
|
|
|
|
GL_CHECK_ERROR(glEnable(GL_BLEND));
|
|
|
|
GL_CHECK_ERROR(glPixelStorei(GL_PACK_ALIGNMENT, 1));
|
|
|
|
GL_CHECK_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
|
2022-03-13 22:52:32 +00:00
|
|
|
|
2023-01-09 16:55:54 +00:00
|
|
|
#if !defined(USE_OPENGLES)
|
|
|
|
const int antiAliasing {Settings::getInstance()->getInt("AntiAliasing")};
|
|
|
|
if (antiAliasing == 2 || antiAliasing == 4) {
|
|
|
|
GL_CHECK_ERROR(glEnable(GL_MULTISAMPLE));
|
|
|
|
LOG(LogInfo) << "Anti-aliasing: " << antiAliasing << "x MSAA";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
LOG(LogInfo) << "Anti-aliasing: disabled";
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
// These are used for the shader post processing.
|
|
|
|
GL_CHECK_ERROR(glGenFramebuffers(1, &mShaderFBO1));
|
|
|
|
GL_CHECK_ERROR(glGenFramebuffers(1, &mShaderFBO2));
|
2022-03-13 22:52:32 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
GL_CHECK_ERROR(glGenBuffers(1, &mVertexBuffer1));
|
|
|
|
GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer1));
|
|
|
|
GL_CHECK_ERROR(glGenVertexArrays(1, &mVertexBuffer2));
|
|
|
|
GL_CHECK_ERROR(glBindVertexArray(mVertexBuffer2));
|
2022-03-13 22:52:32 +00:00
|
|
|
|
2022-09-03 19:22:31 +00:00
|
|
|
uint8_t data[4] {255, 255, 255, 255};
|
2022-10-27 22:08:41 +00:00
|
|
|
mWhiteTexture = createTexture(TextureType::BGRA, false, false, false, true, 1, 1, data);
|
2020-06-26 15:17:35 +00:00
|
|
|
|
2023-02-06 22:38:35 +00:00
|
|
|
unsigned int textureWidth {0};
|
|
|
|
unsigned int textureHeight {0};
|
2022-03-11 22:17:04 +00:00
|
|
|
|
2023-02-06 22:38:35 +00:00
|
|
|
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);
|
2022-03-11 22:17:04 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
// Attach textures to the shader framebuffers.
|
|
|
|
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO1));
|
|
|
|
GL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
|
|
|
mPostProcTexture1, 0));
|
2020-06-26 15:17:35 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO2));
|
|
|
|
GL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
|
|
|
mPostProcTexture2, 0));
|
2020-08-30 20:19:37 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
GL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
2020-09-04 16:59:19 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
return true;
|
|
|
|
}
|
2020-06-26 15:17:35 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
void RendererOpenGL::destroyContext()
|
|
|
|
{
|
|
|
|
GL_CHECK_ERROR(glDeleteFramebuffers(1, &mShaderFBO1));
|
|
|
|
GL_CHECK_ERROR(glDeleteFramebuffers(1, &mShaderFBO2));
|
|
|
|
destroyTexture(mPostProcTexture1);
|
|
|
|
destroyTexture(mPostProcTexture2);
|
|
|
|
destroyTexture(mWhiteTexture);
|
2023-01-09 16:55:54 +00:00
|
|
|
|
|
|
|
mShaderProgramVector.clear();
|
|
|
|
|
|
|
|
mCoreShader.reset();
|
|
|
|
mBlurHorizontalShader.reset();
|
|
|
|
mBlurVerticalShader.reset();
|
|
|
|
mScanlinelShader.reset();
|
|
|
|
mLastShader.reset();
|
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
SDL_GL_DeleteContext(mSDLContext);
|
|
|
|
mSDLContext = nullptr;
|
|
|
|
}
|
|
|
|
|
2022-09-02 19:01:31 +00:00
|
|
|
void RendererOpenGL::setMatrix(const glm::mat4& matrix)
|
2022-03-14 18:51:48 +00:00
|
|
|
{
|
2022-09-05 21:36:49 +00:00
|
|
|
// Calculate the projection matrix.
|
|
|
|
mTrans = getProjectionMatrix() * matrix;
|
2022-03-14 18:51:48 +00:00
|
|
|
}
|
2020-06-26 15:17:35 +00:00
|
|
|
|
2023-02-12 21:14:09 +00:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
void RendererOpenGL::setScissor(const Rect& scissor)
|
|
|
|
{
|
|
|
|
if ((scissor.x == 0) && (scissor.y == 0) && (scissor.w == 0) && (scissor.h == 0)) {
|
|
|
|
GL_CHECK_ERROR(glDisable(GL_SCISSOR_TEST));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// glScissor starts at the bottom left of the window.
|
|
|
|
GL_CHECK_ERROR(glScissor(scissor.x,
|
2023-02-12 21:14:09 +00:00
|
|
|
static_cast<GLint>(mWindowHeight) - scissor.y - scissor.h,
|
2022-03-14 18:51:48 +00:00
|
|
|
scissor.w, scissor.h));
|
|
|
|
GL_CHECK_ERROR(glEnable(GL_SCISSOR_TEST));
|
2020-06-26 15:17:35 +00:00
|
|
|
}
|
2022-03-14 18:51:48 +00:00
|
|
|
}
|
2020-06-26 15:17:35 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
void RendererOpenGL::setSwapInterval()
|
|
|
|
{
|
|
|
|
if (Settings::getInstance()->getBool("VSync")) {
|
|
|
|
// Adaptive VSync seems to be nonfunctional or having issues on some hardware
|
|
|
|
// and drivers, so only attempt to apply regular VSync.
|
|
|
|
if (SDL_GL_SetSwapInterval(1) == 0) {
|
2023-01-25 20:56:07 +00:00
|
|
|
LOG(LogInfo) << "VSync: enabled";
|
2022-03-14 18:51:48 +00:00
|
|
|
}
|
|
|
|
else {
|
2023-01-22 20:03:08 +00:00
|
|
|
Settings::getInstance()->setBool("VSync", false);
|
2022-03-14 18:51:48 +00:00
|
|
|
LOG(LogWarning) << "Could not enable VSync: " << SDL_GetError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
SDL_GL_SetSwapInterval(0);
|
2023-01-25 20:56:07 +00:00
|
|
|
LOG(LogInfo) << "VSync: disabled";
|
2020-06-26 15:17:35 +00:00
|
|
|
}
|
2022-03-14 18:51:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void RendererOpenGL::swapBuffers()
|
|
|
|
{
|
|
|
|
#if defined(__APPLE__)
|
|
|
|
// On macOS when running in the background, the OpenGL driver apparently does not swap
|
|
|
|
// the frames which leads to a very fast swap time. This makes ES-DE use a lot of CPU
|
|
|
|
// resources which slows down the games significantly on slower machines. By introducing
|
|
|
|
// a delay if the swap time is very low we reduce CPU usage while still keeping the
|
|
|
|
// application functioning normally.
|
|
|
|
const auto beforeSwap = std::chrono::system_clock::now();
|
|
|
|
SDL_GL_SwapWindow(getSDLWindow());
|
|
|
|
|
|
|
|
if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() -
|
|
|
|
beforeSwap)
|
|
|
|
.count() < 3.0)
|
|
|
|
SDL_Delay(10);
|
|
|
|
#else
|
|
|
|
SDL_GL_SwapWindow(getSDLWindow());
|
|
|
|
#endif
|
|
|
|
GL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int RendererOpenGL::createTexture(const TextureType type,
|
|
|
|
const bool linearMinify,
|
|
|
|
const bool linearMagnify,
|
2022-09-05 21:36:49 +00:00
|
|
|
const bool mipmapping,
|
2022-03-14 18:51:48 +00:00
|
|
|
const bool repeat,
|
|
|
|
const unsigned int width,
|
|
|
|
const unsigned int height,
|
|
|
|
void* data)
|
|
|
|
{
|
2022-03-14 19:14:18 +00:00
|
|
|
const GLenum textureType {convertTextureType(type)};
|
2022-03-14 18:51:48 +00:00
|
|
|
unsigned int texture;
|
|
|
|
|
|
|
|
GL_CHECK_ERROR(glGenTextures(1, &texture));
|
|
|
|
GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture));
|
|
|
|
|
|
|
|
GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
|
|
|
|
repeat ? static_cast<GLfloat>(GL_REPEAT) :
|
|
|
|
static_cast<GLfloat>(GL_CLAMP_TO_EDGE)));
|
|
|
|
GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
|
|
|
|
repeat ? static_cast<GLfloat>(GL_REPEAT) :
|
|
|
|
static_cast<GLfloat>(GL_CLAMP_TO_EDGE)));
|
2022-09-05 21:36:49 +00:00
|
|
|
if (mipmapping) {
|
|
|
|
GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
|
|
|
static_cast<GLfloat>(GL_LINEAR_MIPMAP_LINEAR)));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
|
|
|
linearMinify ? static_cast<GLfloat>(GL_LINEAR) :
|
|
|
|
static_cast<GLfloat>(GL_NEAREST)));
|
|
|
|
}
|
2022-03-14 18:51:48 +00:00
|
|
|
GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
|
|
|
linearMagnify ? static_cast<GLfloat>(GL_LINEAR) :
|
|
|
|
static_cast<GLfloat>(GL_NEAREST)));
|
|
|
|
|
2022-10-27 22:08:41 +00:00
|
|
|
#if defined(USE_OPENGLES)
|
2022-03-14 18:51:48 +00:00
|
|
|
GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureType,
|
|
|
|
GL_UNSIGNED_BYTE, data));
|
2022-10-27 22:08:41 +00:00
|
|
|
#else
|
|
|
|
GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, textureType,
|
|
|
|
GL_UNSIGNED_BYTE, data));
|
|
|
|
#endif
|
2022-09-05 21:36:49 +00:00
|
|
|
|
|
|
|
if (mipmapping)
|
|
|
|
GL_CHECK_ERROR(glGenerateMipmap(GL_TEXTURE_2D));
|
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
return texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RendererOpenGL::destroyTexture(const unsigned int texture)
|
|
|
|
{
|
|
|
|
GL_CHECK_ERROR(glDeleteTextures(1, &texture));
|
|
|
|
}
|
|
|
|
|
|
|
|
void RendererOpenGL::updateTexture(const unsigned int texture,
|
|
|
|
const TextureType type,
|
|
|
|
const unsigned int x,
|
|
|
|
const unsigned int y,
|
|
|
|
const unsigned int width,
|
|
|
|
const unsigned int height,
|
|
|
|
void* data)
|
|
|
|
{
|
2022-03-14 19:14:18 +00:00
|
|
|
const GLenum textureType {convertTextureType(type)};
|
2020-06-26 15:17:35 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture));
|
|
|
|
GL_CHECK_ERROR(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, textureType,
|
|
|
|
GL_UNSIGNED_BYTE, data));
|
2020-06-26 15:17:35 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, mWhiteTexture));
|
|
|
|
}
|
|
|
|
|
|
|
|
void RendererOpenGL::bindTexture(const unsigned int texture)
|
|
|
|
{
|
|
|
|
if (texture == 0)
|
|
|
|
GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, mWhiteTexture));
|
|
|
|
else
|
2021-08-19 19:39:01 +00:00
|
|
|
GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture));
|
2022-03-14 18:51:48 +00:00
|
|
|
}
|
2022-03-11 22:17:04 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
void RendererOpenGL::drawTriangleStrips(const Vertex* vertices,
|
|
|
|
const unsigned int numVertices,
|
2022-03-15 16:14:55 +00:00
|
|
|
const BlendFactor srcBlendFactor,
|
|
|
|
const BlendFactor dstBlendFactor)
|
2022-03-14 18:51:48 +00:00
|
|
|
{
|
|
|
|
const float width {vertices[3].position[0]};
|
|
|
|
const float height {vertices[3].position[1]};
|
|
|
|
|
2022-03-15 16:14:55 +00:00
|
|
|
GL_CHECK_ERROR(
|
|
|
|
glBlendFunc(convertBlendFactor(srcBlendFactor), convertBlendFactor(dstBlendFactor)));
|
2022-03-14 18:51:48 +00:00
|
|
|
|
2022-03-14 21:30:24 +00:00
|
|
|
if (vertices->shaders == 0 || vertices->shaders & Shader::CORE) {
|
2022-03-14 18:51:48 +00:00
|
|
|
if (mCoreShader == nullptr)
|
2022-03-14 21:30:24 +00:00
|
|
|
mCoreShader = getShaderProgram(Shader::CORE);
|
2022-03-14 18:51:48 +00:00
|
|
|
if (mCoreShader) {
|
|
|
|
if (mLastShader != mCoreShader)
|
|
|
|
mCoreShader->activateShaders();
|
|
|
|
mCoreShader->setModelViewProjectionMatrix(mTrans);
|
|
|
|
if (mLastShader != mCoreShader)
|
|
|
|
mCoreShader->setAttribPointers();
|
|
|
|
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices,
|
|
|
|
GL_DYNAMIC_DRAW));
|
2022-08-30 17:42:37 +00:00
|
|
|
mCoreShader->setClipRegion(vertices->clipregion);
|
2022-12-14 19:17:41 +00:00
|
|
|
mCoreShader->setBrightness(vertices->brightness);
|
2022-03-14 18:51:48 +00:00
|
|
|
mCoreShader->setOpacity(vertices->opacity);
|
|
|
|
mCoreShader->setSaturation(vertices->saturation);
|
|
|
|
mCoreShader->setDimming(vertices->dimming);
|
2022-04-18 19:37:58 +00:00
|
|
|
mCoreShader->setReflectionsFalloff(vertices->reflectionsFalloff);
|
2022-03-14 21:30:24 +00:00
|
|
|
mCoreShader->setFlags(vertices->shaderFlags);
|
2022-03-14 18:51:48 +00:00
|
|
|
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
|
|
|
|
mLastShader = mCoreShader;
|
|
|
|
}
|
2020-06-26 15:17:35 +00:00
|
|
|
}
|
2022-03-14 21:30:24 +00:00
|
|
|
else if (vertices->shaders & Shader::BLUR_HORIZONTAL) {
|
2022-03-14 18:51:48 +00:00
|
|
|
if (mBlurHorizontalShader == nullptr)
|
2022-03-14 21:30:24 +00:00
|
|
|
mBlurHorizontalShader = getShaderProgram(Shader::BLUR_HORIZONTAL);
|
2022-03-14 18:51:48 +00:00
|
|
|
if (mBlurHorizontalShader) {
|
|
|
|
if (mLastShader != mBlurHorizontalShader)
|
|
|
|
mBlurHorizontalShader->activateShaders();
|
|
|
|
mBlurHorizontalShader->setModelViewProjectionMatrix(mTrans);
|
|
|
|
if (mLastShader != mBlurHorizontalShader)
|
|
|
|
mBlurHorizontalShader->setAttribPointers();
|
|
|
|
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices,
|
|
|
|
GL_DYNAMIC_DRAW));
|
|
|
|
mBlurHorizontalShader->setTextureSize({width, height});
|
2023-02-06 22:38:35 +00:00
|
|
|
mBlurHorizontalShader->setFlags(vertices->shaderFlags);
|
2022-03-14 18:51:48 +00:00
|
|
|
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
|
|
|
|
mLastShader = mBlurHorizontalShader;
|
|
|
|
}
|
|
|
|
return;
|
2020-06-26 15:17:35 +00:00
|
|
|
}
|
2022-03-14 21:30:24 +00:00
|
|
|
else if (vertices->shaders & Shader::BLUR_VERTICAL) {
|
2022-03-14 18:51:48 +00:00
|
|
|
if (mBlurVerticalShader == nullptr)
|
2022-03-14 21:30:24 +00:00
|
|
|
mBlurVerticalShader = getShaderProgram(Shader::BLUR_VERTICAL);
|
2022-03-14 18:51:48 +00:00
|
|
|
if (mBlurVerticalShader) {
|
|
|
|
if (mLastShader != mBlurVerticalShader)
|
|
|
|
mBlurVerticalShader->activateShaders();
|
|
|
|
mBlurVerticalShader->setModelViewProjectionMatrix(mTrans);
|
|
|
|
if (mLastShader != mBlurVerticalShader)
|
|
|
|
mBlurVerticalShader->setAttribPointers();
|
|
|
|
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices,
|
|
|
|
GL_DYNAMIC_DRAW));
|
|
|
|
mBlurVerticalShader->setTextureSize({width, height});
|
2023-02-06 22:38:35 +00:00
|
|
|
mBlurVerticalShader->setFlags(vertices->shaderFlags);
|
2022-03-14 18:51:48 +00:00
|
|
|
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
|
|
|
|
mLastShader = mBlurVerticalShader;
|
2022-03-11 22:17:04 +00:00
|
|
|
}
|
2022-03-14 18:51:48 +00:00
|
|
|
return;
|
|
|
|
}
|
2022-03-14 21:30:24 +00:00
|
|
|
else if (vertices->shaders & Shader::SCANLINES) {
|
2022-03-14 18:51:48 +00:00
|
|
|
if (mScanlinelShader == nullptr)
|
2022-03-14 21:30:24 +00:00
|
|
|
mScanlinelShader = getShaderProgram(Shader::SCANLINES);
|
2022-03-14 18:51:48 +00:00
|
|
|
float shaderWidth {width * 1.2f};
|
|
|
|
// Scale the scanlines relative to screen resolution.
|
2023-02-06 22:38:35 +00:00
|
|
|
float resolutionModifier {getScreenResolutionModifier()};
|
2022-03-14 18:51:48 +00:00
|
|
|
float relativeHeight {height / getScreenHeight()};
|
|
|
|
float shaderHeight {0.0f};
|
|
|
|
if (relativeHeight == 1.0f) {
|
|
|
|
// Full screen.
|
2023-02-06 22:38:35 +00:00
|
|
|
float modifier {1.30f - (0.1f * resolutionModifier)};
|
2022-03-14 18:51:48 +00:00
|
|
|
shaderHeight = height * modifier;
|
2022-03-11 22:17:04 +00:00
|
|
|
}
|
2022-03-14 18:51:48 +00:00
|
|
|
else {
|
|
|
|
// Portion of screen, e.g. gamelist view.
|
|
|
|
// Average the relative width and height to avoid applying exaggerated
|
|
|
|
// scanlines to videos with non-standard aspect ratios.
|
|
|
|
float relativeWidth {width / getScreenWidth()};
|
|
|
|
float relativeAdjustment {(relativeWidth + relativeHeight) / 2.0f};
|
2023-02-06 22:38:35 +00:00
|
|
|
float modifier {1.41f + relativeAdjustment / 7.0f - (0.14f * resolutionModifier)};
|
2022-03-14 18:51:48 +00:00
|
|
|
shaderHeight = height * modifier;
|
2022-03-11 22:17:04 +00:00
|
|
|
}
|
2022-03-14 18:51:48 +00:00
|
|
|
if (mScanlinelShader) {
|
|
|
|
if (mLastShader != mScanlinelShader)
|
|
|
|
mScanlinelShader->activateShaders();
|
|
|
|
mScanlinelShader->setModelViewProjectionMatrix(mTrans);
|
|
|
|
if (mLastShader != mScanlinelShader)
|
|
|
|
mScanlinelShader->setAttribPointers();
|
|
|
|
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices,
|
|
|
|
GL_DYNAMIC_DRAW));
|
|
|
|
mScanlinelShader->setOpacity(vertices->opacity);
|
2022-12-14 19:17:41 +00:00
|
|
|
mScanlinelShader->setBrightness(vertices->brightness);
|
2022-03-17 18:33:09 +00:00
|
|
|
mScanlinelShader->setSaturation(vertices->saturation);
|
2022-03-14 18:51:48 +00:00
|
|
|
mScanlinelShader->setTextureSize({shaderWidth, shaderHeight});
|
2023-02-06 22:38:35 +00:00
|
|
|
mScanlinelShader->setFlags(vertices->shaderFlags);
|
2022-03-14 18:51:48 +00:00
|
|
|
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
|
|
|
|
mLastShader = mScanlinelShader;
|
2020-08-30 20:19:37 +00:00
|
|
|
}
|
2020-06-26 15:17:35 +00:00
|
|
|
}
|
2022-03-14 18:51:48 +00:00
|
|
|
}
|
2020-06-26 15:17:35 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
void RendererOpenGL::shaderPostprocessing(unsigned int shaders,
|
|
|
|
const Renderer::postProcessingParams& parameters,
|
|
|
|
unsigned char* textureRGBA)
|
|
|
|
{
|
|
|
|
Vertex vertices[4];
|
|
|
|
std::vector<unsigned int> shaderList;
|
|
|
|
float widthf {getScreenWidth()};
|
|
|
|
float heightf {getScreenHeight()};
|
|
|
|
GLuint width {static_cast<GLuint>(widthf)};
|
|
|
|
GLuint height {static_cast<GLuint>(heightf)};
|
2023-02-06 22:38:35 +00:00
|
|
|
const int screenRotation {getScreenRotation()};
|
2023-02-12 21:14:09 +00:00
|
|
|
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);
|
|
|
|
}
|
2022-03-14 18:51:48 +00:00
|
|
|
|
|
|
|
// Set vertex positions and texture coordinates to full screen as all
|
|
|
|
// post-processing is applied to the complete screen area.
|
|
|
|
// clang-format off
|
|
|
|
vertices[0] = {{0.0f, 0.0f }, {0.0f, 1.0f}, 0xFFFFFFFF};
|
|
|
|
vertices[1] = {{0.0f, heightf}, {0.0f, 0.0f}, 0xFFFFFFFF};
|
|
|
|
vertices[2] = {{widthf, 0.0f }, {1.0f, 1.0f}, 0xFFFFFFFF};
|
|
|
|
vertices[3] = {{widthf, heightf}, {1.0f, 0.0f}, 0xFFFFFFFF};
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
vertices->opacity = parameters.opacity;
|
|
|
|
vertices->saturation = parameters.saturation;
|
|
|
|
vertices->dimming = parameters.dimming;
|
2022-12-12 19:42:54 +00:00
|
|
|
vertices->shaderFlags = ShaderFlags::POST_PROCESSING | ShaderFlags::PREMULTIPLIED;
|
2022-03-14 18:51:48 +00:00
|
|
|
|
2023-02-06 22:38:35 +00:00
|
|
|
if (screenRotation == 90 || screenRotation == 270)
|
|
|
|
vertices->shaderFlags |= ShaderFlags::ROTATED;
|
|
|
|
|
2022-03-14 21:30:24 +00:00
|
|
|
if (shaders & Shader::CORE)
|
|
|
|
shaderList.push_back(Shader::CORE);
|
|
|
|
if (shaders & Shader::BLUR_HORIZONTAL)
|
|
|
|
shaderList.push_back(Shader::BLUR_HORIZONTAL);
|
|
|
|
if (shaders & Shader::BLUR_VERTICAL)
|
|
|
|
shaderList.push_back(Shader::BLUR_VERTICAL);
|
|
|
|
if (shaders & Shader::SCANLINES)
|
|
|
|
shaderList.push_back(Shader::SCANLINES);
|
2022-03-14 18:51:48 +00:00
|
|
|
|
|
|
|
setMatrix(getIdentity());
|
|
|
|
bindTexture(mPostProcTexture1);
|
|
|
|
|
|
|
|
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO1));
|
|
|
|
|
2023-02-06 22:38:35 +00:00
|
|
|
int shaderCalls {0};
|
|
|
|
bool evenBlurPasses {true};
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
// Blit the screen contents to mPostProcTexture.
|
2023-02-06 22:38:35 +00:00
|
|
|
if (screenRotation == 0) {
|
2023-02-12 21:14:09 +00:00
|
|
|
GL_CHECK_ERROR(glBlitFramebuffer(
|
|
|
|
0, 0, width + mPaddingWidth, height - mScreenOffsetY, -mScreenOffsetX - mPaddingWidth,
|
|
|
|
mScreenOffsetY, width - mScreenOffsetX, height, GL_COLOR_BUFFER_BIT, GL_NEAREST));
|
2023-02-06 22:38:35 +00:00
|
|
|
}
|
|
|
|
else if (screenRotation == 90 || screenRotation == 270) {
|
|
|
|
if (!evenBlurPasses || !textureRGBA)
|
2023-02-12 21:14:09 +00:00
|
|
|
GL_CHECK_ERROR(glBlitFramebuffer(0, 0, height + mPaddingWidth, width - mScreenOffsetY,
|
|
|
|
-mScreenOffsetX - mPaddingWidth, mScreenOffsetY,
|
|
|
|
height - mScreenOffsetX, width, GL_COLOR_BUFFER_BIT,
|
|
|
|
GL_NEAREST));
|
2023-02-06 22:38:35 +00:00
|
|
|
else
|
2023-02-12 21:14:09 +00:00
|
|
|
GL_CHECK_ERROR(glBlitFramebuffer(0, 0, height + mPaddingWidth, width - mScreenOffsetY,
|
|
|
|
height + mScreenOffsetX + mPaddingWidth,
|
|
|
|
width - mScreenOffsetY, mScreenOffsetX, 0,
|
2023-02-06 22:38:35 +00:00
|
|
|
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)
|
2023-02-12 21:14:09 +00:00
|
|
|
GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width + mPaddingWidth, height - mScreenOffsetY,
|
|
|
|
-mScreenOffsetX - mPaddingWidth, mScreenOffsetY,
|
|
|
|
width - mScreenOffsetX, height, GL_COLOR_BUFFER_BIT,
|
|
|
|
GL_NEAREST));
|
2023-02-06 22:38:35 +00:00
|
|
|
else
|
2023-02-12 21:14:09 +00:00
|
|
|
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));
|
2023-02-06 22:38:35 +00:00
|
|
|
}
|
2022-03-14 18:51:48 +00:00
|
|
|
|
2023-02-06 22:38:35 +00:00
|
|
|
if (shaderCalls > 1)
|
|
|
|
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO2));
|
2022-03-14 18:51:48 +00:00
|
|
|
|
|
|
|
bool firstFBO {true};
|
|
|
|
|
2023-02-06 22:38:35 +00:00
|
|
|
for (size_t i {0}; i < shaderList.size(); ++i) {
|
2022-03-14 18:51:48 +00:00
|
|
|
vertices->shaders = shaderList[i];
|
2022-10-11 16:11:36 +00:00
|
|
|
int shaderPasses {1};
|
2022-03-14 18:51:48 +00:00
|
|
|
// For the blur shaders there is an optional variable to set the number of passes
|
|
|
|
// to execute, which proportionally affects the blur amount.
|
2022-03-14 21:30:24 +00:00
|
|
|
if (shaderList[i] == Renderer::Shader::BLUR_HORIZONTAL ||
|
|
|
|
shaderList[i] == Renderer::Shader::BLUR_VERTICAL) {
|
2022-03-14 18:51:48 +00:00
|
|
|
shaderPasses = parameters.blurPasses;
|
2020-06-26 15:17:35 +00:00
|
|
|
}
|
|
|
|
|
2023-02-06 22:38:35 +00:00
|
|
|
for (int p {0}; p < shaderPasses; ++p) {
|
|
|
|
if (!textureRGBA && i == shaderList.size() - 1 && p == shaderPasses - 1) {
|
2022-03-14 18:51:48 +00:00
|
|
|
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
|
2023-02-12 21:14:09 +00:00
|
|
|
if (offsetOrPadding)
|
|
|
|
setViewport(mViewport);
|
2022-03-14 18:51:48 +00:00
|
|
|
drawTriangleStrips(vertices, 4, BlendFactor::SRC_ALPHA,
|
|
|
|
BlendFactor::ONE_MINUS_SRC_ALPHA);
|
|
|
|
break;
|
|
|
|
}
|
2023-02-06 22:38:35 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
drawTriangleStrips(vertices, 4, BlendFactor::SRC_ALPHA,
|
|
|
|
BlendFactor::ONE_MINUS_SRC_ALPHA);
|
2023-02-06 22:38:35 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
if (firstFBO) {
|
|
|
|
bindTexture(mPostProcTexture2);
|
|
|
|
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mShaderFBO2));
|
|
|
|
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO1));
|
|
|
|
GL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
|
|
|
|
firstFBO = false;
|
2021-01-06 23:17:59 +00:00
|
|
|
}
|
|
|
|
else {
|
2022-03-14 18:51:48 +00:00
|
|
|
bindTexture(mPostProcTexture1);
|
|
|
|
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mShaderFBO1));
|
|
|
|
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mShaderFBO2));
|
|
|
|
GL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
|
|
|
|
firstFBO = true;
|
2020-06-26 15:17:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
// If textureRGBA has an address, it means that the output should go to this
|
|
|
|
// texture rather than to the screen. The glReadPixels() function is slow, but
|
|
|
|
// since this will typically only run every now and then to create a cached
|
|
|
|
// screen texture, it doesn't really matter.
|
|
|
|
if (textureRGBA) {
|
|
|
|
if (firstFBO)
|
|
|
|
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mShaderFBO1));
|
|
|
|
else
|
|
|
|
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, mShaderFBO2));
|
2019-08-08 20:16:11 +00:00
|
|
|
|
2022-10-27 22:08:41 +00:00
|
|
|
#if defined(USE_OPENGLES)
|
2023-02-06 22:38:35 +00:00
|
|
|
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));
|
2022-10-27 22:08:41 +00:00
|
|
|
#else
|
2023-02-06 22:38:35 +00:00
|
|
|
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));
|
2022-10-27 22:08:41 +00:00
|
|
|
#endif
|
2022-03-14 18:51:48 +00:00
|
|
|
GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
|
|
|
|
}
|
2020-09-04 16:59:19 +00:00
|
|
|
|
2022-03-14 18:51:48 +00:00
|
|
|
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0));
|
2023-02-12 21:14:09 +00:00
|
|
|
|
|
|
|
if (offsetOrPadding)
|
|
|
|
setViewport(mViewport);
|
2022-03-14 18:51:48 +00:00
|
|
|
}
|