From a48e1e37ca465d19573c93a4c1cd9a099bfd0757 Mon Sep 17 00:00:00 2001 From: Francisco Zurita Date: Sun, 6 Nov 2016 23:34:11 -0500 Subject: [PATCH] Add support for LOD with GLES2 --- src/GLES2/GLSLCombiner_gles2.cpp | 34 +++++++++++---- src/GLES2/Shaders_gles2.h | 73 +++++++++++++++++++++++++++++++- src/OpenGL.cpp | 7 +++ src/Textures.cpp | 14 +++--- 4 files changed, 111 insertions(+), 17 deletions(-) diff --git a/src/GLES2/GLSLCombiner_gles2.cpp b/src/GLES2/GLSLCombiner_gles2.cpp index ecda4ed1..5c645879 100644 --- a/src/GLES2/GLSLCombiner_gles2.cpp +++ b/src/GLES2/GLSLCombiner_gles2.cpp @@ -191,23 +191,29 @@ ShaderCombiner::ShaderCombiner(Combiner & _color, Combiner & _alpha, const gDPCo if (bUseHWLight) strFragmentShader.append(fragment_shader_calc_light); - if (bUseLod) - strFragmentShader.append(fragment_shader_fake_mipmap); - else if (usesTexture()) { + + if (bUseLod) { + if (config.generalEmulation.enableLOD != 0) + strFragmentShader.append(fragment_shader_mipmap); + else + strFragmentShader.append(fragment_shader_fake_mipmap); + } else if (usesTexture()) { if (config.texture.bilinearMode == BILINEAR_3POINT) strFragmentShader.append(fragment_shader_readtex_3point); else strFragmentShader.append(fragment_shader_readtex); } - if (config.generalEmulation.enableNoise != 0) + + if (config.generalEmulation.enableNoise != 0) { strFragmentShader.append(fragment_shader_noise); + } GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); const GLchar * strShaderData = strFragmentShader.data(); glShaderSource(fragmentShader, 1, &strShaderData, NULL); glCompileShader(fragmentShader); if (!checkShaderCompileStatus(fragmentShader)) - LOG(LOG_ERROR, "Error in fragment shader:\n%s\n", strFragmentShader.data()); + logErrorShader(GL_FRAGMENT_SHADER, strFragmentShader); m_program = glCreateProgram(); _locate_attributes(); @@ -251,6 +257,7 @@ void ShaderCombiner::_locateUniforms() { LocateUniform(uFbMonochrome); LocateUniform(uFbFixedAlpha); LocateUniform(uMaxTile) + LocateUniform(uTextureDetail); LocateUniform(uTexturePersp); LocateUniform(uTextureFilterMode); LocateUniform(uForceBlendCycle1); @@ -388,9 +395,20 @@ void ShaderCombiner::updateDitherMode(bool _bForce) void ShaderCombiner::updateLOD(bool _bForce) { - if (usesLOD()) { - m_uniforms.uMinLod.set(gDP.primColor.m, _bForce); - m_uniforms.uMaxTile.set(gSP.texture.level, _bForce); + if (!usesLOD()) + return; + + m_uniforms.uMinLod.set(gDP.primColor.m, _bForce); + m_uniforms.uMaxTile.set(gSP.texture.level, _bForce); + + if (config.generalEmulation.enableLOD != 0) { + const int uCalcLOD = (gDP.otherMode.textureLOD == G_TL_LOD) ? 1 : 0; + m_uniforms.uEnableLod.set(uCalcLOD, _bForce); + if (config.frameBufferEmulation.nativeResFactor == 0) + m_uniforms.uScreenScale.set(video().getScaleX(), video().getScaleY(), _bForce); + else + m_uniforms.uScreenScale.set(float(config.frameBufferEmulation.nativeResFactor), float(config.frameBufferEmulation.nativeResFactor), _bForce); + m_uniforms.uTextureDetail.set(gDP.otherMode.textureDetail, _bForce); } } diff --git a/src/GLES2/Shaders_gles2.h b/src/GLES2/Shaders_gles2.h index 88feee1a..20be1403 100644 --- a/src/GLES2/Shaders_gles2.h +++ b/src/GLES2/Shaders_gles2.h @@ -1,4 +1,6 @@ -#define SHADER_VERSION "#version 100 \n" +#define SHADER_VERSION "#version 100 \n" \ +"#extension GL_EXT_shader_texture_lod : enable \n" \ +"#extension GL_OES_standard_derivatives : enable \n" static const char* vertex_shader = SHADER_VERSION @@ -281,6 +283,75 @@ static const char* fragment_shader_end = "} \n" ; +static const char* fragment_shader_mipmap = +"uniform lowp int uEnableLod; \n" +"uniform mediump float uMinLod; \n" +"uniform lowp int uMaxTile; \n" +"uniform lowp int uTextureDetail; \n" +" \n" +"mediump float mipmap(out lowp vec4 readtex0, out lowp vec4 readtex1) { \n" +" readtex0 = texture2D(uTex0, vTexCoord0); \n" +" readtex1 = texture2DLodEXT(uTex1, vTexCoord1, 0.0); \n" +" \n" +" mediump float fMaxTile = float(uMaxTile); \n" +#if 1 +" mediump vec2 dx = abs(dFdx(vLodTexCoord)); \n" +" dx *= uScreenScale; \n" +" mediump float lod = max(dx.x, dx.y); \n" +#else +" mediump vec2 dx = dFdx(vLodTexCoord); \n" +" dx *= uScreenScale; \n" +" mediump vec2 dy = dFdy(vLodTexCoord); \n" +" dy *= uScreenScale; \n" +" mediump float lod = max(length(dx), length(dy)); \n" +#endif +" bool magnify = lod < 1.0; \n" +" mediump float lod_tile = magnify ? 0.0 : floor(log2(floor(lod))); \n" +" bool distant = lod > 128.0 || lod_tile >= fMaxTile; \n" +" mediump float lod_frac = fract(lod/pow(2.0, lod_tile)); \n" +" if (magnify) lod_frac = max(lod_frac, uMinLod); \n" +" if (uTextureDetail == 0) { \n" +" if (distant) lod_frac = 1.0; \n" +" else if (magnify) lod_frac = 0.0; \n" +" } \n" +" if (magnify && (uTextureDetail == 1 || uTextureDetail == 3)) \n" +" lod_frac = 1.0 - lod_frac; \n" +" if (uMaxTile == 0) { \n" +" if (uEnableLod != 0 && (uTextureDetail == 2 || uTextureDetail == 3)) \n" +" readtex1 = readtex0; \n" +" return lod_frac; \n" +" } \n" +" if (uEnableLod == 0) return lod_frac; \n" +" \n" +" lod_tile = min(lod_tile, fMaxTile); \n" +" lowp float lod_tile_m1 = max(0.0, lod_tile - 1.0); \n" +" lowp vec4 lodT = texture2DLodEXT(uTex1, vTexCoord1, lod_tile); \n" +" lowp vec4 lodT_m1 = texture2DLodEXT(uTex1, vTexCoord1, lod_tile_m1); \n" +" lowp vec4 lodT_p1 = texture2DLodEXT(uTex1, vTexCoord1, lod_tile + 1.0); \n" +" if (lod_tile < 1.0) { \n" +" if (magnify) { \n" +// !sharpen && !detail +" if (uTextureDetail == 0) readtex1 = readtex0; \n" +" } else { \n" +// detail +" if (uTextureDetail == 2 || uTextureDetail == 3) { \n" +" readtex0 = lodT; \n" +" readtex1 = lodT_p1; \n" +" } \n" +" } \n" +" } else { \n" +" if (uTextureDetail == 2 || uTextureDetail == 3) { \n" +" readtex0 = lodT; \n" +" readtex1 = lodT_p1; \n" +" } else { \n" +" readtex0 = lodT_m1; \n" +" readtex1 = lodT; \n" +" } \n" +" } \n" +" return lod_frac; \n" +"} \n" +; + static const char* fragment_shader_fake_mipmap = "uniform lowp int uMaxTile; \n" "uniform mediump float uMinLod; \n" diff --git a/src/OpenGL.cpp b/src/OpenGL.cpp index d28b38dc..56cc48be 100644 --- a/src/OpenGL.cpp +++ b/src/OpenGL.cpp @@ -2102,6 +2102,13 @@ void OGLRender::_initExtensions() } else config.texture.maxAnisotropyF = 0.0f; LOG(LOG_VERBOSE, "Max Anisotropy: %f\n", config.texture.maxAnisotropyF); + +#ifdef GLES2 + if(!OGLVideo::isExtensionSupported("GL_EXT_shader_texture_lod") || + !OGLVideo::isExtensionSupported("GL_OES_standard_derivatives")) { + config.generalEmulation.enableLOD = 0; + } +#endif } void OGLRender::_initStates() diff --git a/src/Textures.cpp b/src/Textures.cpp index 1b14ad70..eeacad02 100644 --- a/src/Textures.cpp +++ b/src/Textures.cpp @@ -1066,13 +1066,11 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture) pDest = (u32*)malloc(_pTexture->textureBytes); assert(pDest != nullptr); - GLint mipLevel = 0, maxLevel = 0; -#ifndef GLES2 - if (config.generalEmulation.enableLOD != 0 && gSP.texture.level > 1) - maxLevel = _tile == 0 ? 0 : gSP.texture.level - 1; -#endif + GLint mipLevel = 0; + _pTexture->max_level = 0; - _pTexture->max_level = maxLevel; + if (config.generalEmulation.enableLOD != 0 && gSP.texture.level > 1) + _pTexture->max_level = static_cast(_tile == 0 ? 0 : gSP.texture.level - 1); CachedTexture tmptex(0); memcpy(&tmptex, _pTexture, sizeof(CachedTexture)); @@ -1099,7 +1097,7 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture) bool bLoaded = false; if ((config.textureFilter.txEnhancementMode | config.textureFilter.txFilterMode) != 0 && - maxLevel == 0 && + _pTexture->max_level == 0 && (config.textureFilter.txFilterIgnoreBG == 0 || (RSP.cmd != G_TEXRECT && RSP.cmd != G_TEXRECTFLIP)) && TFH.isInited()) { @@ -1135,7 +1133,7 @@ void TextureCache::_load(u32 _tile, CachedTexture *_pTexture) tmptex.realHeight, 0, GL_RGBA, glType, pDest); #endif } - if (mipLevel == maxLevel) + if (mipLevel == _pTexture->max_level) break; ++mipLevel; const u32 tileMipLevel = gSP.texture.tile + mipLevel + 1;