D3D11: Implement zcomploc for hardware supporting D3D 11.0.

This commit is contained in:
NeoBrainX 2013-07-22 14:38:09 +02:00 committed by degasus
parent 805009abca
commit eed36cbf78
6 changed files with 47 additions and 12 deletions

View File

@ -805,6 +805,7 @@ union PE_CONTROL
u32 unused : 17;
u32 rid : 8;
};
u32 hex;
};
@ -1005,6 +1006,9 @@ struct BPMemory
TevKSel tevksel[8];//0xf6,0xf7,f8,f9,fa,fb,fc,fd
u32 bpMask; //0xFE
u32 unknown18; //ff
bool UseEarlyDepthTest() const { return zcontrol.early_ztest && zmode.testenable; }
bool UseLateDepthTest() const { return !zcontrol.early_ztest && zmode.testenable; }
};
#pragma pack()

View File

@ -258,8 +258,8 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api
unsigned int numStages = bpmem.genMode.numtevstages + 1;
unsigned int numTexgen = bpmem.genMode.numtexgens;
const bool forced_early_z = g_ActiveConfig.backend_info.bSupportsEarlyZ && bpmem.zcontrol.early_ztest && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED);
const bool per_pixel_depth = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.early_ztest && bpmem.zmode.testenable) || (!g_ActiveConfig.bFastDepthCalc && !forced_early_z);
const bool forced_early_z = g_ActiveConfig.backend_info.bSupportsEarlyZ && bpmem.UseEarlyDepthTest() && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED);
const bool per_pixel_depth = (bpmem.ztex2.op != ZTEXTURE_DISABLE && bpmem.UseLateDepthTest()) || (!g_ActiveConfig.bFastDepthCalc && !forced_early_z);
out.Write("//Pixel Shader for TEV stages\n");
out.Write("//%i TEV stages, %i texgens, %i IND stages\n",
@ -365,18 +365,37 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api
}
out.Write("float4 clipPos;\n");
}
if (forced_early_z)
{
// HACK: This doesn't force the driver to write to depth buffer if alpha test fails.
// It just allows it, but it seems that all drivers do.
out.Write("layout(early_fragment_tests) in;\n");
}
else if (bpmem.UseEarlyDepthTest() && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED))
{
static bool warn_once = true;
if (warn_once)
WARN_LOG(VIDEO, "Early z test enabled but not possible to emulate with current configuration. Make sure to use the D3D11 or OpenGL backend and enable fast depth calculations. If this message still shows up your hardware isn't able to emulate the feature properly (a GPU which supports D3D 11.0 / OGL 4.2 is required).");
warn_once = false;
}
out.Write("void main()\n{\n");
}
else
{
if (forced_early_z)
{
out.Write("[earlydepthstencil]\n");
}
else if (bpmem.UseEarlyDepthTest() && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED))
{
static bool warn_once = true;
if (warn_once)
WARN_LOG(VIDEO, "Early z test enabled but not possible to emulate with current configuration. Make sure to use the D3D11 or OpenGL backend and enable fast depth calculations. If this message still shows up your hardware isn't able to emulate the feature properly (a GPU which supports D3D 11.0 / OGL 4.2 is required).");
warn_once = false;
}
out.Write("void main(\n");
if(ApiType != API_D3D11)
{
@ -630,11 +649,11 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api
uid_data.per_pixel_depth = per_pixel_depth;
uid_data.forced_early_z = forced_early_z;
uid_data.fast_depth_calc = g_ActiveConfig.bFastDepthCalc;
uid_data.early_ztest = bpmem.zcontrol.early_ztest;
uid_data.early_ztest = bpmem.UseEarlyDepthTest();
uid_data.fog_fsel = bpmem.fog.c_proj_fsel.fsel;
// Note: z-textures are not written to depth buffer if early depth test is used
if (per_pixel_depth && bpmem.zcontrol.early_ztest)
if (per_pixel_depth && bpmem.UseEarlyDepthTest())
out.Write("depth = zCoord;\n");
// Note: depth texture output is only written to depth buffer if late depth test is used
@ -652,7 +671,7 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api
out.Write("zCoord = zCoord * (16777216.0f/16777215.0f);\n");
}
if (per_pixel_depth && !bpmem.zcontrol.early_ztest)
if (per_pixel_depth && bpmem.UseLateDepthTest())
out.Write("depth = zCoord;\n");
if (dstAlphaMode == DSTALPHA_ALPHA_PASS)
@ -1185,11 +1204,11 @@ static void WriteAlphaTest(T& out, pixel_shader_uid_data& uid_data, API_TYPE Api
// We implement "depth test before texturing" by disabling alpha test when early-z is in use.
// It seems to be less buggy than not to update the depth buffer if alpha test fails,
// but both ways wouldn't be accurate.
// OpenGL 4.2 has a flag which allows the driver to still update the depth buffer
// if alpha test fails. The driver doesn't have to, but I assume they all do because
// it's the much faster code path for the GPU.
uid_data.alpha_test_use_zcomploc_hack = bpmem.zcontrol.early_ztest && bpmem.zmode.updateenable && !g_ActiveConfig.backend_info.bSupportsEarlyZ;
uid_data.alpha_test_use_zcomploc_hack = bpmem.UseEarlyDepthTest() && bpmem.zmode.updateenable && !g_ActiveConfig.backend_info.bSupportsEarlyZ;
if (!uid_data.alpha_test_use_zcomploc_hack)
{
out.Write("\t\tdiscard;\n");

View File

@ -245,6 +245,13 @@ std::vector<DXGI_SAMPLE_DESC> EnumAAModes(IDXGIAdapter* adapter)
return aa_modes;
}
D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter)
{
D3D_FEATURE_LEVEL feat_level = D3D_FEATURE_LEVEL_9_1;
PD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, D3D11_CREATE_DEVICE_SINGLETHREADED, supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, NULL, &feat_level, NULL);
return feat_level;
}
DXGI_SAMPLE_DESC GetAAMode(int index)
{
return aa_modes[index];

View File

@ -31,6 +31,7 @@ void UnloadD3D();
void UnloadD3DX();
void UnloadD3DCompiler();
D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter);
std::vector<DXGI_SAMPLE_DESC> EnumAAModes(IDXGIAdapter* adapter);
DXGI_SAMPLE_DESC GetAAMode(int index);

View File

@ -90,7 +90,6 @@ void InitBackendInfo()
g_Config.backend_info.bSupportsFormatReinterpretation = true;
g_Config.backend_info.bSupportsPixelLighting = true;
g_Config.backend_info.bSupportsPrimitiveRestart = true;
g_Config.backend_info.bSupportsEarlyZ = false;
IDXGIFactory* factory;
IDXGIAdapter* ad;
@ -103,11 +102,13 @@ void InitBackendInfo()
g_Config.backend_info.AAModes.clear();
while (factory->EnumAdapters((UINT)g_Config.backend_info.Adapters.size(), &ad) != DXGI_ERROR_NOT_FOUND)
{
const size_t adapter_index = g_Config.backend_info.Adapters.size();
DXGI_ADAPTER_DESC desc;
ad->GetDesc(&desc);
// TODO: These don't get updated on adapter change, yet
if (g_Config.backend_info.Adapters.size() == g_Config.iAdapter)
if (adapter_index == g_Config.iAdapter)
{
char buf[32];
std::vector<DXGI_SAMPLE_DESC> modes;
@ -119,6 +120,9 @@ void InitBackendInfo()
else sprintf_s(buf, 32, _trans("%d samples"), modes[i].Count);
g_Config.backend_info.AAModes.push_back(buf);
}
// Requires the earlydepthstencil attribute (only available in shader model 5)
g_Config.backend_info.bSupportsEarlyZ = (DX11::D3D::GetFeatureLevel(ad) == D3D_FEATURE_LEVEL_11_0);
}
g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description));

View File

@ -135,7 +135,7 @@ inline void Draw(s32 x, s32 y, s32 xi, s32 yi)
if (z < 0 || z > 0x00ffffff)
return;
if (bpmem.zcontrol.early_ztest && bpmem.zmode.testenable && g_SWVideoConfig.bZComploc)
if (bpmem.UseEarlyDepthTest() && g_SWVideoConfig.bZComploc)
{
// TODO: Test if perf regs are incremented even if test is disabled
SWPixelEngine::pereg.IncZInputQuadCount(true);