From cd1b134ddc188c61c9b230669588502d62b31d6b Mon Sep 17 00:00:00 2001 From: Sergey Lipskiy Date: Sun, 17 Jul 2016 11:15:02 +0600 Subject: [PATCH] Add legacy blending option: Use old, fixed functionality based method for emulation of N64 blending modes. --- src/Combiner.cpp | 2 +- src/Config.cpp | 1 + src/Config.h | 3 +- src/GLES2/GLSLCombiner_gles2.cpp | 10 ++- src/GLES2/Shaders_gles2.h | 2 + src/OGL3X/GLSLCombiner_ogl3x.cpp | 11 ++- src/OGL3X/Shaders_ogl3x.h | 2 + src/OpenGL.cpp | 140 +++++++++++++++++++++++++++++ src/OpenGL.h | 1 + src/ShaderUtils.cpp | 22 +++-- src/mupenplus/Config_mupenplus.cpp | 3 + 11 files changed, 184 insertions(+), 13 deletions(-) diff --git a/src/Combiner.cpp b/src/Combiner.cpp index d4717c3b..d9e9683c 100644 --- a/src/Combiner.cpp +++ b/src/Combiner.cpp @@ -375,7 +375,7 @@ Storage format: uint32 - number of shaders shaders in binary form */ -static const u32 ShaderStorageFormatVersion = 0x07U; +static const u32 ShaderStorageFormatVersion = 0x08U; void CombinerInfo::_saveShadersStorage() const { if (m_shadersLoaded >= m_combiners.size()) diff --git a/src/Config.cpp b/src/Config.cpp index c5c9355e..8831ceb1 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -36,6 +36,7 @@ void Config::resetToDefaults() generalEmulation.enableShadersStorage = 1; generalEmulation.correctTexrectCoords = tcDisable; generalEmulation.enableNativeResTexrects = 0; + generalEmulation.enableLegacyBlending = 0; generalEmulation.hacks = 0; #ifdef ANDROID generalEmulation.forcePolygonOffset = 0; diff --git a/src/Config.h b/src/Config.h index 0cb18f42..06c91a4d 100644 --- a/src/Config.h +++ b/src/Config.h @@ -4,7 +4,7 @@ #include #include "Types.h" -#define CONFIG_VERSION_CURRENT 11U +#define CONFIG_VERSION_CURRENT 12U #define BILINEAR_3POINT 0 #define BILINEAR_STANDARD 1 @@ -49,6 +49,7 @@ struct Config u32 enableShadersStorage; u32 correctTexrectCoords; u32 enableNativeResTexrects; + u32 enableLegacyBlending; u32 hacks; #ifdef ANDROID u32 forcePolygonOffset; diff --git a/src/GLES2/GLSLCombiner_gles2.cpp b/src/GLES2/GLSLCombiner_gles2.cpp index 68c1bc68..5dbf881c 100644 --- a/src/GLES2/GLSLCombiner_gles2.cpp +++ b/src/GLES2/GLSLCombiner_gles2.cpp @@ -149,12 +149,12 @@ ShaderCombiner::ShaderCombiner(Combiner & _color, Combiner & _alpha, const gDPCo if (usesTexture()) { strFragmentShader.assign(fragment_shader_header_common_variables); - if (gDP.otherMode.cycleType == G_CYC_2CYCLE) + if (gDP.otherMode.cycleType == G_CYC_2CYCLE && config.generalEmulation.enableLegacyBlending == 0) strFragmentShader.append(fragment_shader_header_common_variables_blend_mux_2cycle); strFragmentShader.append(fragment_shader_header_common_functions); } else { strFragmentShader.assign(fragment_shader_header_common_variables_notex); - if (gDP.otherMode.cycleType == G_CYC_2CYCLE) + if (gDP.otherMode.cycleType == G_CYC_2CYCLE && config.generalEmulation.enableLegacyBlending == 0) strFragmentShader.append(fragment_shader_header_common_variables_blend_mux_2cycle); strFragmentShader.append(fragment_shader_header_common_functions_notex); } @@ -328,6 +328,9 @@ void ShaderCombiner::updateFogMode(bool _bForce) void ShaderCombiner::updateBlendMode(bool _bForce) { + if (config.generalEmulation.enableLegacyBlending != 0) + return; + if (gDP.otherMode.cycleType <= G_CYC_2CYCLE) { m_uniforms.uBlendMux1.set(gDP.otherMode.c1_m1a, gDP.otherMode.c1_m1b, @@ -356,6 +359,9 @@ void ShaderCombiner::updateBlendMode(bool _bForce) void ShaderCombiner::disableBlending() { + if (config.generalEmulation.enableLegacyBlending != 0) + return; + m_uniforms.uForceBlendCycle1.set(0, false); m_uniforms.uForceBlendCycle2.set(0, false); } diff --git a/src/GLES2/Shaders_gles2.h b/src/GLES2/Shaders_gles2.h index 41b7ec65..a83b5595 100644 --- a/src/GLES2/Shaders_gles2.h +++ b/src/GLES2/Shaders_gles2.h @@ -157,6 +157,7 @@ SHADER_VERSION "uniform lowp float uK5; \n" "uniform mediump vec2 uScreenScale; \n" "uniform lowp int uAlphaCompareMode; \n" +"uniform lowp int uFogUsage; \n" "uniform lowp ivec2 uFbMonochrome; \n" "uniform lowp ivec2 uFbFixedAlpha;\n" "uniform lowp int uEnableAlphaTest; \n" @@ -194,6 +195,7 @@ SHADER_VERSION "uniform lowp float uK5; \n" "uniform mediump vec2 uScreenScale; \n" "uniform lowp int uAlphaCompareMode; \n" +"uniform lowp int uFogUsage; \n" "uniform lowp int uEnableAlphaTest; \n" "uniform lowp int uCvgXAlpha; \n" "uniform lowp int uAlphaCvgSel; \n" diff --git a/src/OGL3X/GLSLCombiner_ogl3x.cpp b/src/OGL3X/GLSLCombiner_ogl3x.cpp index e80ef631..e480ee62 100644 --- a/src/OGL3X/GLSLCombiner_ogl3x.cpp +++ b/src/OGL3X/GLSLCombiner_ogl3x.cpp @@ -310,7 +310,7 @@ ShaderCombiner::ShaderCombiner(Combiner & _color, Combiner & _alpha, const gDPCo if (usesTexture()) { strFragmentShader.assign(fragment_shader_header_common_variables); - if (gDP.otherMode.cycleType == G_CYC_2CYCLE) + if (gDP.otherMode.cycleType == G_CYC_2CYCLE && config.generalEmulation.enableLegacyBlending == 0) strFragmentShader.append(fragment_shader_header_common_variables_blend_mux_2cycle); #ifdef GL_MULTISAMPLING_SUPPORT @@ -342,7 +342,7 @@ ShaderCombiner::ShaderCombiner(Combiner & _color, Combiner & _alpha, const gDPCo } else { strFragmentShader.assign(fragment_shader_header_common_variables_notex); - if (gDP.otherMode.cycleType == G_CYC_2CYCLE) + if (gDP.otherMode.cycleType == G_CYC_2CYCLE && config.generalEmulation.enableLegacyBlending == 0) strFragmentShader.append(fragment_shader_header_common_variables_blend_mux_2cycle); strFragmentShader.append(fragment_shader_header_noise); strFragmentShader.append(fragment_shader_header_noise_dither); @@ -634,6 +634,9 @@ void ShaderCombiner::updateFogMode(bool _bForce) void ShaderCombiner::updateBlendMode(bool _bForce) { + if (config.generalEmulation.enableLegacyBlending != 0) + return; + if (gDP.otherMode.cycleType <= G_CYC_2CYCLE) { m_uniforms.uBlendMux1.set(gDP.otherMode.c1_m1a, gDP.otherMode.c1_m1b, @@ -662,6 +665,9 @@ void ShaderCombiner::updateBlendMode(bool _bForce) void ShaderCombiner::disableBlending() { + if (config.generalEmulation.enableLegacyBlending != 0) + return; + m_uniforms.uForceBlendCycle1.set(0, false); m_uniforms.uForceBlendCycle2.set(0, false); } @@ -849,6 +855,7 @@ void ShaderCombiner::getShaderCombinerOptionsSet(std::vector & _vecOptions) _vecOptions.push_back(config.generalEmulation.enableNoise); _vecOptions.push_back(config.generalEmulation.enableLOD); _vecOptions.push_back(config.frameBufferEmulation.N64DepthCompare); + _vecOptions.push_back(config.generalEmulation.enableLegacyBlending); } #ifdef GL_IMAGE_TEXTURES_SUPPORT diff --git a/src/OGL3X/Shaders_ogl3x.h b/src/OGL3X/Shaders_ogl3x.h index 02fcf208..d4150cf0 100644 --- a/src/OGL3X/Shaders_ogl3x.h +++ b/src/OGL3X/Shaders_ogl3x.h @@ -181,6 +181,7 @@ MAIN_SHADER_VERSION "uniform lowp int uAlphaCompareMode;\n" "uniform lowp int uAlphaDitherMode; \n" "uniform lowp int uColorDitherMode; \n" +"uniform lowp int uFogUsage; \n" "uniform lowp ivec2 uFbMonochrome; \n" "uniform lowp ivec2 uFbFixedAlpha; \n" "uniform lowp int uEnableAlphaTest; \n" @@ -242,6 +243,7 @@ MAIN_SHADER_VERSION "uniform lowp int uAlphaCompareMode;\n" "uniform lowp int uAlphaDitherMode; \n" "uniform lowp int uColorDitherMode; \n" +"uniform lowp int uFogUsage; \n" "uniform lowp int uEnableAlphaTest; \n" "uniform lowp int uCvgXAlpha; \n" "uniform lowp int uAlphaCvgSel; \n" diff --git a/src/OpenGL.cpp b/src/OpenGL.cpp index 848d89af..8f709c06 100644 --- a/src/OpenGL.cpp +++ b/src/OpenGL.cpp @@ -691,8 +691,148 @@ void OGLRender::addTriangle(int _v0, int _v1, int _v2) #endif } +void OGLRender::_legacySetBlendMode() const +{ + const u32 blendmode = gDP.otherMode.l >> 16; + // 0x7000 = CVG_X_ALPHA|ALPHA_CVG_SEL|FORCE_BL + if (gDP.otherMode.alphaCvgSel != 0 && (gDP.otherMode.l & 0x7000) != 0x7000) { + switch (blendmode) { + case 0x4055: // Mario Golf + case 0x5055: // Paper Mario intro clr_mem * a_in + clr_mem * a_mem + glEnable(GL_BLEND); + glBlendFunc(GL_ZERO, GL_ONE); + break; + default: + glDisable(GL_BLEND); + } + return; + } + + if (gDP.otherMode.forceBlender != 0 && gDP.otherMode.cycleType < G_CYC_COPY) { + glEnable(GL_BLEND); + + switch (blendmode) + { + // Mace objects + case 0x0382: + // Mace special blend mode, see GLSLCombiner.cpp + case 0x0091: + // 1080 Sky + case 0x0C08: + // Used LOTS of places + case 0x0F0A: + //DK64 blue prints + case 0x0302: + // Bomberman 2 special blend mode, see GLSLCombiner.cpp + case 0xA500: + //Sin and Punishment + case 0xCB02: + // Battlezone + // clr_in * a + clr_in * (1-a) + case 0xC800: + // Conker BFD + // clr_in * a_fog + clr_fog * (1-a) + // clr_in * 0 + clr_in * 1 + case 0x07C2: + case 0x00C0: + //ISS64 + case 0xC302: + // Donald Duck + case 0xC702: + glBlendFunc(GL_ONE, GL_ZERO); + break; + + case 0x55f0: + // Bust-A-Move 3 DX + // CLR_MEM * A_FOG + CLR_FOG * 1MA + glBlendFunc(GL_ONE, GL_SRC_ALPHA); + break; + + case 0x0F1A: + if (gDP.otherMode.cycleType == G_CYC_1CYCLE) + glBlendFunc(GL_ONE, GL_ZERO); + else + glBlendFunc(GL_ZERO, GL_ONE); + break; + + //Space Invaders + case 0x0448: // Add + case 0x055A: + glBlendFunc(GL_ONE, GL_ONE); + break; + + case 0xc712: // Pokemon Stadium? + case 0xAF50: // LOT in Zelda: MM + case 0x0F5A: // LOT in Zelda: MM + case 0x0FA5: // Seems to be doing just blend color - maybe combiner can be used for this? + case 0x5055: // Used in Paper Mario intro, I'm not sure if this is right... + //clr_in * 0 + clr_mem * 1 + glBlendFunc(GL_ZERO, GL_ONE); + break; + + case 0x5F50: //clr_mem * 0 + clr_mem * (1-a) + glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); + break; + + case 0xF550: //clr_fog * a_fog + clr_mem * (1-a) + case 0x0150: // spiderman + case 0x0550: // bomberman 64 + case 0x0D18: //clr_in * a_fog + clr_mem * (1-a) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + + case 0xC912: //40 winks, clr_in * a_fog + clr_mem * 1 + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + break; + + case 0x0040: // Fzero + case 0xC810: // Blends fog + case 0x0C18: // Standard interpolated blend + case 0x0050: // Standard interpolated blend + case 0x0051: // Standard interpolated blend + case 0x0055: // Used for antialiasing + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + + case 0x0C19: // Used for antialiasing + case 0xC811: // Blends fog + glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA); + break; + + case 0x5000: // V8 explosions + glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); + break; + + case 0xFA00: // Bomberman second attack + glBlendFunc(GL_ONE, GL_ZERO); + break; + + default: + //LOG(LOG_VERBOSE, "Unhandled blend mode=%x", gDP.otherMode.l >> 16); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + } + } + else if ((config.generalEmulation.hacks & hack_pilotWings) != 0 && (gDP.otherMode.l & 0x80) != 0) { //CLR_ON_CVG without FORCE_BL + glEnable(GL_BLEND); + glBlendFunc(GL_ZERO, GL_ONE); + } + else if ((config.generalEmulation.hacks & hack_blastCorps) != 0 && gDP.otherMode.cycleType < G_CYC_COPY && gSP.texture.on == 0 && currentCombiner()->usesTexture()) { // Blast Corps + glEnable(GL_BLEND); + glBlendFunc(GL_ZERO, GL_ONE); + } + else { + glDisable(GL_BLEND); + } +} + void OGLRender::_setBlendMode() const { + if (config.generalEmulation.enableLegacyBlending != 0) { + _legacySetBlendMode(); + return; + } + if (gDP.otherMode.forceBlender != 0 && gDP.otherMode.cycleType < G_CYC_COPY) { GLenum srcFactor = GL_ONE; GLenum dstFactor = GL_ZERO; diff --git a/src/OpenGL.h b/src/OpenGL.h index 4830b1e1..4d15aa53 100644 --- a/src/OpenGL.h +++ b/src/OpenGL.h @@ -187,6 +187,7 @@ private: void _setColorArray() const; void _setTexCoordArrays() const; void _setBlendMode() const; + void _legacySetBlendMode() const; void _updateCullFace() const; void _updateViewport() const; void _updateScreenCoordsViewport() const; diff --git a/src/ShaderUtils.cpp b/src/ShaderUtils.cpp index 279a2776..289106fc 100644 --- a/src/ShaderUtils.cpp +++ b/src/ShaderUtils.cpp @@ -316,14 +316,22 @@ int compileCombiner(Combiner & _color, Combiner & _alpha, std::string & _strShad } #endif - if (gDP.otherMode.cycleType <= G_CYC_2CYCLE) - _strShader.append(fragment_shader_blender1); - if (gDP.otherMode.cycleType == G_CYC_2CYCLE) - _strShader.append(fragment_shader_blender2); + if (config.generalEmulation.enableLegacyBlending == 0) { + if (gDP.otherMode.cycleType <= G_CYC_2CYCLE) + _strShader.append(fragment_shader_blender1); + if (gDP.otherMode.cycleType == G_CYC_2CYCLE) + _strShader.append(fragment_shader_blender2); - _strShader.append( - " fragColor = vec4(color2, alpha2); \n" - ); + _strShader.append( + " fragColor = vec4(color2, alpha2); \n" + ); + } else { + _strShader.append( + " fragColor = vec4(color2, alpha2); \n" + " if (uFogUsage == 1) \n" + " fragColor.rgb = mix(fragColor.rgb, uFogColor.rgb, vShadeColor.a); \n" + ); + } return nInputs; } diff --git a/src/mupenplus/Config_mupenplus.cpp b/src/mupenplus/Config_mupenplus.cpp index 2f0aa864..acea0c9e 100644 --- a/src/mupenplus/Config_mupenplus.cpp +++ b/src/mupenplus/Config_mupenplus.cpp @@ -74,6 +74,8 @@ bool Config_SetDefault() assert(res == M64ERR_SUCCESS); res = ConfigSetDefaultBool(g_configVideoGliden64, "enableNativeResTexrects", config.generalEmulation.enableNativeResTexrects, "Render 2D texrects in native resolution to fix misalignment between parts of 2D image."); assert(res == M64ERR_SUCCESS); + res = ConfigSetDefaultBool(g_configVideoGliden64, "enableLegacyBlending", config.generalEmulation.enableLegacyBlending, "Do not use shaders to emulate N64 blending modes. Works faster on slow GPU. Can cause glitches."); + assert(res == M64ERR_SUCCESS); #ifdef ANDROID res = ConfigSetDefaultBool(g_configVideoGliden64, "ForcePolygonOffset", config.generalEmulation.forcePolygonOffset, "If true, use polygon offset values specified below"); assert(res == M64ERR_SUCCESS); @@ -205,6 +207,7 @@ void Config_LoadConfig() config.generalEmulation.enableShadersStorage = ConfigGetParamBool(g_configVideoGliden64, "EnableShadersStorage"); config.generalEmulation.correctTexrectCoords = ConfigGetParamInt(g_configVideoGliden64, "CorrectTexrectCoords"); config.generalEmulation.enableNativeResTexrects = ConfigGetParamBool(g_configVideoGliden64, "enableNativeResTexrects"); + config.generalEmulation.enableLegacyBlending = ConfigGetParamBool(g_configVideoGliden64, "enableLegacyBlending"); #ifdef ANDROID config.generalEmulation.forcePolygonOffset = ConfigGetParamBool(g_configVideoGliden64, "ForcePolygonOffset"); config.generalEmulation.polygonOffsetFactor = ConfigGetParamFloat(g_configVideoGliden64, "PolygonOffsetFactor");