From 45651098f6d15cfd474fc7edd6ea6539fe708f3c Mon Sep 17 00:00:00 2001 From: Rodolfo Bogado Date: Sun, 31 Mar 2013 20:02:13 -0300 Subject: [PATCH] Use a brute force approach to test for Dual source blend support. Sorry for a direct commit to the main branch but i need fast feedback, and i don't want to leave problematic code in the main branch for a long time. if this approach does not work for the drivers with problems will transform dual source blend to an option in the D3D9 backend. I appreciate the help of the people that tested my last commit and thanks to neobrain for pointing this solution. --- Source/Core/VideoCommon/Src/VideoConfig.h | 2 +- Source/Plugins/Plugin_VideoDX9/Src/Render.cpp | 51 +++++++++-------- Source/Plugins/Plugin_VideoDX9/Src/main.cpp | 57 ++++++++++++++----- 3 files changed, 70 insertions(+), 40 deletions(-) diff --git a/Source/Core/VideoCommon/Src/VideoConfig.h b/Source/Core/VideoCommon/Src/VideoConfig.h index 442e95f9bf..1a76baa733 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.h +++ b/Source/Core/VideoCommon/Src/VideoConfig.h @@ -153,7 +153,7 @@ struct VideoConfig bool bSupportsDualSourceBlend; // only supported by D3D11 and OpenGL bool bSupportsFormatReinterpretation; bool bSupportsPixelLighting; - + bool bSupportsSeparateAlphaFunction; bool bSupportsGLSLUBO; // needed by pixelShaderGen, so must stay in videoCommon } backend_info; diff --git a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp index 02bfe7e52c..0209477038 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp @@ -663,16 +663,16 @@ void Renderer::SetBlendMode(bool forceUpdate) bool target_has_alpha = bpmem.zcontrol.pixel_format == PIXELFMT_RGBA6_Z24; //bDstAlphaPass is taked in account because the ability of disabling alpha composition is //really usefull for debuging shader and blending errors - bool useDstAlpha = !g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate && target_has_alpha; - bool useDualSource = useDstAlpha && g_ActiveConfig.backend_info.bSupportsDualSourceBlend; + bool use_DstAlpha = !g_ActiveConfig.bDstAlphaPass && bpmem.dstalpha.enable && bpmem.blendmode.alphaupdate && target_has_alpha; + bool use_DualSource = use_DstAlpha && g_ActiveConfig.backend_info.bSupportsDualSourceBlend; const D3DBLEND d3dSrcFactors[8] = { D3DBLEND_ZERO, D3DBLEND_ONE, D3DBLEND_DESTCOLOR, D3DBLEND_INVDESTCOLOR, - (useDualSource) ? D3DBLEND_SRCCOLOR2 : D3DBLEND_SRCALPHA, - (useDualSource) ? D3DBLEND_INVSRCCOLOR2 : D3DBLEND_INVSRCALPHA, + (use_DualSource) ? D3DBLEND_SRCCOLOR2 : D3DBLEND_SRCALPHA, + (use_DualSource) ? D3DBLEND_INVSRCCOLOR2 : D3DBLEND_INVSRCALPHA, (target_has_alpha) ? D3DBLEND_DESTALPHA : D3DBLEND_ONE, (target_has_alpha) ? D3DBLEND_INVDESTALPHA : D3DBLEND_ZERO }; @@ -682,8 +682,8 @@ void Renderer::SetBlendMode(bool forceUpdate) D3DBLEND_ONE, D3DBLEND_SRCCOLOR, D3DBLEND_INVSRCCOLOR, - (useDualSource) ? D3DBLEND_SRCCOLOR2 : D3DBLEND_SRCALPHA, - (useDualSource) ? D3DBLEND_INVSRCCOLOR2 : D3DBLEND_INVSRCALPHA, + (use_DualSource) ? D3DBLEND_SRCCOLOR2 : D3DBLEND_SRCALPHA, + (use_DualSource) ? D3DBLEND_INVSRCCOLOR2 : D3DBLEND_INVSRCALPHA, (target_has_alpha) ? D3DBLEND_DESTALPHA : D3DBLEND_ONE, (target_has_alpha) ? D3DBLEND_INVDESTALPHA : D3DBLEND_ZERO }; @@ -696,7 +696,7 @@ void Renderer::SetBlendMode(bool forceUpdate) bool blend_enable = bpmem.blendmode.subtract || bpmem.blendmode.blendenable; D3D::SetRenderState(D3DRS_ALPHABLENDENABLE, blend_enable); - D3D::SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, blend_enable); + D3D::SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, blend_enable && g_ActiveConfig.backend_info.bSupportsSeparateAlphaFunction); if (blend_enable) { D3DBLENDOP op = D3DBLENDOP_ADD; @@ -711,24 +711,27 @@ void Renderer::SetBlendMode(bool forceUpdate) D3D::SetRenderState(D3DRS_BLENDOP, op); D3D::SetRenderState(D3DRS_SRCBLEND, d3dSrcFactors[srcidx]); D3D::SetRenderState(D3DRS_DESTBLEND, d3dDestFactors[dstidx]); - if (useDualSource) - { - op = D3DBLENDOP_ADD; - srcidx = GX_BL_ONE; - dstidx = GX_BL_ZERO; - } - else + if (g_ActiveConfig.backend_info.bSupportsSeparateAlphaFunction) { - // we can't use D3DBLEND_DESTCOLOR or D3DBLEND_INVDESTCOLOR for source in alpha channel so use their alpha equivalent instead - if (srcidx == GX_BL_DSTCLR) srcidx = GX_BL_DSTALPHA; - if (srcidx == GX_BL_INVDSTCLR) srcidx = GX_BL_INVDSTALPHA; - // we can't use D3DBLEND_SRCCOLOR or D3DBLEND_INVSRCCOLOR for destination in alpha channel so use their alpha equivalent instead - if (dstidx == GX_BL_SRCCLR) dstidx = GX_BL_SRCALPHA; - if (dstidx == GX_BL_INVSRCCLR) dstidx = GX_BL_INVSRCALPHA; - } - D3D::SetRenderState(D3DRS_BLENDOPALPHA, op); - D3D::SetRenderState(D3DRS_SRCBLENDALPHA, d3dSrcFactors[srcidx]); - D3D::SetRenderState(D3DRS_DESTBLENDALPHA, d3dDestFactors[dstidx]); + if (use_DualSource) + { + op = D3DBLENDOP_ADD; + srcidx = GX_BL_ONE; + dstidx = GX_BL_ZERO; + } + else + { + // we can't use D3DBLEND_DESTCOLOR or D3DBLEND_INVDESTCOLOR for source in alpha channel so use their alpha equivalent instead + if (srcidx == GX_BL_DSTCLR) srcidx = GX_BL_DSTALPHA; + if (srcidx == GX_BL_INVDSTCLR) srcidx = GX_BL_INVDSTALPHA; + // we can't use D3DBLEND_SRCCOLOR or D3DBLEND_INVSRCCOLOR for destination in alpha channel so use their alpha equivalent instead + if (dstidx == GX_BL_SRCCLR) dstidx = GX_BL_SRCALPHA; + if (dstidx == GX_BL_INVSRCCLR) dstidx = GX_BL_INVSRCALPHA; + } + D3D::SetRenderState(D3DRS_BLENDOPALPHA, op); + D3D::SetRenderState(D3DRS_SRCBLENDALPHA, d3dSrcFactors[srcidx]); + D3D::SetRenderState(D3DRS_DESTBLENDALPHA, d3dDestFactors[dstidx]); + } } } diff --git a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp index 10fab8ea5a..793b520d18 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp @@ -95,26 +95,16 @@ std::string VideoBackend::GetDisplayName() void InitBackendInfo() { DX9::D3D::Init(); - const int shaderModel = ((DX9::D3D::GetCaps().PixelShaderVersion >> 8) & 0xFF); + D3DCAPS9 device_caps = DX9::D3D::GetCaps(); + const int shaderModel = ((device_caps.PixelShaderVersion >> 8) & 0xFF); const int maxConstants = (shaderModel < 3) ? 32 : ((shaderModel < 4) ? 224 : 65536); g_Config.backend_info.APIType = shaderModel < 3 ? API_D3D9_SM20 : API_D3D9_SM30; g_Config.backend_info.bUseRGBATextures = false; g_Config.backend_info.bUseMinimalMipCount = true; g_Config.backend_info.bSupports3DVision = true; - OSVERSIONINFO info; - ZeroMemory(&info, sizeof(OSVERSIONINFO)); - info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - if (GetVersionEx(&info)) - { - // dual source blending is only supported in windows 7 o newer. sorry xp users - // we cannot test for device caps because most drivers just declare the minimun caps - // and don't expose their support for some functionalities - g_Config.backend_info.bSupportsDualSourceBlend = info.dwPlatformId == VER_PLATFORM_WIN32_NT && info.dwMajorVersion > 5; - } - else - { - g_Config.backend_info.bSupportsDualSourceBlend = false; - } + g_Config.backend_info.bSupportsSeparateAlphaFunction = device_caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND; + // Dual source blend will be tested later because in most devices the support is not declared in the device caps + g_Config.backend_info.bSupportsDualSourceBlend = false; g_Config.backend_info.bSupportsFormatReinterpretation = true; g_Config.backend_info.bSupportsPixelLighting = C_PLIGHTS + 40 <= maxConstants && C_PMATERIALS + 4 <= maxConstants; @@ -200,7 +190,44 @@ void VideoBackend::Video_Prepare() CommandProcessor::Init(); PixelEngine::Init(); DLCache::Init(); + // Test fo dual source blend support + // We can only support dual source blend if we first suport a separate alpha function + g_Config.backend_info.bSupportsDualSourceBlend = g_Config.backend_info.bSupportsSeparateAlphaFunction; + if(g_Config.backend_info.bSupportsDualSourceBlend) + { + // Test all the belnding modes that dual source blend requires + DWORD d3d_state = 0; + DWORD d3d_old_state = 0; + D3D::dev->SetRenderState(D3DRS_ALPHABLENDENABLE, true); + D3D::dev->GetRenderState(D3DRS_SRCBLEND, &d3d_old_state); + // Test for source D3DBLEND_SRCCOLOR2 support + D3D::dev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCCOLOR2); + D3D::dev->GetRenderState(D3DRS_SRCBLEND, &d3d_state); + g_Config.backend_info.bSupportsDualSourceBlend = (d3d_state == D3DBLEND_SRCCOLOR2); + // Test for source D3DBLEND_INVSRCCOLOR2 support + d3d_state = 0; + D3D::dev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_INVSRCCOLOR2); + D3D::dev->GetRenderState(D3DRS_SRCBLEND, &d3d_state); + g_Config.backend_info.bSupportsDualSourceBlend = g_Config.backend_info.bSupportsDualSourceBlend && d3d_state == D3DBLEND_INVSRCCOLOR2; + // Restore original state + D3D::dev->SetRenderState(D3DRS_SRCBLEND, d3d_old_state); + + d3d_old_state = 0; + D3D::dev->GetRenderState(D3DRS_DESTBLEND, &d3d_old_state); + // Test for destination D3DBLEND_SRCCOLOR2 support + D3D::dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR2); + D3D::dev->GetRenderState(D3DRS_DESTBLEND, &d3d_state); + g_Config.backend_info.bSupportsDualSourceBlend = g_Config.backend_info.bSupportsDualSourceBlend && d3d_state == D3DBLEND_SRCCOLOR2; + // test for destination D3DBLEND_INVSRCCOLOR2 support + d3d_state = 0; + D3D::dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR2); + D3D::dev->GetRenderState(D3DRS_DESTBLEND, &d3d_state); + g_Config.backend_info.bSupportsDualSourceBlend = g_Config.backend_info.bSupportsDualSourceBlend && d3d_state == D3DBLEND_INVSRCCOLOR2; + // Restore original state + D3D::dev->SetRenderState(D3DRS_DESTBLEND, d3d_old_state); + D3D::dev->SetRenderState(D3DRS_ALPHABLENDENABLE, false); + } // Notify the core that the video backend is ready Host_Message(WM_USER_CREATE); }