diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index d57b4fabb5..60fef26895 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -26,7 +26,7 @@ // Mash together all the inputs that contribute to the code of a generated pixel shader into // a unique identifier, basically containing all the bits. Yup, it's a lot .... -void GetPixelShaderId(PIXELSHADERUID &uid, u32 s_texturemask, u32 zbufrender, u32 zBufRenderToCol0) +void GetPixelShaderId(PIXELSHADERUID &uid, u32 s_texturemask, u32 zbufrender, u32 zBufRenderToCol0, u32 dstAlphaEnable) { u32 projtexcoords = 0; for (u32 i = 0; i < (u32)bpmem.genMode.numtevstages + 1; i++) { @@ -39,7 +39,7 @@ void GetPixelShaderId(PIXELSHADERUID &uid, u32 s_texturemask, u32 zbufrender, u3 uid.values[0] = (u32)bpmem.genMode.numtevstages | ((u32)bpmem.genMode.numindstages << 4) | ((u32)bpmem.genMode.numtexgens << 7) | - ((u32)bpmem.dstalpha.enable << 11) | + ((u32)dstAlphaEnable << 11) | ((u32)((bpmem.alphaFunc.hex >> 16) & 0xff) << 12) | (projtexcoords << 20) | ((u32)bpmem.ztex2.op << 28) | @@ -369,7 +369,7 @@ static void BuildSwapModeTable() } } -const char *GeneratePixelShader(u32 texture_mask, bool has_zbuffer_target, bool bRenderZToCol0, bool HLSL) +const char *GeneratePixelShader(u32 texture_mask, bool has_zbuffer_target, bool bRenderZToCol0, bool dstAlphaEnable, bool HLSL) { text[sizeof(text) - 1] = 0x7C; // canary DVSTARTPROFILE(); @@ -535,17 +535,12 @@ const char *GeneratePixelShader(u32 texture_mask, bool has_zbuffer_target, bool } else { if (!bRenderZToCol0) { - /* donkopunchstania: NEEDS FIX - dstalpha does not change how fragments are blended with the EFB - once the blending is done, the dstalpha is written to the EFB in place of the - fragment alpha if dstalpha is enabled. this only matters if the EFB supports alpha. - Commenting this out fixed Metroids but causes glitches in Super Mario Sunshine. - - if (bpmem.dstalpha.enable) + if (dstAlphaEnable) { WRITE(p, " ocol0 = float4(prev.rgb,"I_ALPHA"[0].w);\n"); - else - */ - WriteFog(p, bOutputZ); - WRITE(p, " ocol0 = prev;\n"); + } else { + WriteFog(p, bOutputZ); + WRITE(p, " ocol0 = prev;\n"); + } } else { WRITE(p, " ocol0 = prev;\n"); } diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.h b/Source/Core/VideoCommon/Src/PixelShaderGen.h index d6228f352b..d288e12f7b 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.h +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.h @@ -91,7 +91,7 @@ public: } }; -const char *GeneratePixelShader(u32 texture_mask, bool has_zbuffer_target, bool bRenderZToCol0, bool HLSL = false); -void GetPixelShaderId(PIXELSHADERUID &, u32 s_texturemask, u32 zbufrender, u32 zBufRenderToCol0); +const char *GeneratePixelShader(u32 texture_mask, bool has_zbuffer_target, bool bRenderZToCol0, bool dstAlphaEnable, bool HLSL = false); +void GetPixelShaderId(PIXELSHADERUID &, u32 s_texturemask, u32 zbufrender, u32 zBufRenderToCol0, u32 dstAlphaEnable); #endif diff --git a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp index 688a5a3eab..de316d2d8f 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/PixelShaderCache.cpp @@ -67,7 +67,7 @@ void PixelShaderCache::SetShader() DVSTARTPROFILE(); PIXELSHADERUID uid; - GetPixelShaderId(uid, PixelShaderManager::GetTextureMask(), false, false); + GetPixelShaderId(uid, PixelShaderManager::GetTextureMask(), false, false, false); PSCache::iterator iter; iter = PixelShaders.find(uid); @@ -85,7 +85,7 @@ void PixelShaderCache::SetShader() } bool HLSL = false; - const char *code = GeneratePixelShader(PixelShaderManager::GetTextureMask(), false, false, HLSL); + const char *code = GeneratePixelShader(PixelShaderManager::GetTextureMask(), false, false, false, HLSL); LPDIRECT3DPIXELSHADER9 shader = HLSL ? D3D::CompilePixelShader(code, (int)strlen(code), false) : CompileCgShader(code); if (shader) { diff --git a/Source/Plugins/Plugin_VideoOGL/Src/BPStructs.cpp b/Source/Plugins/Plugin_VideoOGL/Src/BPStructs.cpp index 7adeba7888..9c9b459222 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/BPStructs.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/BPStructs.cpp @@ -153,7 +153,7 @@ void BPWritten(int addr, int changes, int newval) PRIM_LOG("constalpha: alp=%d, en=%d\n", bpmem.dstalpha.alpha, bpmem.dstalpha.enable); SETSTAT(stats.dstAlphaEnable, bpmem.dstalpha.enable); SETSTAT_UINT(stats.dstAlpha, bpmem.dstalpha.alpha); - Renderer::SetBlendMode(false); + PixelShaderManager::SetDestAlpha(bpmem.dstalpha); } break; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp index 1408f9a74c..a582d10caa 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp @@ -105,13 +105,14 @@ GLuint PixelShaderCache::GetColorMatrixProgram() } -FRAGMENTSHADER* PixelShaderCache::GetShader() +FRAGMENTSHADER* PixelShaderCache::GetShader(bool dstAlphaEnable) { DVSTARTPROFILE(); PIXELSHADERUID uid; u32 zbufrender = (Renderer::UseFakeZTarget() && bpmem.zmode.updateenable) ? 1 : 0; u32 zBufRenderToCol0 = Renderer::GetRenderMode() != Renderer::RM_Normal; - GetPixelShaderId(uid, PixelShaderManager::GetTextureMask(), zbufrender, zBufRenderToCol0); + u32 dstAlpha = dstAlphaEnable ? 1 : 0; + GetPixelShaderId(uid, PixelShaderManager::GetTextureMask(), zbufrender, zBufRenderToCol0, dstAlpha); PSCache::iterator iter = pshaders.find(uid); @@ -128,7 +129,8 @@ FRAGMENTSHADER* PixelShaderCache::GetShader() PSCacheEntry& newentry = pshaders[uid]; const char *code = GeneratePixelShader(PixelShaderManager::GetTextureMask(), Renderer::UseFakeZTarget(), - Renderer::GetRenderMode() != Renderer::RM_Normal); + Renderer::GetRenderMode() != Renderer::RM_Normal, + dstAlphaEnable); #if defined(_DEBUG) || defined(DEBUGFAST) if (g_Config.iLog & CONF_SAVESHADERS && code) { diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h index c6956c7eb2..21a762dbfb 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.h @@ -58,7 +58,7 @@ public: static void ProgressiveCleanup(); static void Shutdown(); - static FRAGMENTSHADER* GetShader(); + static FRAGMENTSHADER* GetShader(bool dstAlphaEnable); static bool CompilePixelShader(FRAGMENTSHADER& ps, const char* pstrprogram); static GLuint GetColorMatrixProgram(); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 6398287dea..596284bc05 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -111,7 +111,6 @@ static bool s_bATIDrawBuffers = false; static bool s_bHaveStencilBuffer = false; static bool s_bHaveFramebufferBlit = false; static bool s_bHaveCoverageMSAA = false; -static bool g_bBlendSeparate = false; static u32 s_blendMode; static bool s_bNativeResolution = false; @@ -206,10 +205,6 @@ bool Renderer::Init() INFO_LOG(VIDEO, ptoken); // write to the log file INFO_LOG(VIDEO, "\n"); - if (strstr(ptoken, "GL_EXT_blend_func_separate") != NULL && - strstr(ptoken, "GL_EXT_blend_equation_separate") != NULL) - g_bBlendSeparate = true; - // Checks if it ONLY has the ATI_draw_buffers extension, some have both if (GLEW_ATI_draw_buffers && !GLEW_ARB_draw_buffers) s_bATIDrawBuffers = true; @@ -683,58 +678,35 @@ void Renderer::SetBlendMode(bool forceUpdate) { // blend mode bit mask // 0 - blend enable - // 1 - dst alpha enable // 2 - reverse subtract enable (else add) // 3-5 - srcRGB function // 6-8 - dstRGB function - // 9-16 - dstAlpha u32 newval = bpmem.blendmode.subtract << 2; - if (g_bBlendSeparate) { - newval |= bpmem.dstalpha.enable ? 3 : 0; - newval |= bpmem.dstalpha.alpha << 9; + if (bpmem.blendmode.subtract) { + newval |= 0x0049; // enable blending src 1 dst 1 + } else if (bpmem.blendmode.blendenable) { + newval |= 1; // enable blending + newval |= bpmem.blendmode.srcfactor << 3; + newval |= bpmem.blendmode.dstfactor << 6; } - - if (bpmem.blendmode.blendenable) { - newval |= 1; - if (bpmem.blendmode.subtract) { - newval |= 0x0048; // src 1 dst 1 - } else { - newval |= bpmem.blendmode.srcfactor << 3; - newval |= bpmem.blendmode.dstfactor << 6; - } - } else { - newval |= 0x0008; // src 1 dst 0 - } - + u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode; if (changes & 1) { + // blend enable change (newval & 1) ? glEnable(GL_BLEND) : glDisable(GL_BLEND); } - bool dstAlphaEnable = g_bBlendSeparate && newval & 2; - - if (changes & 6) { - // dst alpha enable or subtract enable change - if (dstAlphaEnable) - glBlendEquationSeparate(newval & 4 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD, GL_FUNC_ADD); - else - glBlendEquation(newval & 4 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD); + if (changes & 4) { + // subtract enable change + glBlendEquation(newval & 4 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD); } - if (changes & 0x1FA) { - // dst alpha enable or blend RGB change - if (dstAlphaEnable) - glBlendFuncSeparate(glSrcFactors[(newval >> 3) & 7], glDestFactors[(newval >> 6) & 7], GL_CONSTANT_ALPHA, GL_ZERO); - else - glBlendFunc(glSrcFactors[(newval >> 3) & 7], glDestFactors[(newval >> 6) & 7]); - } - - if (dstAlphaEnable && changes & 0x1FE00) { - // dst alpha color change - glBlendColor(0, 0, 0, (float)bpmem.dstalpha.alpha / 255.0f); + if (changes & 0x1F8) { + // blend RGB change + glBlendFunc(glSrcFactors[(newval >> 3) & 7], glDestFactors[(newval >> 6) & 7]); } s_blendMode = newval; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp index 6cea9e6828..bc2179f227 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp @@ -238,7 +238,7 @@ void Flush() PixelShaderManager::SetTexturesUsed(nonpow2tex); } - FRAGMENTSHADER* ps = PixelShaderCache::GetShader(); + FRAGMENTSHADER* ps = PixelShaderCache::GetShader(false); VERTEXSHADER* vs = VertexShaderCache::GetShader(g_nativeVertexFmt->m_components); bool bRestoreBuffers = false; @@ -284,6 +284,31 @@ void Flush() groupStart += s_vertexGroups[i].second; } + // run through vertex groups again to set alpha + if (bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate) { + ps = PixelShaderCache::GetShader(true); + + if (ps) glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ps->glprogid); + + // only update alpha + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); + + groupStart = 0; + for (unsigned i = 0; i < s_vertexGroups.size(); i++) + { + INCSTAT(stats.thisFrame.numDrawCalls); + glMultiDrawArrays(s_vertexGroups[i].first, + &s_vertexFirstOffset[groupStart], + &s_vertexGroupSize[groupStart], + s_vertexGroups[i].second); + groupStart += s_vertexGroups[i].second; + } + + // restore color mask + if (!bRestoreBuffers) + Renderer::SetColorMask(); + } + #if defined(_DEBUG) || defined(DEBUGFAST) if (g_Config.iLog & CONF_SAVESHADERS) { // save the shaders