1
0
mirror of https://github.com/blawar/GLideN64.git synced 2024-07-02 09:03:37 +00:00

Use hybrid texture filter to draw frame buffer image on screen.

Related to #2088
This commit is contained in:
Sergey Lipskiy 2019-11-23 13:52:06 +07:00
parent bc05d5f0d8
commit 488d52de16
2 changed files with 141 additions and 7 deletions

View File

@ -1484,7 +1484,7 @@ void FrameBufferList::renderBuffer()
hOffset + dstX1,
vOffset + (s32)(dstY1*dstScaleY) };
TextureParam filter = textureParameters::FILTER_LINEAR;
const TextureParam filter = textureParameters::FILTER_NEAREST;
ObjectHandle readBuffer;
if (pFilteredBuffer->m_pTexture->frameBufferTexture == CachedTexture::fbMultiSample) {

View File

@ -352,6 +352,108 @@ namespace glsl {
}
};
/*---------------Hybrid texture filter-------------*/
static
std::string const& getHybridTextureFilter()
{
static std::string strFilter =
"#if __VERSION__ < 130 \n"
"uniform ivec2 uTextureSize; \n"
"#endif \n"
" \n"
"ivec2 getTextureSize(in sampler2D tex) \n"
"{ \n"
"#if __VERSION__ < 130 \n"
" return uTextureSize; \n"
"#else \n"
" return textureSize(tex, 0); \n"
"#endif \n"
"} \n"
"vec2 norm2denorm(in vec2 uv, in ivec2 texture_size) \n"
"{ \n"
" return uv * texture_size - 0.5f; \n"
"} \n"
"ivec2 denorm2idx(in vec2 d_uv) \n"
"{ \n"
" return ivec2(floor(d_uv)); \n"
"} \n"
"ivec2 norm2idx(in vec2 uv, in ivec2 texture_size) \n"
"{ \n"
" return denorm2idx(norm2denorm(uv, texture_size)); \n"
"} \n"
"vec2 idx2norm(in ivec2 idx, in ivec2 texture_size) \n"
"{ \n"
" vec2 denorm_uv = vec2(idx) + 0.5f; \n"
" return denorm_uv / texture_size; \n"
"} \n"
"vec4 texel_fetch(in sampler2D tex, in ivec2 idx, in ivec2 texture_size) \n"
"{ \n"
" vec2 uv = idx2norm(idx, texture_size); \n"
" return texture2D(tex, uv); \n"
"} \n"
"vec4 hybridFilter(in sampler2D tex, in vec2 uv) \n"
"{ \n"
" ivec2 texSize = getTextureSize(tex); \n"
" vec2 denorm_uv = norm2denorm(uv,texSize); \n"
" ivec2 idx_low = denorm2idx(denorm_uv); \n"
" vec2 ratio = denorm_uv - idx_low; \n"
" ivec2 rounded_idx = idx_low + ivec2(step(0.5f, ratio)); \n"
" \n"
" ivec2 idx00 = idx_low; \n"
" vec4 t00 = texel_fetch(tex, idx00, texSize); \n"
" \n"
" ivec2 idx01 = idx00 + ivec2(0, 1); \n"
" vec4 t01 = texel_fetch(tex, idx01, texSize); \n"
" \n"
" ivec2 idx10 = idx00 + ivec2(1, 0); \n"
" vec4 t10 = texel_fetch(tex, idx10, texSize); \n"
" \n"
" ivec2 idx11 = idx00 + ivec2(1, 1); \n"
" vec4 t11 = texel_fetch(tex, idx11, texSize); \n"
" \n"
" /* \n"
" * radius is the distance from the edge where interpolation happens. \n"
" * It's calculated based on how big a fragment is in denormalized \n"
" * texture coordinates. \n"
" * \n"
" * E.g.: If a texel maps to 5 fragments, then each fragment is \n"
" * 1/5 texels big. So the smooth transition should be between one and \n"
" * two fragments big, since there are enough fragments to show the full \n"
" * color of the texel. \n"
" * \n"
" * If a fragment is larger than one texel, we don't care, we're already \n"
" * sampling the wrong texels, and should be using mipmaps instead. \n"
" */ \n"
" \n"
" // Here, fwidth() is used to estimte how much denorm_uv changes per fragment. \n"
" // But we divide it by 2, since fwidth() is adding abs(dx) + abs(dy). \n"
" vec2 fragment_size = fwidth(denorm_uv) / 2.0f; \n"
" \n"
" float is_frag_gt1, radius; \n"
" // Do nothing if fragment is greater than 1 texel \n"
" // Don't make the transition more than one fragment (+/- 0.5 fragment) \n"
" is_frag_gt1 = step(1.0f, fragment_size.s); \n"
" radius = min(fragment_size.s, 0.5f); \n"
" ratio.s = ratio.s * is_frag_gt1 + smoothstep(0.5f - radius, \n"
" 0.5f + radius, ratio.s) * (1.0 - is_frag_gt1); \n"
" is_frag_gt1 = step(1.0f, fragment_size.t); \n"
" radius = min(fragment_size.t, 0.5f); \n"
" ratio.t = ratio.t * is_frag_gt1 + smoothstep(0.5f - radius, \n"
" 0.5f + radius, ratio.t) * (1.0 - is_frag_gt1); \n"
" \n"
" // interpolate first on S direction then on T. \n"
" vec4 top = mix(t00, t10, ratio.s); \n"
" vec4 bottom = mix(t01, t11, ratio.s); \n"
" // only interpolate within texture bounds to avoid sampling black texels \n"
" float is_opaque = step(2.0f, top.a + bottom.a); \n"
" return mix(top, bottom, ratio.t) * is_opaque + \n"
" texel_fetch(tex, rounded_idx, texSize) * (1.0 - is_opaque); \n"
"} \n"
;
return strFilter;
}
/*---------------TexrectCopyShaderPart-------------*/
class TexrectCopy : public ShaderPart
@ -359,14 +461,15 @@ namespace glsl {
public:
TexrectCopy(const opengl::GLInfo & _glinfo)
{
m_part =
m_part = getHybridTextureFilter();
m_part +=
"IN mediump vec2 vTexCoord0; \n"
"uniform sampler2D uTex0; \n"
"OUT lowp vec4 fragColor; \n"
" \n"
"void main() \n"
"{ \n"
" fragColor = texture2D(uTex0, vTexCoord0); \n"
" fragColor = hybridFilter(uTex0, vTexCoord0); \n"
;
}
};
@ -378,7 +481,8 @@ namespace glsl {
public:
TexrectColorAndDepthCopy(const opengl::GLInfo & _glinfo)
{
m_part =
m_part = getHybridTextureFilter();
m_part +=
"IN mediump vec2 vTexCoord0; \n"
"uniform sampler2D uTex0; \n"
"uniform sampler2D uTex1; \n"
@ -386,9 +490,9 @@ namespace glsl {
" \n"
"void main() \n"
"{ \n"
" fragColor = texture2D(uTex0, vTexCoord0); \n"
" gl_FragDepth = texture2D(uTex1, vTexCoord0).r; \n"
;
" fragColor = hybridFilter(uTex0, vTexCoord0); \n"
" gl_FragDepth = texture2D(uTex1, vTexCoord0).r; \n"
;
}
};
@ -681,8 +785,23 @@ namespace glsl {
m_useProgram->useProgram(m_program);
const int texLoc = glGetUniformLocation(GLuint(m_program), "uTex0");
glUniform1i(texLoc, 0);
m_textureSizeLoc = glGetUniformLocation(GLuint(m_program), "uTextureSize");
m_useProgram->useProgram(graphics::ObjectHandle::null);
}
void activate() override
{
TexrectCopyShaderBase::activate();
if (m_textureSizeLoc < 0)
return;
GLint texWidth, texHeight;
glGetTexLevelParameteriv(0, 0, GL_TEXTURE_WIDTH, &texWidth);
glGetTexLevelParameteriv(0, 0, GL_TEXTURE_HEIGHT, &texHeight);
glUniform2i(m_textureSizeLoc, texWidth, texHeight);
}
private:
GLint m_textureSizeLoc;
};
/*---------------TexrectColorAndDepthCopyShader-------------*/
@ -704,8 +823,23 @@ namespace glsl {
glUniform1i(texLoc0, 0);
const int texLoc1 = glGetUniformLocation(GLuint(m_program), "uTex1");
glUniform1i(texLoc1, 1);
m_textureSizeLoc = glGetUniformLocation(GLuint(m_program), "uTextureSize");
m_useProgram->useProgram(graphics::ObjectHandle::null);
}
void activate() override
{
TexrectColorAndDepthCopyShaderBase::activate();
if (m_textureSizeLoc < 0)
return;
GLint texWidth, texHeight;
glGetTexLevelParameteriv(0, 0, GL_TEXTURE_WIDTH, &texWidth);
glGetTexLevelParameteriv(0, 0, GL_TEXTURE_HEIGHT, &texHeight);
glUniform2i(m_textureSizeLoc, texWidth, texHeight);
}
private:
GLint m_textureSizeLoc;
};
/*---------------PostProcessorShader-------------*/