Updates to the OpenGL shader handling.

This commit is contained in:
Leon Styhre 2020-09-12 12:14:48 +02:00
parent fcb139e567
commit 3643c08caf
11 changed files with 231 additions and 142 deletions

View file

@ -169,6 +169,7 @@ namespace Renderer
std::vector<std::string> shaderFiles;
shaderFiles.push_back(":/shaders/glsl/desaturate.glsl");
shaderFiles.push_back(":/shaders/glsl/dim.glsl");
shaderFiles.push_back(":/shaders/glsl/blur_horizontal.glsl");
shaderFiles.push_back(":/shaders/glsl/blur_vertical.glsl");
shaderFiles.push_back(":/shaders/glsl/scanlines.glsl");
@ -258,6 +259,8 @@ namespace Renderer
break;
}
mProjectionMatrix = projection;
setViewport(viewport);
setProjection(projection);
swapBuffers();
@ -358,7 +361,8 @@ namespace Renderer
vertices[i].pos.round();
bindTexture(0);
drawTriangleStrips(vertices, 4, _srcBlendFactor, _dstBlendFactor);
drawTriangleStrips(vertices, 4, Transform4x4f::Identity(),
_srcBlendFactor, _dstBlendFactor);
}
unsigned int rgbaToABGR(const unsigned int _color)
@ -398,6 +402,11 @@ namespace Renderer
return nullptr;
};
const Transform4x4f getProjectionMatrix()
{
return mProjectionMatrix;
}
SDL_Window* getSDLWindow() { return sdlWindow; }
int getWindowWidth() { return windowWidth; }
int getWindowHeight() { return windowHeight; }

View file

@ -8,6 +8,7 @@
#ifndef ES_CORE_RENDERER_RENDERER_H
#define ES_CORE_RENDERER_RENDERER_H
#include "math/Transform4x4f.h"
#include "math/Vector2f.h"
#include "Log.h"
#include "Shader_GL21.h"
@ -22,26 +23,30 @@ struct SDL_Window;
namespace Renderer
{
const unsigned int SHADER_DESATURATE = 1;
const unsigned int SHADER_BLUR_HORIZONTAL = 2;
const unsigned int SHADER_BLUR_VERTICAL = 4;
const unsigned int SHADER_SCANLINES = 8;
const unsigned int SHADER_DIM = 2;
const unsigned int SHADER_BLUR_HORIZONTAL = 4;
const unsigned int SHADER_BLUR_VERTICAL = 8;
const unsigned int SHADER_SCANLINES = 16;
struct shaderParameters {
std::array<GLfloat, 2> textureSize;
std::array<GLfloat, 4> textureCoordinates;
float fragmentSaturation;
float fragmentDimValue;
unsigned int shaderPasses;
shaderParameters()
: textureSize({0.0, 0.0}),
textureCoordinates({0.0, 0.0, 0.0, 0.0}),
fragmentSaturation(1.0),
fragmentDimValue(0.4),
shaderPasses(1)
{};
};
static std::vector<Shader*> sShaderProgramVector;
static GLuint shaderFBO;
static Transform4x4f mProjectionMatrix;
#if !defined(NDEBUG)
#define GL_CHECK_ERROR(Function) (Function, _GLCheckError(#Function))
@ -149,6 +154,7 @@ namespace Renderer
unsigned int abgrToRGBA(unsigned int color);
Shader* getShaderProgram(unsigned int shaderID);
const Transform4x4f getProjectionMatrix();
void shaderPostprocessing(unsigned int shaders,
const Renderer::shaderParameters& parameters = shaderParameters(),
unsigned char* textureRGBA = nullptr);
@ -184,9 +190,10 @@ namespace Renderer
void drawTriangleStrips(
const Vertex* _vertices,
const unsigned int _numVertices,
const Transform4x4f& _trans = Transform4x4f::Identity(),
const Blend::Factor _srcBlendFactor = Blend::SRC_ALPHA,
const Blend::Factor _dstBlendFactor = Blend::ONE_MINUS_SRC_ALPHA,
const shaderParameters& parameters = shaderParameters());
const shaderParameters& _parameters = shaderParameters());
void setProjection(const Transform4x4f& _projection);
void setMatrix(const Transform4x4f& _matrix);
void setViewport(const Rect& _viewport);

View file

@ -241,12 +241,14 @@ namespace Renderer
void drawTriangleStrips(
const Vertex* _vertices,
const unsigned int _numVertices,
const Transform4x4f& _trans,
const Blend::Factor _srcBlendFactor,
const Blend::Factor _dstBlendFactor,
const shaderParameters& parameters)
const shaderParameters& _parameters)
{
float width = _vertices[3].pos[0];
float height = _vertices[3].pos[1];
GL_CHECK_ERROR(glVertexPointer(2, GL_FLOAT, sizeof(Vertex), &_vertices[0].pos));
GL_CHECK_ERROR(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &_vertices[0].tex));
GL_CHECK_ERROR(glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), &_vertices[0].col));
@ -254,16 +256,19 @@ namespace Renderer
GL_CHECK_ERROR(glBlendFunc(convertBlendFactor(_srcBlendFactor),
convertBlendFactor(_dstBlendFactor)));
if (_vertices[0].shaders == 0) {
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, _numVertices));
for (unsigned int i = 0; i < parameters.shaderPasses; i++) {
// If saturation is set below the maximum (default) value, run the desaturation shader.
if (_vertices->saturation < 1.0 || parameters.fragmentSaturation < 1.0) {
}
else {
for (unsigned int i = 0; i < _parameters.shaderPasses; i++) {
// If saturation is set below the maximum (default) value, run the
// desaturation shader.
if (_vertices->saturation < 1.0 || _parameters.fragmentSaturation < 1.0) {
Shader* runShader = getShaderProgram(SHADER_DESATURATE);
// Only try to use the shader if it has been loaded properly.
if (runShader) {
runShader->activateShaders();
runShader->getVariableLocations(runShader->getProgramID());
runShader->setModelViewProjectionMatrix(getProjectionMatrix() * _trans);
runShader->setSaturation(_vertices->saturation);
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, _numVertices));
runShader->deactivateShaders();
@ -271,11 +276,22 @@ namespace Renderer
}
// Check if any other shaders are set to be used and if so, run them.
if (_vertices->shaders & SHADER_DIM) {
Shader* runShader = getShaderProgram(SHADER_DIM);
if (runShader) {
runShader->activateShaders();
runShader->setModelViewProjectionMatrix(getProjectionMatrix() * _trans);
runShader->setDimValue(_parameters.fragmentDimValue);
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, _numVertices));
runShader->deactivateShaders();
}
}
if (_vertices->shaders & SHADER_BLUR_HORIZONTAL) {
Shader* runShader = getShaderProgram(SHADER_BLUR_HORIZONTAL);
if (runShader) {
runShader->activateShaders();
runShader->getVariableLocations(runShader->getProgramID());
runShader->setModelViewProjectionMatrix(getProjectionMatrix() * _trans);
runShader->setTextureSize({width, height});
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, _numVertices));
runShader->deactivateShaders();
@ -286,7 +302,7 @@ namespace Renderer
Shader* runShader = getShaderProgram(SHADER_BLUR_VERTICAL);
if (runShader) {
runShader->activateShaders();
runShader->getVariableLocations(runShader->getProgramID());
runShader->setModelViewProjectionMatrix(getProjectionMatrix() * _trans);
runShader->setTextureSize({width, height});
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, _numVertices));
runShader->deactivateShaders();
@ -298,10 +314,10 @@ namespace Renderer
float shaderWidth = width * 1.2;
// Workaround to get the scanlines to render somehow proportional to the
// resolution. A better solution is for sure needed.
float shaderHeight = height + height / ((int)height >> 7) * 1.5;
float shaderHeight = height + height / ((int)height >> 7) * 2.0;
if (runShader) {
runShader->activateShaders();
runShader->getVariableLocations(runShader->getProgramID());
runShader->setModelViewProjectionMatrix(getProjectionMatrix() * _trans);
runShader->setTextureSize({shaderWidth, shaderHeight});
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, _numVertices));
runShader->deactivateShaders();
@ -309,6 +325,7 @@ namespace Renderer
}
}
}
}
void setProjection(const Transform4x4f& _projection)
{
@ -386,22 +403,11 @@ namespace Renderer
vertices[3] = { { widthf, heightf }, { 1, 0 }, 0};
vertices[0].shaders = shaders;
vertices[1].shaders = shaders;
vertices[2].shaders = shaders;
vertices[3].shaders = shaders;
if (parameters.fragmentSaturation < 1.0) {
if (parameters.fragmentSaturation < 1.0)
vertices[0].saturation = parameters.fragmentSaturation;
vertices[1].saturation = parameters.fragmentSaturation;
vertices[2].saturation = parameters.fragmentSaturation;
vertices[3].saturation = parameters.fragmentSaturation;
}
setMatrix(Transform4x4f::Identity());
// The following method to apply the shaders is not optimal as it requires
// glBlitFramebuffer() to run twice. However, this function seems to be
// very fast so maybe it's not a practical issue.
GLuint screenTexture = createTexture(Texture::RGBA, false, false, width, height, nullptr);
GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0));
@ -420,7 +426,8 @@ namespace Renderer
GL_COLOR_BUFFER_BIT, GL_NEAREST));
// Apply/render the shaders.
drawTriangleStrips(vertices, 4, Blend::SRC_ALPHA, Blend::ONE_MINUS_SRC_ALPHA, parameters);
drawTriangleStrips(vertices, 4, Transform4x4f::Identity(),
Blend::SRC_ALPHA, Blend::ONE_MINUS_SRC_ALPHA, parameters);
// 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 would

View file

@ -198,8 +198,10 @@ namespace Renderer
void drawTriangleStrips(
const Vertex* _vertices,
const unsigned int _numVertices,
const Transform4x4f& _trans,
const Blend::Factor _srcBlendFactor,
const Blend::Factor _dstBlendFactor)
const Blend::Factor _dstBlendFactor,
const shaderParameters& _parameters)
{
GL_CHECK_ERROR(glVertexPointer(2, GL_FLOAT, sizeof(Vertex), &_vertices[0].pos));
GL_CHECK_ERROR(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &_vertices[0].tex));

View file

@ -16,10 +16,12 @@ namespace Renderer
{
Renderer::Shader::Shader()
: mProgramID(-1),
shaderMVPMatrix(-1),
shaderTextureSize(-1),
shaderTextureCoord(-1),
shaderColor(-1),
shaderSaturation(-1)
shaderSaturation(-1),
shaderDimValue(-1)
{
}
@ -87,6 +89,7 @@ namespace Renderer
return false;
}
getVariableLocations(mProgramID);
return true;
}
@ -98,35 +101,53 @@ namespace Renderer
void Renderer::Shader::getVariableLocations(GLuint programID)
{
// Some of the variable names are chosen to be compatible with the RetroArch GLSL shaders.
shaderMVPMatrix = glGetUniformLocation(mProgramID, "MVPMatrix");
shaderTextureSize = glGetUniformLocation(mProgramID, "TextureSize");
shaderTextureCoord = glGetAttribLocation(mProgramID, "TexCoord");
shaderColor = glGetAttribLocation(mProgramID, "COLOR");
shaderSaturation = glGetUniformLocation(mProgramID, "saturation");
shaderDimValue = glGetUniformLocation(mProgramID, "dimValue");
}
void Renderer::Shader::setModelViewProjectionMatrix(Transform4x4f mvpMatrix)
{
if (shaderMVPMatrix != -1)
GL_CHECK_ERROR(glUniformMatrix4fv(shaderMVPMatrix, 1, GL_FALSE, (GLfloat*)&mvpMatrix));
}
void Renderer::Shader::setTextureSize(std::array<GLfloat, 2> shaderVec2)
{
if (shaderTextureSize != -1)
GL_CHECK_ERROR(glUniform2f(shaderTextureSize, shaderVec2[0], shaderVec2[1]));
}
void Renderer::Shader::setTextureCoordinates(std::array<GLfloat, 4> shaderVec4)
{
glEnableVertexAttribArray(shaderTextureCoord);
glVertexAttribPointer(shaderTextureCoord, 4, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*)(uintptr_t)&shaderVec4);
if (shaderTextureCoord != -1) {
glVertexAttrib4f(shaderTextureCoord, shaderVec4[0], shaderVec4[1],
shaderVec4[2], shaderVec4[3]);
}
}
void Renderer::Shader::setColor(std::array<GLfloat, 4> shaderVec4)
{
if (shaderColor != -1)
GL_CHECK_ERROR(glUniform4f(shaderColor, shaderVec4[0],
shaderVec4[1], shaderVec4[2], shaderVec4[3]));
}
void Renderer::Shader::setSaturation(GLfloat saturation)
{
if (shaderSaturation != -1)
GL_CHECK_ERROR(glUniform1f(shaderSaturation, saturation));
}
void Renderer::Shader::setDimValue(GLfloat dimValue)
{
if (shaderDimValue != -1)
GL_CHECK_ERROR(glUniform1f(shaderDimValue, dimValue));
}
void Renderer::Shader::activateShaders()
{
GL_CHECK_ERROR(glUseProgram(mProgramID));

View file

@ -9,6 +9,8 @@
#define GL_GLEXT_PROTOTYPES
#include "math/Transform4x4f.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
#include <array>
@ -32,10 +34,12 @@ namespace Renderer
// Get references to the variables inside the compiled shaders.
void getVariableLocations(GLuint programID);
// One-way communication with the compiled shaders.
void setModelViewProjectionMatrix(Transform4x4f mvpMatrix);
void setTextureSize(std::array<GLfloat, 2> shaderVec2);
void setTextureCoordinates(std::array<GLfloat, 4> shaderVec4);
void setColor(std::array<GLfloat, 4> shaderVec4);
void setSaturation(GLfloat saturation);
void setDimValue(GLfloat dimValue);
// Sets the shader program to use the loaded shaders.
void activateShaders();
// Sets the shader program to 0 which reverts to the fixed function pipeline.
@ -51,10 +55,12 @@ namespace Renderer
std::vector<std::tuple<std::string, std::string, GLenum>> shaderVector;
// Variables used for communication with the compiled shaders.
GLint shaderMVPMatrix;
GLint shaderTextureSize;
GLint shaderTextureCoord;
GLint shaderColor;
GLint shaderSaturation;
GLint shaderDimValue;
};
} // Renderer

View file

@ -42,7 +42,7 @@ uniform COMPAT_PRECISION vec2 InputSize;
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_Position = MVPMatrix * gl_Vertex;
// gl_Position = MVPMatrix * VertexCoord;
COL0 = COLOR;
TEX0.xy = gl_MultiTexCoord0.xy;
@ -132,6 +132,6 @@ void main()
#endif
FragColor = vec4(color);
// FragColor = vec4(0.4, 0.0, 0.2, 0.6);
// FragColor = vec4(0.4, 0.0, 0.2, 0.2);
}
#endif

View file

@ -43,7 +43,7 @@ uniform COMPAT_PRECISION vec2 InputSize;
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_Position = MVPMatrix * gl_Vertex;
// gl_Position = MVPMatrix * VertexCoord;
COL0 = COLOR;
TEX0.xy = gl_MultiTexCoord0.xy;

View file

@ -1,7 +1,7 @@
//
// desaturate.glsl
//
// Desaturates textures such as game images.
// Desaturates textures.
// The uniform variable 'saturation' sets the saturation intensity.
// Setting this to the value 0 results in complete desaturation (grayscale).
//
@ -9,12 +9,13 @@
#if defined(VERTEX)
// Vertex section of code:
uniform mat4 MVPMatrix;
varying vec2 vTexCoord;
void main(void)
{
vTexCoord = gl_MultiTexCoord0.xy;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_Position = MVPMatrix * gl_Vertex;
}
#elif defined(FRAGMENT)
@ -27,9 +28,9 @@ varying vec2 vTexCoord;
void main()
{
vec4 color = texture2D(myTexture, vTexCoord);
vec3 grayscale = vec3(dot(color.rgb, vec3(0.2125, 0.7154, 0.0721)));
vec3 grayscale = vec3(dot(color.rgb, vec3(0.3, 0.59, 0.11)));
vec3 blendedColor = mix(grayscale, color.rgb, saturation);
gl_FragColor = vec4(blendedColor, color.a);
}

View file

@ -0,0 +1,36 @@
//
// dim.glsl
//
// Dims textures.
// The uniform variable 'dimValue' sets the amount of dimming.
// Setting this to the value 0 results in a completely black screen.
//
#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 float dimValue = 0.4;
uniform sampler2D myTexture;
varying vec2 vTexCoord;
void main()
{
vec4 dimColor = vec4(dimValue, dimValue, dimValue, 1.0);
vec4 color = texture2D(myTexture, vTexCoord) * dimColor;
gl_FragColor = color;
}
#endif

View file

@ -68,7 +68,7 @@ uniform COMPAT_PRECISION vec2 InputSize;
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_Position = MVPMatrix * gl_Vertex;
// gl_Position = MVPMatrix * VertexCoord;
COL0 = COLOR;
TEX0.xy = gl_MultiTexCoord0.xy;