2015-01-30 13:59:52 +00:00
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include "N64.h"
|
|
|
|
#include "gSP.h"
|
|
|
|
#include "PostProcessor.h"
|
2015-01-31 07:14:13 +00:00
|
|
|
#include "FrameBuffer.h"
|
2015-01-31 13:03:57 +00:00
|
|
|
#include "GLSLCombiner.h"
|
2015-05-19 14:58:21 +00:00
|
|
|
#include "ShaderUtils.h"
|
2015-01-31 07:50:06 +00:00
|
|
|
#include "Config.h"
|
2015-01-30 13:59:52 +00:00
|
|
|
|
2015-05-30 16:39:19 +00:00
|
|
|
#if defined(GLES3_1)
|
2015-06-10 12:57:13 +00:00
|
|
|
#define SHADER_VERSION "#version 310 es \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
#elif defined(GLES3)
|
2015-05-14 13:55:39 +00:00
|
|
|
#define SHADER_VERSION "#version 300 es \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
#elif defined(GLES2)
|
|
|
|
#define SHADER_VERSION "#version 100 \n"
|
2015-05-14 13:55:39 +00:00
|
|
|
#else
|
|
|
|
#define SHADER_VERSION "#version 330 core \n"
|
|
|
|
#endif
|
|
|
|
|
2015-05-30 16:39:19 +00:00
|
|
|
#ifdef GLES2
|
|
|
|
#define FRAGMENT_SHADER_END " gl_FragColor = fragColor; \n"
|
|
|
|
#else
|
|
|
|
#define FRAGMENT_SHADER_END "\n"
|
|
|
|
#endif
|
|
|
|
|
2016-04-22 20:49:18 +00:00
|
|
|
#ifdef ANDROID
|
|
|
|
PostProcessor PostProcessor::processor;
|
|
|
|
#endif
|
|
|
|
|
2015-01-31 07:14:13 +00:00
|
|
|
static const char * vertexShader =
|
2015-05-14 13:55:39 +00:00
|
|
|
SHADER_VERSION
|
2016-12-31 12:29:50 +00:00
|
|
|
"#if (__VERSION__ > 120) \n"
|
|
|
|
"# define IN in \n"
|
|
|
|
"# define OUT out \n"
|
|
|
|
"#else \n"
|
|
|
|
"# define IN attribute \n"
|
|
|
|
"# define OUT varying \n"
|
|
|
|
"#endif // __VERSION \n"
|
|
|
|
"IN highp vec2 aRectPosition; \n"
|
|
|
|
"IN highp vec2 aTexCoord0; \n"
|
|
|
|
"OUT mediump vec2 vTexCoord; \n"
|
|
|
|
"void main() { \n"
|
|
|
|
"gl_Position = vec4(aRectPosition.x, aRectPosition.y, 0.0, 1.0);\n"
|
|
|
|
"vTexCoord = aTexCoord0; \n"
|
|
|
|
"} \n"
|
2015-01-30 13:59:52 +00:00
|
|
|
;
|
|
|
|
|
2015-01-31 07:14:13 +00:00
|
|
|
static const char* extractBloomShader =
|
2015-05-14 13:55:39 +00:00
|
|
|
SHADER_VERSION
|
2015-05-30 16:39:19 +00:00
|
|
|
"#if (__VERSION__ > 120) \n"
|
|
|
|
"# define IN in \n"
|
|
|
|
"# define OUT out \n"
|
2015-06-10 12:57:13 +00:00
|
|
|
"# define texture2D texture \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
"#else \n"
|
|
|
|
"# define IN varying \n"
|
|
|
|
"# define OUT \n"
|
|
|
|
"#endif // __VERSION __ \n"
|
|
|
|
"IN mediump vec2 vTexCoord; \n"
|
2015-02-01 04:07:42 +00:00
|
|
|
"uniform sampler2D Sample0; \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
"OUT lowp vec4 fragColor; \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
" \n"
|
|
|
|
"uniform lowp int ThresholdLevel; \n"
|
|
|
|
" \n"
|
|
|
|
"void main() \n"
|
|
|
|
"{ \n"
|
2015-02-01 04:07:42 +00:00
|
|
|
" lowp vec4 color = texture2D(Sample0, vTexCoord); \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
" \n"
|
|
|
|
" mediump float lum = dot(vec4(0.30, 0.59, 0.11, 0.0), color);\n"
|
|
|
|
" mediump float scale = lum; \n"
|
|
|
|
" lowp int level = clamp(ThresholdLevel, 2, 6); \n"
|
|
|
|
" for (int i = 1; i < level; ++i) \n"
|
|
|
|
" scale *= lum; \n"
|
|
|
|
" fragColor = scale*color; \n"
|
|
|
|
" fragColor.a = 1.0; \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
FRAGMENT_SHADER_END
|
2015-01-31 07:14:13 +00:00
|
|
|
"} \n"
|
|
|
|
;
|
|
|
|
|
|
|
|
static const char* seperableBlurShader =
|
|
|
|
/// Author: Nathaniel Meyer
|
|
|
|
///
|
|
|
|
/// Copyright: Nutty Software
|
|
|
|
/// http://www.nutty.ca
|
|
|
|
///
|
|
|
|
/// Fragment shader for performing a seperable blur on the specified texture.
|
2015-05-14 13:55:39 +00:00
|
|
|
SHADER_VERSION
|
2015-05-30 16:39:19 +00:00
|
|
|
"#if (__VERSION__ > 120) \n"
|
|
|
|
"# define IN in \n"
|
|
|
|
"# define OUT out \n"
|
2015-06-10 12:57:13 +00:00
|
|
|
"# define texture2D texture \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
"#else \n"
|
|
|
|
"# define IN varying \n"
|
|
|
|
"# define OUT \n"
|
|
|
|
"#endif // __VERSION __ \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
// Uniform variables.
|
2015-02-01 04:07:42 +00:00
|
|
|
"uniform sampler2D Sample0; \n"
|
2015-01-31 13:03:57 +00:00
|
|
|
"uniform mediump vec2 TexelSize; \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
" \n"
|
2015-01-31 13:03:57 +00:00
|
|
|
"uniform lowp int Orientation; \n"
|
|
|
|
"uniform lowp int BlurAmount; \n"
|
|
|
|
"uniform lowp float BlurScale; \n"
|
|
|
|
"uniform lowp float BlurStrength; \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
" \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
"IN mediump vec2 vTexCoord; \n"
|
|
|
|
"OUT lowp vec4 fragColor; \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
" \n"
|
|
|
|
// Gets the Gaussian value in the first dimension.
|
|
|
|
// "x" Distance from origin on the x-axis.
|
|
|
|
// "deviation" Standard deviation.
|
|
|
|
// returns The gaussian value on the x-axis.
|
2015-01-31 13:03:57 +00:00
|
|
|
"mediump float Gaussian (in mediump float x, in mediump float deviation) \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
"{ \n"
|
2015-01-31 13:03:57 +00:00
|
|
|
" return (1.0 / sqrt(2.0 * 3.141592 * deviation)) * exp(-((x * x) / (2.0 * deviation))); \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
"} \n"
|
|
|
|
" \n"
|
|
|
|
// Fragment shader entry.
|
|
|
|
"void main () \n"
|
|
|
|
"{ \n"
|
|
|
|
" // Locals \n"
|
2015-01-31 13:03:57 +00:00
|
|
|
" mediump float halfBlur = float(BlurAmount) * 0.5; \n"
|
|
|
|
" mediump vec4 colour = vec4(0.0); \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
" \n"
|
|
|
|
" // Gaussian deviation \n"
|
2015-01-31 13:03:57 +00:00
|
|
|
" mediump float deviation = halfBlur * 0.35; \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
" deviation *= deviation; \n"
|
2015-01-31 13:03:57 +00:00
|
|
|
" mediump float strength = 1.0 - BlurStrength; \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
" \n"
|
|
|
|
" if ( Orientation == 0 ) \n"
|
|
|
|
" { \n"
|
|
|
|
" // Horizontal blur \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
" for (lowp int i = 0; i < BlurAmount; ++i) \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
" { \n"
|
2015-01-31 13:03:57 +00:00
|
|
|
" mediump float offset = float(i) - halfBlur; \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
" colour += texture2D(Sample0, vTexCoord + vec2(offset * TexelSize.x * BlurScale, 0.0)) * Gaussian(offset * strength, deviation); \n"
|
|
|
|
" } \n"
|
2015-01-31 13:03:57 +00:00
|
|
|
" } \n"
|
|
|
|
" else \n"
|
|
|
|
" { \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
" // Vertical blur \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
" for (lowp int i = 0; i < BlurAmount; ++i) \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
" { \n"
|
2015-01-31 13:03:57 +00:00
|
|
|
" mediump float offset = float(i) - halfBlur; \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
" colour += texture2D(Sample0, vTexCoord + vec2(0.0, offset * TexelSize.y * BlurScale)) * Gaussian(offset * strength, deviation); \n"
|
|
|
|
" } \n"
|
2015-01-31 13:03:57 +00:00
|
|
|
" } \n"
|
|
|
|
" \n"
|
|
|
|
" // Apply colour \n"
|
|
|
|
" fragColor = clamp(colour, 0.0, 1.0); \n"
|
|
|
|
" fragColor.a = 1.0; \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
FRAGMENT_SHADER_END
|
2015-01-31 13:03:57 +00:00
|
|
|
"} \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
;
|
|
|
|
|
|
|
|
static const char* glowShader =
|
|
|
|
/// Author: Nathaniel Meyer
|
|
|
|
///
|
|
|
|
/// Copyright: Nutty Software
|
|
|
|
/// http://www.nutty.ca
|
|
|
|
///
|
|
|
|
/// Fragment shader for blending two textures using an algorithm that overlays the glowmap.
|
2015-05-14 13:55:39 +00:00
|
|
|
SHADER_VERSION
|
2015-05-30 16:39:19 +00:00
|
|
|
"#if (__VERSION__ > 120) \n"
|
|
|
|
"# define IN in \n"
|
|
|
|
"# define OUT out \n"
|
2015-06-10 12:57:13 +00:00
|
|
|
"# define texture2D texture \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
"#else \n"
|
|
|
|
"# define IN varying \n"
|
|
|
|
"# define OUT \n"
|
|
|
|
"#endif // __VERSION __ \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
// Uniform variables.
|
2015-02-01 04:07:42 +00:00
|
|
|
"uniform sampler2D Sample0; \n"
|
|
|
|
"uniform sampler2D Sample1; \n"
|
2015-01-31 13:03:57 +00:00
|
|
|
"uniform lowp int BlendMode; \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
" \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
"IN mediump vec2 vTexCoord; \n"
|
|
|
|
"OUT lowp vec4 fragColor; \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
" \n"
|
|
|
|
// Fragment shader entry.
|
|
|
|
"void main () \n"
|
|
|
|
"{ \n"
|
2015-01-31 13:03:57 +00:00
|
|
|
" lowp vec4 dst = texture2D(Sample0, vTexCoord); // rendered scene \n"
|
|
|
|
" lowp vec4 src = texture2D(Sample1, vTexCoord); // glowmap \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
" \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
" if (BlendMode == 0) { \n"
|
2015-02-02 08:57:15 +00:00
|
|
|
" // Additive blending (strong result, high overexposure) \n"
|
|
|
|
" fragColor = min(src + dst, 1.0); \n"
|
|
|
|
" fragColor.a = 1.0; \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
" } else if (BlendMode == 1) { \n"
|
2015-02-02 08:57:15 +00:00
|
|
|
" fragColor = clamp((src + dst) - (src * dst), 0.0, 1.0); \n"
|
|
|
|
" fragColor.a = 1.0; \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
" } else if (BlendMode == 2) { \n"
|
2015-02-02 08:57:15 +00:00
|
|
|
" src = (src * 0.5) + 0.5; \n"
|
|
|
|
" \n"
|
|
|
|
" if (src.x <= 0.5) \n"
|
|
|
|
" fragColor.x = dst.x - (1.0 - 2.0 * src.x) * dst.x * (1.0 - dst.x); \n"
|
|
|
|
" else if ((src.x > 0.5) && (dst.x <= 0.25)) \n"
|
|
|
|
" fragColor.x = dst.x + (2.0 * src.x - 1.0) * (4.0 * dst.x * (4.0 * dst.x + 1.0) * (dst.x - 1.0) + 7.0 * dst.x);\n"
|
|
|
|
" else \n"
|
|
|
|
" fragColor.x = dst.x + (2.0 * src.x - 1.0) * (sqrt(dst.x) - dst.x); \n"
|
|
|
|
" if (src.y <= 0.5) \n"
|
|
|
|
" fragColor.y = dst.y - (1.0 - 2.0 * src.y) * dst.y * (1.0 - dst.y); \n"
|
|
|
|
" else if ((src.y > 0.5) && (dst.y <= 0.25)) \n"
|
|
|
|
" fragColor.y = dst.y + (2.0 * src.y - 1.0) * (4.0 * dst.y * (4.0 * dst.y + 1.0) * (dst.y - 1.0) + 7.0 * dst.y);\n"
|
|
|
|
" else \n"
|
|
|
|
" fragColor.y = dst.y + (2.0 * src.y - 1.0) * (sqrt(dst.y) - dst.y); \n"
|
|
|
|
" if (src.z <= 0.5) \n"
|
|
|
|
" fragColor.z = dst.z - (1.0 - 2.0 * src.z) * dst.z * (1.0 - dst.z); \n"
|
|
|
|
" else if ((src.z > 0.5) && (dst.z <= 0.25)) \n"
|
|
|
|
" fragColor.z = dst.z + (2.0 * src.z - 1.0) * (4.0 * dst.z * (4.0 * dst.z + 1.0) * (dst.z - 1.0) + 7.0 * dst.z);\n"
|
|
|
|
" else \n"
|
|
|
|
" fragColor.z = dst.z + (2.0 * src.z - 1.0) * (sqrt(dst.z) - dst.z); \n"
|
|
|
|
" fragColor.a = 1.0; \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
" } else { \n"
|
2015-02-02 08:57:15 +00:00
|
|
|
" // Show just the glow map \n"
|
|
|
|
" fragColor = src; \n"
|
|
|
|
" } \n"
|
2015-05-30 16:39:19 +00:00
|
|
|
FRAGMENT_SHADER_END
|
2015-02-02 08:57:15 +00:00
|
|
|
"} \n"
|
2015-01-31 07:14:13 +00:00
|
|
|
;
|
|
|
|
|
2015-12-23 10:22:30 +00:00
|
|
|
static const char* gammaCorrectionShader =
|
|
|
|
SHADER_VERSION
|
|
|
|
"#if (__VERSION__ > 120) \n"
|
|
|
|
"# define IN in \n"
|
|
|
|
"# define OUT out \n"
|
|
|
|
"# define texture2D texture \n"
|
|
|
|
"#else \n"
|
|
|
|
"# define IN varying \n"
|
|
|
|
"# define OUT \n"
|
|
|
|
"#endif // __VERSION __ \n"
|
|
|
|
"IN mediump vec2 vTexCoord; \n"
|
|
|
|
"uniform sampler2D Sample0; \n"
|
|
|
|
"uniform lowp float uGammaCorrectionLevel; \n"
|
|
|
|
"OUT lowp vec4 fragColor; \n"
|
|
|
|
" \n"
|
|
|
|
"void main() \n"
|
|
|
|
"{ \n"
|
|
|
|
" fragColor = texture2D(Sample0, vTexCoord); \n"
|
|
|
|
" fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / uGammaCorrectionLevel)); \n"
|
|
|
|
FRAGMENT_SHADER_END
|
|
|
|
"} \n"
|
|
|
|
;
|
|
|
|
|
2016-10-29 17:33:05 +00:00
|
|
|
static const char* orientationCorrectionShader =
|
|
|
|
SHADER_VERSION
|
|
|
|
"#if (__VERSION__ > 120) \n"
|
|
|
|
"# define IN in \n"
|
|
|
|
"# define OUT out \n"
|
|
|
|
"# define texture2D texture \n"
|
|
|
|
"#else \n"
|
|
|
|
"# define IN varying \n"
|
|
|
|
"# define OUT \n"
|
|
|
|
"#endif // __VERSION __ \n"
|
|
|
|
"IN mediump vec2 vTexCoord; \n"
|
|
|
|
"uniform sampler2D Sample0; \n"
|
|
|
|
"OUT lowp vec4 fragColor; \n"
|
|
|
|
" \n"
|
|
|
|
"void main() \n"
|
|
|
|
"{ \n"
|
|
|
|
" fragColor = texture2D( Sample0, vec2(1.0 - vTexCoord.x, 1.0 - vTexCoord.y)); \n"
|
|
|
|
FRAGMENT_SHADER_END
|
|
|
|
"} \n"
|
|
|
|
;
|
|
|
|
|
2015-01-31 07:14:13 +00:00
|
|
|
static
|
2016-04-02 12:56:07 +00:00
|
|
|
void _initTexture(CachedTexture * pTexture)
|
2015-01-30 13:59:52 +00:00
|
|
|
{
|
2015-01-31 07:14:13 +00:00
|
|
|
pTexture->format = G_IM_FMT_RGBA;
|
|
|
|
pTexture->clampS = 1;
|
|
|
|
pTexture->clampT = 1;
|
2015-05-06 13:47:12 +00:00
|
|
|
pTexture->frameBufferTexture = CachedTexture::fbOneSample;
|
2015-01-31 07:14:13 +00:00
|
|
|
pTexture->maskS = 0;
|
|
|
|
pTexture->maskT = 0;
|
|
|
|
pTexture->mirrorS = 0;
|
|
|
|
pTexture->mirrorT = 0;
|
|
|
|
pTexture->realWidth = video().getWidth();
|
|
|
|
pTexture->realHeight = video().getHeight();
|
|
|
|
pTexture->textureBytes = pTexture->realWidth * pTexture->realHeight * 4;
|
|
|
|
textureCache().addFrameBufferTextureSize(pTexture->textureBytes);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, pTexture->glName);
|
|
|
|
|
2015-12-23 10:22:30 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pTexture->realWidth, pTexture->realHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
2015-01-30 13:59:52 +00:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
2016-04-02 12:56:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
CachedTexture * _createTexture()
|
|
|
|
{
|
2017-01-01 14:59:54 +00:00
|
|
|
CachedTexture * pTexture = textureCache().addFrameBufferTexture(false);
|
2016-04-02 12:56:07 +00:00
|
|
|
_initTexture(pTexture);
|
2015-01-31 07:14:13 +00:00
|
|
|
return pTexture;
|
|
|
|
}
|
2015-01-30 13:59:52 +00:00
|
|
|
|
2016-04-02 12:56:07 +00:00
|
|
|
static
|
|
|
|
void _initFBO(GLuint _FBO, CachedTexture * _pTexture)
|
|
|
|
{
|
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _FBO);
|
|
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _pTexture->glName, 0);
|
|
|
|
assert(checkFBO());
|
|
|
|
}
|
|
|
|
|
2015-01-31 07:14:13 +00:00
|
|
|
static
|
|
|
|
GLuint _createFBO(CachedTexture * _pTexture)
|
|
|
|
{
|
|
|
|
GLuint FBO;
|
|
|
|
glGenFramebuffers(1, &FBO);
|
2016-04-02 12:56:07 +00:00
|
|
|
_initFBO(FBO, _pTexture);
|
2015-01-31 07:14:13 +00:00
|
|
|
return FBO;
|
|
|
|
}
|
|
|
|
|
2016-04-02 12:56:07 +00:00
|
|
|
PostProcessor::PostProcessor()
|
|
|
|
: m_extractBloomProgram(0)
|
|
|
|
, m_seperableBlurProgram(0)
|
|
|
|
, m_glowProgram(0)
|
|
|
|
, m_bloomProgram(0)
|
|
|
|
, m_gammaCorrectionProgram(0)
|
2016-10-29 17:33:05 +00:00
|
|
|
, m_orientationCorrectionProgram(0)
|
2016-04-02 12:56:07 +00:00
|
|
|
, m_pResultBuffer(nullptr)
|
|
|
|
, m_FBO_glowMap(0)
|
|
|
|
, m_FBO_blur(0)
|
|
|
|
, m_pTextureOriginal(nullptr)
|
|
|
|
, m_pTextureGlowMap(nullptr)
|
|
|
|
, m_pTextureBlur(nullptr)
|
|
|
|
{}
|
|
|
|
|
2015-12-23 10:22:30 +00:00
|
|
|
void PostProcessor::_initCommon()
|
2015-01-31 07:14:13 +00:00
|
|
|
{
|
2016-04-02 12:56:07 +00:00
|
|
|
m_pResultBuffer = new FrameBuffer();
|
|
|
|
_initTexture(m_pResultBuffer->m_pTexture);
|
|
|
|
_initFBO(m_pResultBuffer->m_FBO, m_pResultBuffer->m_pTexture);
|
|
|
|
|
2015-12-23 10:22:30 +00:00
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PostProcessor::_initGammaCorrection()
|
|
|
|
{
|
2016-12-31 12:29:50 +00:00
|
|
|
m_gammaCorrectionProgram = createRectShaderProgram(vertexShader, gammaCorrectionShader);
|
2015-12-23 10:22:30 +00:00
|
|
|
glUseProgram(m_gammaCorrectionProgram);
|
|
|
|
int loc = glGetUniformLocation(m_gammaCorrectionProgram, "Sample0");
|
|
|
|
assert(loc >= 0);
|
|
|
|
glUniform1i(loc, 0);
|
|
|
|
loc = glGetUniformLocation(m_gammaCorrectionProgram, "uGammaCorrectionLevel");
|
|
|
|
assert(loc >= 0);
|
|
|
|
const f32 gammaLevel = (config.gammaCorrection.force != 0) ? config.gammaCorrection.level : 2.0f;
|
|
|
|
glUniform1f(loc, gammaLevel);
|
|
|
|
glUseProgram(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PostProcessor::_initBlur()
|
|
|
|
{
|
2016-12-31 12:29:50 +00:00
|
|
|
m_extractBloomProgram = createRectShaderProgram(vertexShader, extractBloomShader);
|
2015-02-10 15:25:19 +00:00
|
|
|
glUseProgram(m_extractBloomProgram);
|
|
|
|
int loc = glGetUniformLocation(m_extractBloomProgram, "Sample0");
|
|
|
|
assert(loc >= 0);
|
|
|
|
glUniform1i(loc, 0);
|
|
|
|
loc = glGetUniformLocation(m_extractBloomProgram, "ThresholdLevel");
|
|
|
|
assert(loc >= 0);
|
|
|
|
glUniform1i(loc, config.bloomFilter.thresholdLevel);
|
|
|
|
|
2016-12-31 12:29:50 +00:00
|
|
|
m_seperableBlurProgram = createRectShaderProgram(vertexShader, seperableBlurShader);
|
2015-02-10 15:25:19 +00:00
|
|
|
glUseProgram(m_seperableBlurProgram);
|
|
|
|
loc = glGetUniformLocation(m_seperableBlurProgram, "Sample0");
|
|
|
|
assert(loc >= 0);
|
|
|
|
glUniform1i(loc, 0);
|
|
|
|
loc = glGetUniformLocation(m_seperableBlurProgram, "TexelSize");
|
|
|
|
assert(loc >= 0);
|
|
|
|
glUniform2f(loc, 1.0f / video().getWidth(), 1.0f / video().getHeight());
|
|
|
|
loc = glGetUniformLocation(m_seperableBlurProgram, "Orientation");
|
|
|
|
assert(loc >= 0);
|
|
|
|
glUniform1i(loc, 0);
|
|
|
|
loc = glGetUniformLocation(m_seperableBlurProgram, "BlurAmount");
|
|
|
|
assert(loc >= 0);
|
|
|
|
glUniform1i(loc, config.bloomFilter.blurAmount);
|
|
|
|
loc = glGetUniformLocation(m_seperableBlurProgram, "BlurScale");
|
|
|
|
assert(loc >= 0);
|
|
|
|
glUniform1f(loc, 1.0f);
|
|
|
|
loc = glGetUniformLocation(m_seperableBlurProgram, "BlurStrength");
|
|
|
|
assert(loc >= 0);
|
|
|
|
glUniform1f(loc, config.bloomFilter.blurStrength/100.0f);
|
|
|
|
|
2016-12-31 12:29:50 +00:00
|
|
|
m_glowProgram = createRectShaderProgram(vertexShader, glowShader);
|
2015-02-10 15:25:19 +00:00
|
|
|
glUseProgram(m_glowProgram);
|
|
|
|
loc = glGetUniformLocation(m_glowProgram, "Sample0");
|
|
|
|
assert(loc >= 0);
|
|
|
|
glUniform1i(loc, 0);
|
|
|
|
loc = glGetUniformLocation(m_glowProgram, "Sample1");
|
|
|
|
assert(loc >= 0);
|
|
|
|
glUniform1i(loc, 1);
|
|
|
|
loc = glGetUniformLocation(m_glowProgram, "BlendMode");
|
|
|
|
assert(loc >= 0);
|
|
|
|
glUniform1i(loc, config.bloomFilter.blendMode);
|
|
|
|
|
|
|
|
m_pTextureGlowMap = _createTexture();
|
|
|
|
m_pTextureBlur = _createTexture();
|
|
|
|
|
|
|
|
m_FBO_glowMap = _createFBO(m_pTextureGlowMap);
|
|
|
|
m_FBO_blur = _createFBO(m_pTextureBlur);
|
2015-01-31 07:14:13 +00:00
|
|
|
|
2015-02-01 04:07:42 +00:00
|
|
|
glUseProgram(0);
|
2015-01-30 13:59:52 +00:00
|
|
|
}
|
|
|
|
|
2016-10-29 17:33:05 +00:00
|
|
|
void PostProcessor::_initOrientationCorrection()
|
|
|
|
{
|
2016-12-31 12:29:50 +00:00
|
|
|
m_orientationCorrectionProgram = createRectShaderProgram(vertexShader, orientationCorrectionShader);
|
2016-10-29 17:33:05 +00:00
|
|
|
glUseProgram(m_orientationCorrectionProgram);
|
|
|
|
int loc = glGetUniformLocation(m_orientationCorrectionProgram, "Sample0");
|
|
|
|
assert(loc >= 0);
|
|
|
|
glUniform1i(loc, 0);
|
|
|
|
glUseProgram(0);
|
|
|
|
}
|
|
|
|
|
2015-12-23 10:21:55 +00:00
|
|
|
void PostProcessor::init()
|
|
|
|
{
|
2015-12-23 10:22:30 +00:00
|
|
|
_initCommon();
|
|
|
|
_initGammaCorrection();
|
2016-10-29 17:33:05 +00:00
|
|
|
if (config.generalEmulation.enableBlitScreenWorkaround != 0)
|
|
|
|
_initOrientationCorrection();
|
2015-12-23 10:21:55 +00:00
|
|
|
if (config.bloomFilter.enable != 0)
|
|
|
|
_initBlur();
|
|
|
|
}
|
|
|
|
|
2015-12-23 10:22:30 +00:00
|
|
|
void PostProcessor::_destroyCommon()
|
2015-01-30 13:59:52 +00:00
|
|
|
{
|
2016-04-02 12:56:07 +00:00
|
|
|
delete m_pResultBuffer;
|
|
|
|
m_pResultBuffer = nullptr;
|
2016-04-02 12:21:03 +00:00
|
|
|
|
|
|
|
m_pTextureOriginal = nullptr;
|
2015-12-23 10:22:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PostProcessor::_destroyGammaCorrection()
|
|
|
|
{
|
|
|
|
if (m_gammaCorrectionProgram != 0)
|
|
|
|
glDeleteProgram(m_gammaCorrectionProgram);
|
|
|
|
m_gammaCorrectionProgram = 0;
|
|
|
|
}
|
|
|
|
|
2016-10-29 17:33:05 +00:00
|
|
|
void PostProcessor::_destroyOrientationCorrection()
|
|
|
|
{
|
|
|
|
if (m_orientationCorrectionProgram != 0)
|
|
|
|
glDeleteProgram(m_orientationCorrectionProgram);
|
|
|
|
m_orientationCorrectionProgram = 0;
|
|
|
|
}
|
|
|
|
|
2015-12-23 10:22:30 +00:00
|
|
|
void PostProcessor::_destroyBlur()
|
|
|
|
{
|
2015-01-31 07:14:13 +00:00
|
|
|
if (m_extractBloomProgram != 0)
|
|
|
|
glDeleteProgram(m_extractBloomProgram);
|
|
|
|
m_extractBloomProgram = 0;
|
2016-04-02 12:56:07 +00:00
|
|
|
|
2015-01-31 07:14:13 +00:00
|
|
|
if (m_seperableBlurProgram != 0)
|
|
|
|
glDeleteProgram(m_seperableBlurProgram);
|
|
|
|
m_seperableBlurProgram = 0;
|
2016-04-02 12:56:07 +00:00
|
|
|
|
2015-01-31 07:14:13 +00:00
|
|
|
if (m_glowProgram != 0)
|
|
|
|
glDeleteProgram(m_glowProgram);
|
|
|
|
m_glowProgram = 0;
|
2016-04-02 12:56:07 +00:00
|
|
|
|
2015-01-30 13:59:52 +00:00
|
|
|
if (m_bloomProgram != 0)
|
|
|
|
glDeleteProgram(m_bloomProgram);
|
2015-01-31 07:14:13 +00:00
|
|
|
m_bloomProgram = 0;
|
2015-01-30 13:59:52 +00:00
|
|
|
|
2015-01-31 07:14:13 +00:00
|
|
|
if (m_FBO_glowMap != 0)
|
|
|
|
glDeleteFramebuffers(1, &m_FBO_glowMap);
|
|
|
|
m_FBO_glowMap = 0;
|
2016-04-02 12:56:07 +00:00
|
|
|
|
2015-01-31 07:14:13 +00:00
|
|
|
if (m_FBO_blur != 0)
|
|
|
|
glDeleteFramebuffers(1, &m_FBO_blur);
|
|
|
|
m_FBO_blur = 0;
|
2015-01-30 13:59:52 +00:00
|
|
|
|
2015-12-23 10:22:30 +00:00
|
|
|
if (m_pTextureGlowMap != nullptr)
|
2015-01-31 07:14:13 +00:00
|
|
|
textureCache().removeFrameBufferTexture(m_pTextureGlowMap);
|
2015-12-23 10:22:30 +00:00
|
|
|
m_pTextureGlowMap = nullptr;
|
2016-04-02 12:56:07 +00:00
|
|
|
|
2015-12-23 10:22:30 +00:00
|
|
|
if (m_pTextureBlur != nullptr)
|
2015-01-31 07:14:13 +00:00
|
|
|
textureCache().removeFrameBufferTexture(m_pTextureBlur);
|
2015-12-23 10:22:30 +00:00
|
|
|
m_pTextureBlur = nullptr;
|
2015-01-30 13:59:52 +00:00
|
|
|
}
|
|
|
|
|
2015-12-23 10:21:55 +00:00
|
|
|
|
|
|
|
void PostProcessor::destroy()
|
|
|
|
{
|
|
|
|
_destroyBlur();
|
2015-12-23 10:22:30 +00:00
|
|
|
_destroyGammaCorrection();
|
2016-10-29 17:33:05 +00:00
|
|
|
_destroyOrientationCorrection();
|
2015-12-23 10:22:30 +00:00
|
|
|
_destroyCommon();
|
2015-12-23 10:21:55 +00:00
|
|
|
}
|
|
|
|
|
2015-01-30 13:59:52 +00:00
|
|
|
PostProcessor & PostProcessor::get()
|
|
|
|
{
|
2016-04-22 20:49:18 +00:00
|
|
|
#ifndef ANDROID
|
2015-01-30 13:59:52 +00:00
|
|
|
static PostProcessor processor;
|
2016-04-22 20:49:18 +00:00
|
|
|
#endif
|
2015-01-30 13:59:52 +00:00
|
|
|
return processor;
|
|
|
|
}
|
|
|
|
|
2016-05-13 17:29:35 +00:00
|
|
|
void PostProcessor::_setGLState() {
|
2015-01-30 13:59:52 +00:00
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glDisable(GL_BLEND);
|
2016-12-12 10:02:08 +00:00
|
|
|
glDisable(GL_CULL_FACE);
|
2015-01-30 13:59:52 +00:00
|
|
|
|
|
|
|
static const float vert[] =
|
|
|
|
{
|
|
|
|
-1.0, -1.0, +0.0, +0.0,
|
|
|
|
+1.0, -1.0, +1.0, +0.0,
|
|
|
|
-1.0, +1.0, +0.0, +1.0,
|
|
|
|
+1.0, +1.0, +1.0, +1.0
|
|
|
|
};
|
|
|
|
|
2016-12-31 12:29:50 +00:00
|
|
|
glVertexAttribPointer(SC_RECT_POSITION, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (float*)vert);
|
2015-01-30 13:59:52 +00:00
|
|
|
glEnableVertexAttribArray(SC_TEXCOORD0);
|
|
|
|
glVertexAttribPointer(SC_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (float*)vert + 2);
|
|
|
|
glViewport(0, 0, video().getWidth(), video().getHeight());
|
2016-05-13 17:29:35 +00:00
|
|
|
glScissor(0, 0, m_pResultBuffer->m_pTexture->realWidth, m_pResultBuffer->m_pTexture->realHeight);
|
2015-05-07 13:11:54 +00:00
|
|
|
gSP.changed |= CHANGED_VIEWPORT;
|
2016-03-31 11:52:01 +00:00
|
|
|
gDP.changed |= CHANGED_RENDERMODE | CHANGED_SCISSOR;
|
2015-01-30 13:59:52 +00:00
|
|
|
}
|
|
|
|
|
2015-12-23 10:22:30 +00:00
|
|
|
void PostProcessor::_preDraw(FrameBuffer * _pBuffer)
|
2015-01-30 13:59:52 +00:00
|
|
|
{
|
2016-05-13 17:29:35 +00:00
|
|
|
_setGLState();
|
2015-01-31 07:14:13 +00:00
|
|
|
OGLVideo & ogl = video();
|
2015-01-30 13:59:52 +00:00
|
|
|
|
2016-04-02 12:56:07 +00:00
|
|
|
m_pResultBuffer->m_width = _pBuffer->m_width;
|
|
|
|
m_pResultBuffer->m_height = _pBuffer->m_height;
|
2016-05-13 17:29:35 +00:00
|
|
|
m_pResultBuffer->m_scaleX = ogl.getScaleX();
|
|
|
|
m_pResultBuffer->m_scaleY = ogl.getScaleY();
|
2016-04-30 10:06:51 +00:00
|
|
|
#ifdef GLES2
|
2016-04-02 12:21:03 +00:00
|
|
|
m_pTextureOriginal = _pBuffer->m_pTexture;
|
2015-05-14 14:26:08 +00:00
|
|
|
#else
|
2016-05-14 12:11:45 +00:00
|
|
|
if (_pBuffer->m_pTexture->frameBufferTexture == CachedTexture::fbMultiSample) {
|
|
|
|
_pBuffer->resolveMultisampledTexture(true);
|
|
|
|
m_pTextureOriginal = _pBuffer->m_pResolveTexture;
|
2016-04-02 12:21:03 +00:00
|
|
|
} else
|
|
|
|
m_pTextureOriginal = _pBuffer->m_pTexture;
|
2015-05-14 14:26:08 +00:00
|
|
|
#endif
|
2015-01-30 13:59:52 +00:00
|
|
|
|
2015-02-10 15:25:19 +00:00
|
|
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
2015-12-23 10:22:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PostProcessor::_postDraw()
|
|
|
|
{
|
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
|
|
video().getRender().dropRenderState();
|
|
|
|
glUseProgram(0);
|
|
|
|
}
|
|
|
|
|
2016-04-02 12:56:07 +00:00
|
|
|
FrameBuffer * PostProcessor::doBlur(FrameBuffer * _pBuffer)
|
2015-12-23 10:22:30 +00:00
|
|
|
{
|
2016-04-02 12:56:07 +00:00
|
|
|
if (_pBuffer == nullptr)
|
|
|
|
return nullptr;
|
|
|
|
|
2015-12-23 10:22:30 +00:00
|
|
|
if (config.bloomFilter.enable == 0)
|
2016-04-02 12:56:07 +00:00
|
|
|
return _pBuffer;
|
2015-12-23 10:22:30 +00:00
|
|
|
|
|
|
|
_preDraw(_pBuffer);
|
2015-02-10 15:25:19 +00:00
|
|
|
|
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_FBO_glowMap);
|
|
|
|
textureCache().activateTexture(0, m_pTextureOriginal);
|
|
|
|
glUseProgram(m_extractBloomProgram);
|
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
|
|
|
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_FBO_blur);
|
|
|
|
textureCache().activateTexture(0, m_pTextureGlowMap);
|
|
|
|
glUseProgram(m_seperableBlurProgram);
|
|
|
|
int loc = glGetUniformLocation(m_seperableBlurProgram, "Orientation");
|
|
|
|
assert(loc >= 0);
|
|
|
|
glUniform1i(loc, 0);
|
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
|
|
|
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_FBO_glowMap);
|
|
|
|
textureCache().activateTexture(0, m_pTextureBlur);
|
|
|
|
glUniform1i(loc, 1);
|
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
|
|
|
2016-04-02 12:56:07 +00:00
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_pResultBuffer->m_FBO);
|
2015-02-10 15:25:19 +00:00
|
|
|
textureCache().activateTexture(0, m_pTextureOriginal);
|
|
|
|
textureCache().activateTexture(1, m_pTextureGlowMap);
|
|
|
|
glUseProgram(m_glowProgram);
|
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
|
|
|
2015-12-23 10:22:30 +00:00
|
|
|
_postDraw();
|
2016-04-02 12:56:07 +00:00
|
|
|
return m_pResultBuffer;
|
2015-12-23 10:22:30 +00:00
|
|
|
}
|
|
|
|
|
2016-04-02 12:56:07 +00:00
|
|
|
FrameBuffer * PostProcessor::doGammaCorrection(FrameBuffer * _pBuffer)
|
|
|
|
{
|
|
|
|
if (_pBuffer == nullptr)
|
|
|
|
return nullptr;
|
2015-12-23 10:22:30 +00:00
|
|
|
|
2016-04-02 12:56:07 +00:00
|
|
|
if (((*REG.VI_STATUS & 8) | config.gammaCorrection.force) == 0)
|
|
|
|
return _pBuffer;
|
2015-12-23 10:22:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
_preDraw(_pBuffer);
|
|
|
|
|
2016-04-02 12:56:07 +00:00
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_pResultBuffer->m_FBO);
|
2015-12-23 10:22:30 +00:00
|
|
|
textureCache().activateTexture(0, m_pTextureOriginal);
|
|
|
|
glUseProgram(m_gammaCorrectionProgram);
|
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
|
|
|
|
|
|
_postDraw();
|
2016-04-02 12:56:07 +00:00
|
|
|
return m_pResultBuffer;
|
2015-01-30 13:59:52 +00:00
|
|
|
}
|
2016-10-29 17:33:05 +00:00
|
|
|
|
|
|
|
FrameBuffer * PostProcessor::doOrientationCorrection(FrameBuffer * _pBuffer)
|
|
|
|
{
|
|
|
|
if (_pBuffer == nullptr)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
if (config.generalEmulation.enableBlitScreenWorkaround == 0)
|
|
|
|
return _pBuffer;
|
|
|
|
|
|
|
|
_preDraw(_pBuffer);
|
|
|
|
|
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_pResultBuffer->m_FBO);
|
|
|
|
textureCache().activateTexture(0, m_pTextureOriginal);
|
|
|
|
glUseProgram(m_orientationCorrectionProgram);
|
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
|
|
|
|
|
|
_postDraw();
|
|
|
|
return m_pResultBuffer;
|
|
|
|
}
|
|
|
|
|