Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
D3D11: Implement zcomploc for hardware supporting D3D 11.0.
  • Loading branch information
neobrain authored and degasus committed Aug 9, 2013
1 parent 805009a commit eed36cb
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 12 deletions.
4 changes: 4 additions & 0 deletions Source/Core/VideoCommon/Src/BPMemory.h
Expand Up @@ -805,6 +805,7 @@ union PE_CONTROL
u32 unused : 17;
u32 rid : 8;
};

u32 hex;
};

Expand Down Expand Up @@ -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()
Expand Down
37 changes: 28 additions & 9 deletions Source/Core/VideoCommon/Src/PixelShaderGen.cpp
Expand Up @@ -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",
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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");
Expand Down
7 changes: 7 additions & 0 deletions Source/Plugins/Plugin_VideoDX11/Src/D3DBase.cpp
Expand Up @@ -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];
Expand Down
1 change: 1 addition & 0 deletions Source/Plugins/Plugin_VideoDX11/Src/D3DBase.h
Expand Up @@ -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);

Expand Down
8 changes: 6 additions & 2 deletions Source/Plugins/Plugin_VideoDX11/Src/main.cpp
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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));
Expand Down
2 changes: 1 addition & 1 deletion Source/Plugins/Plugin_VideoSoftware/Src/Rasterizer.cpp
Expand Up @@ -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);
Expand Down

0 comments on commit eed36cb

Please sign in to comment.