Change destination alpha handling. The blending method introduced in rev 1921 was not the correct way to do it. This way was suggested by hrydgard in October and I should have listened. A simple pixel shader as hrydgard suggested cannot be used because the alpha is not set if the pixel is discarded due to failing depth (after z texture) or alpha (result of tev stages) tests. There is a bit of a performance hit so there should be an option to disable the second render pass which sets the alpha because it is probably not needed most of the time.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2662 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
donkopunchstania 2009-03-16 02:47:48 +00:00
parent b1b2868c8b
commit 90254bd924
8 changed files with 59 additions and 65 deletions

View File

@ -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");
}

View File

@ -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

View File

@ -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)
{

View File

@ -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;

View File

@ -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) {

View File

@ -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();

View File

@ -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;

View File

@ -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