Added a GLSL shader to convert the color model BGRA to RGBA.

Also added support for specifying a separate format as compared to internalFormat when creating textures, although the shader should be used primarily as this is not really supported by the OpenGL standard.
This commit is contained in:
Leon Styhre 2022-01-07 18:54:52 +01:00
parent 7430a8b5f5
commit 0c552dd8fb
9 changed files with 80 additions and 14 deletions

View file

@ -271,6 +271,7 @@ namespace Renderer
shaderFiles.push_back(":/shaders/glsl/blur_horizontal.glsl");
shaderFiles.push_back(":/shaders/glsl/blur_vertical.glsl");
shaderFiles.push_back(":/shaders/glsl/scanlines.glsl");
shaderFiles.push_back(":/shaders/glsl/bgra_to_rgba.glsl");
for (auto it = shaderFiles.cbegin(); it != shaderFiles.cend(); ++it) {
Shader* loadShader = new Shader();

View file

@ -26,6 +26,7 @@ namespace Renderer
const unsigned int SHADER_BLUR_HORIZONTAL{8};
const unsigned int SHADER_BLUR_VERTICAL{16};
const unsigned int SHADER_SCANLINES{32};
const unsigned int SHADER_BGRA_TO_RGBA{64};
struct shaderParameters {
std::array<GLfloat, 2> textureSize;
@ -94,6 +95,7 @@ namespace Renderer
{
enum Type {
RGBA, // Replace with AllowShortEnumsOnASingleLine: false (clang-format >=11.0).
BGRA,
ALPHA
};
}
@ -170,6 +172,7 @@ namespace Renderer
bool createContext();
void destroyContext();
unsigned int createTexture(const Texture::Type type,
const Texture::Type format,
const bool linearMinify,
const bool linearMagnify,
const bool repeat,

View file

@ -45,6 +45,7 @@ namespace Renderer
// clang-format off
switch (_type) {
case Texture::RGBA: { return GL_RGBA; } break;
case Texture::BGRA: { return GL_BGRA; } break;
case Texture::ALPHA: { return GL_ALPHA; } break;
default: { return GL_ZERO; }
}
@ -142,7 +143,7 @@ namespace Renderer
}
uint8_t data[4] = {255, 255, 255, 255};
whiteTexture = createTexture(Texture::RGBA, false, false, true, 1, 1, data);
whiteTexture = createTexture(Texture::RGBA, Texture::RGBA, false, false, true, 1, 1, data);
GL_CHECK_ERROR(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
GL_CHECK_ERROR(glEnable(GL_TEXTURE_2D));
@ -167,6 +168,7 @@ namespace Renderer
}
unsigned int createTexture(const Texture::Type type,
const Texture::Type format,
const bool linearMinify,
const bool linearMagnify,
const bool repeat,
@ -175,6 +177,7 @@ namespace Renderer
void* data)
{
const GLenum textureType = convertTextureType(type);
const GLenum textureFormat = convertTextureType(format);
unsigned int texture;
GL_CHECK_ERROR(glGenTextures(1, &texture));
@ -192,8 +195,11 @@ namespace Renderer
GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
linearMagnify ? static_cast<GLfloat>(GL_LINEAR) :
static_cast<GLfloat>(GL_NEAREST)));
GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureType,
// Setting different values for internalFormat and format is not really supported by the
// OpenGL standard so hopefully it works with all drivers and on all operating systems.
// This is only intended as a last resort anyway, normally the BGRA_TO_RGBA shader should
// be used for color model conversion.
GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureFormat,
GL_UNSIGNED_BYTE, data));
return texture;
@ -355,6 +361,16 @@ namespace Renderer
runShader->deactivateShaders();
}
}
if (vertices->shaders & SHADER_BGRA_TO_RGBA) {
Shader* runShader = getShaderProgram(SHADER_BGRA_TO_RGBA);
if (runShader) {
runShader->activateShaders();
runShader->setModelViewProjectionMatrix(getProjectionMatrix() * trans);
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, numVertices));
runShader->deactivateShaders();
}
}
}
#endif
}
@ -470,8 +486,8 @@ namespace Renderer
vertices[0].saturation = parameters.fragmentSaturation;
setMatrix(getIdentity());
GLuint screenTexture =
createTexture(Texture::RGBA, false, false, false, width, height, nullptr);
GLuint screenTexture = createTexture(Texture::RGBA, Texture::RGBA, false, false, false,
width, height, nullptr);
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0));

View file

@ -43,9 +43,10 @@ namespace Renderer
{
// clang-format off
switch (_type) {
case Texture::RGBA: { return GL_RGBA; } break;
case Texture::ALPHA: { return GL_ALPHA; } break;
default: { return GL_ZERO; }
case Texture::RGBA: { return GL_RGBA; } break;
case Texture::BGRA: { return GL_BGRA_EXT; } break;
case Texture::ALPHA: { return GL_ALPHA; } break;
default: { return GL_ZERO; }
}
// clang-format on
}
@ -91,7 +92,7 @@ namespace Renderer
"MISSING");
uint8_t data[4] = {255, 255, 255, 255};
whiteTexture = createTexture(Texture::RGBA, false, false, true, 1, 1, data);
whiteTexture = createTexture(Texture::RGBA, Texture::RGBA, false, false, true, 1, 1, data);
GL_CHECK_ERROR(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
GL_CHECK_ERROR(glEnable(GL_TEXTURE_2D));
@ -112,6 +113,7 @@ namespace Renderer
}
unsigned int createTexture(const Texture::Type type,
const Texture::Type format,
const bool linearMinify,
const bool linearMagnify,
const bool repeat,
@ -120,6 +122,7 @@ namespace Renderer
void* data)
{
const GLenum textureType = convertTextureType(type);
const GLenum textureFormat = convertTextureType(format);
unsigned int texture;
GL_CHECK_ERROR(glGenTextures(1, &texture));
@ -134,7 +137,11 @@ namespace Renderer
GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
linearMagnify ? GL_LINEAR : GL_NEAREST));
GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureType,
// Setting different values for internalFormat and format is not really supported by the
// OpenGL standard so hopefully it works with all drivers and on all operating systems.
// This is only intended as a last resort anyway, normally the BGRA_TO_RGBA shader should
// be used for color model conversion.
GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureFormat,
GL_UNSIGNED_BYTE, data));
return texture;

View file

@ -199,8 +199,8 @@ bool Font::FontTexture::findEmpty(const glm::ivec2& size, glm::ivec2& cursor_out
void Font::FontTexture::initTexture()
{
assert(textureId == 0);
textureId = Renderer::createTexture(Renderer::Texture::ALPHA, false, false, false,
textureSize.x, textureSize.y, nullptr);
textureId = Renderer::createTexture(Renderer::Texture::ALPHA, Renderer::Texture::ALPHA, false,
false, false, textureSize.x, textureSize.y, nullptr);
}
void Font::FontTexture::deinitTexture()

View file

@ -13,7 +13,6 @@
#include "ImageIO.h"
#include "Log.h"
#include "renderers/Renderer.h"
#include "resources/ResourceManager.h"
#include "utils/StringUtil.h"
@ -28,6 +27,7 @@ TextureData::TextureData(bool tile)
: mTile{tile}
, mTextureID{0}
, mDataRGBA({})
, mFormat{Renderer::Texture::RGBA}
, mWidth{0}
, mHeight{0}
, mSourceWidth{0.0f}
@ -219,7 +219,7 @@ bool TextureData::uploadAndBind()
// Upload texture.
mTextureID =
Renderer::createTexture(Renderer::Texture::RGBA, true, mLinearMagnify, mTile,
Renderer::createTexture(Renderer::Texture::RGBA, mFormat, true, mLinearMagnify, mTile,
static_cast<const unsigned int>(mWidth),
static_cast<const unsigned int>(mHeight), mDataRGBA.data());
}

View file

@ -9,6 +9,7 @@
#ifndef ES_CORE_RESOURCES_TEXTURE_DATA_H
#define ES_CORE_RESOURCES_TEXTURE_DATA_H
#include "renderers/Renderer.h"
#include "utils/MathUtil.h"
#include <atomic>
@ -63,6 +64,8 @@ public:
// Whether to rasterize the image even if a size has not been set yet.
void setForceRasterization(bool setting) { mForceRasterization = setting; }
void setFormat(Renderer::Texture::Type format) { mFormat = format; }
// Has the image been loaded but not yet been rasterized as the size was not known?
bool getPendingRasterization() { return mPendingRasterization; }
@ -77,6 +80,7 @@ private:
std::string mPath;
std::atomic<unsigned int> mTextureID;
std::vector<unsigned char> mDataRGBA;
Renderer::Texture::Type mFormat;
std::atomic<int> mWidth;
std::atomic<int> mHeight;
std::atomic<float> mSourceWidth;

View file

@ -45,6 +45,8 @@ public:
return (mTextureData != nullptr ? mTextureData->getPendingRasterization() : false);
}
void setFormat(Renderer::Texture::Type format) { mTextureData->setFormat(format); }
std::string getTextureFilePath();
void rasterizeAt(float width, float height);

View file

@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT
//
// EmulationStation Desktop Edition
// bgra_to_rgba.glsl
//
// Convert from color model BGRA to RGBA.
//
#if defined(VERTEX)
// Vertex section of code:
uniform mat4 MVPMatrix;
varying vec2 vTexCoord;
void main(void)
{
vTexCoord = gl_MultiTexCoord0.xy;
gl_Position = MVPMatrix * gl_Vertex;
}
#elif defined(FRAGMENT)
// Fragment section of code:
uniform sampler2D myTexture;
varying vec2 vTexCoord;
void main()
{
vec4 color = texture2D(myTexture, vTexCoord);
gl_FragColor = vec4(color.bgra);
}
#endif