From c223bd47b9b2a83ed53201964e4912e2faec3d66 Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Wed, 3 Aug 2016 02:01:36 +0200 Subject: [PATCH 01/15] VideoCommon: Implement depth range equation in vertex shader. --- Source/Core/VideoBackends/OGL/Render.cpp | 8 +------- Source/Core/VideoCommon/VertexShaderGen.cpp | 10 +++++----- Source/Core/VideoCommon/VertexShaderManager.cpp | 5 +++++ 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index bde616deac..26f1c8cc21 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -1115,12 +1115,6 @@ void Renderer::SetViewport() (float)scissorYOff); float Width = EFBToScaledXf(2.0f * xfmem.viewport.wd); float Height = EFBToScaledYf(-2.0f * xfmem.viewport.ht); - float GLNear = MathUtil::Clamp( - xfmem.viewport.farZ - - MathUtil::Clamp(xfmem.viewport.zRange, -16777216.0f, 16777216.0f), - 0.0f, 16777215.0f) / - 16777216.0f; - float GLFar = MathUtil::Clamp(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f; if (Width < 0) { X += Width; @@ -1142,7 +1136,7 @@ void Renderer::SetViewport() auto iceilf = [](float f) { return static_cast(ceilf(f)); }; glViewport(iceilf(X), iceilf(Y), iceilf(Width), iceilf(Height)); } - glDepthRangef(GLFar, GLNear); + glDepthRangef(0.0f, 1.0f); } void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index aa69550bd8..e23be6590c 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -399,14 +399,14 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da out.Write("o.colors_1 = color1;\n"); } + // We have to handle the depth range in the vertex shader, because some games will use a depth range beyond + // the normal depth range of 0..1. + out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION".w + o.pos.z * " I_PIXELCENTERCORRECTION".z;\n"); + // write the true depth value, if the game uses depth textures pixel shaders will override with // the correct values // if not early z culling will improve speed - if (g_ActiveConfig.backend_info.bSupportsClipControl) - { - out.Write("o.pos.z = -o.pos.z;\n"); - } - else // OGL + if (!g_ActiveConfig.backend_info.bSupportsClipControl) { // this results in a scale from -1..0 to -1..1 after perspective // divide diff --git a/Source/Core/VideoCommon/VertexShaderManager.cpp b/Source/Core/VideoCommon/VertexShaderManager.cpp index 19fb1f371d..0fb784167d 100644 --- a/Source/Core/VideoCommon/VertexShaderManager.cpp +++ b/Source/Core/VideoCommon/VertexShaderManager.cpp @@ -386,6 +386,11 @@ void VertexShaderManager::SetConstants() const float pixel_size_y = 2.f / Renderer::EFBToScaledXf(2.f * xfmem.viewport.ht); constants.pixelcentercorrection[0] = pixel_center_correction * pixel_size_x; constants.pixelcentercorrection[1] = pixel_center_correction * pixel_size_y; + + // The depth range is handled in the vertex shader. + constants.pixelcentercorrection[2] = (xfmem.viewport.zRange) / 16777216.0f; + constants.pixelcentercorrection[3] = (xfmem.viewport.farZ) / 16777216.0f; + dirty = true; // This is so implementation-dependent that we can't have it here. g_renderer->SetViewport(); From 92aa7669b58442c37b235755e2a6b6ce81963b9a Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Thu, 4 Aug 2016 18:26:45 +0200 Subject: [PATCH 02/15] VertexShaderManager: Use a more accurate depth range. This fixes the gxtest_depth hwtest. --- Source/Core/VideoCommon/VertexShaderManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/VideoCommon/VertexShaderManager.cpp b/Source/Core/VideoCommon/VertexShaderManager.cpp index 0fb784167d..83600463e9 100644 --- a/Source/Core/VideoCommon/VertexShaderManager.cpp +++ b/Source/Core/VideoCommon/VertexShaderManager.cpp @@ -388,8 +388,8 @@ void VertexShaderManager::SetConstants() constants.pixelcentercorrection[1] = pixel_center_correction * pixel_size_y; // The depth range is handled in the vertex shader. - constants.pixelcentercorrection[2] = (xfmem.viewport.zRange) / 16777216.0f; - constants.pixelcentercorrection[3] = (xfmem.viewport.farZ) / 16777216.0f; + constants.pixelcentercorrection[2] = xfmem.viewport.zRange / 16777215.0f; + constants.pixelcentercorrection[3] = xfmem.viewport.farZ / 16777215.0f; dirty = true; // This is so implementation-dependent that we can't have it here. From 159247f4ad51e6b8dc911357ebe8d6327ebd5a37 Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Thu, 4 Aug 2016 18:27:12 +0200 Subject: [PATCH 03/15] VertexShaderGen: Clamp to the console depth range. This fixes the Mii Channel among others. --- Source/Core/VideoCommon/VertexShaderGen.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index e23be6590c..0863e9f17f 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -403,6 +403,10 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da // the normal depth range of 0..1. out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION".w + o.pos.z * " I_PIXELCENTERCORRECTION".z;\n"); + // We have to clamp to 2^24 - 1 here, because we map our depth range to 0..2^24 to prevent round-trip errors. + // Thus we test for values that will result in 2^24 or higher after the perspective divide. + out.Write("if (o.pos.z / o.pos.w >= 1.0) o.pos.z = 16777215.0 / 16777216.0 * o.pos.w;\n"); + // write the true depth value, if the game uses depth textures pixel shaders will override with // the correct values // if not early z culling will improve speed From b1ed7e80fb689da5a4679e5c178f91391e55a6ff Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Thu, 4 Aug 2016 14:09:35 +0200 Subject: [PATCH 04/15] VertexShaderGen: Clip z using user-defined clipping planes. --- Source/Core/VideoBackends/OGL/Render.cpp | 1 + Source/Core/VideoCommon/ShaderGenCommon.h | 4 ++++ Source/Core/VideoCommon/VertexShaderGen.cpp | 5 +++++ 3 files changed, 10 insertions(+) diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 26f1c8cc21..13a34ce2e1 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -724,6 +724,7 @@ Renderer::Renderer() glClearDepthf(1.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); + glEnable(GL_CLIP_DISTANCE0); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment diff --git a/Source/Core/VideoCommon/ShaderGenCommon.h b/Source/Core/VideoCommon/ShaderGenCommon.h index e7d0667861..434099e85e 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/ShaderGenCommon.h @@ -196,6 +196,8 @@ inline void GenerateVSOutputMembers(T& object, APIType api_type, u32 texgens, DefineOutputMember(object, api_type, qualifier, "float3", "WorldPos", -1, "TEXCOORD", texgens + 2); } + + DefineOutputMember(object, api_type, qualifier, "float", "clipDist", -1, "SV_ClipDistance"); } template @@ -216,6 +218,8 @@ inline void AssignVSOutputMembers(T& object, const char* a, const char* b, u32 t object.Write("\t%s.Normal = %s.Normal;\n", a, b); object.Write("\t%s.WorldPos = %s.WorldPos;\n", a, b); } + + object.Write("\t%s.clipDist = %s.clipDist;\n", a, b); } // We use the flag "centroid" to fix some MSAA rendering bugs. With MSAA, the diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 0863e9f17f..abb79d90fc 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -399,6 +399,10 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da out.Write("o.colors_1 = color1;\n"); } + // Since we're adjusting z for the depth range before the perspective divide, we have to do our + // own clipping. + out.Write("o.clipDist = o.pos.z + o.pos.w;\n"); + // We have to handle the depth range in the vertex shader, because some games will use a depth range beyond // the normal depth range of 0..1. out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION".w + o.pos.z * " I_PIXELCENTERCORRECTION".z;\n"); @@ -457,6 +461,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da out.Write("colors_1 = o.colors_1;\n"); } + out.Write("gl_ClipDistance[0] = o.clipDist;\n"); out.Write("gl_Position = o.pos;\n"); } else // D3D From e9e81ece6538c6676054dbc0e9d156fcc59801c9 Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Wed, 3 Aug 2016 21:54:22 +0200 Subject: [PATCH 05/15] VideoBackends: Enable depth clamping. --- Source/Core/VideoBackends/D3D/D3DState.cpp | 2 +- Source/Core/VideoBackends/D3D/Render.cpp | 9 +-------- Source/Core/VideoBackends/D3D12/D3DState.cpp | 2 +- Source/Core/VideoBackends/D3D12/Render.cpp | 8 ++------ Source/Core/VideoBackends/OGL/Render.cpp | 3 ++- Source/Core/VideoCommon/VertexShaderGen.cpp | 4 ---- 6 files changed, 7 insertions(+), 21 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index e277c74805..e82f103586 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -440,7 +440,7 @@ ID3D11RasterizerState* StateCache::Get(RasterizerState state) return it->second; D3D11_RASTERIZER_DESC rastdc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, state.cull_mode, false, 0, - 0.f, 0, true, true, false, false); + 0.f, 0, false, true, false, false); ID3D11RasterizerState* res = nullptr; diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index d7babc9ff7..d1cf55b982 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -578,14 +578,7 @@ void Renderer::SetViewport() Wd = (X + Wd <= GetTargetWidth()) ? Wd : (GetTargetWidth() - X); Ht = (Y + Ht <= GetTargetHeight()) ? Ht : (GetTargetHeight() - Y); - D3D11_VIEWPORT vp = CD3D11_VIEWPORT( - X, Y, Wd, Ht, - 1.0f - MathUtil::Clamp(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f, - 1.0f - - MathUtil::Clamp(xfmem.viewport.farZ - MathUtil::Clamp(xfmem.viewport.zRange, - 0.0f, 16777216.0f), - 0.0f, 16777215.0f) / - 16777216.0f); + D3D11_VIEWPORT vp = CD3D11_VIEWPORT(X, Y, Wd, Ht, D3D11_MIN_DEPTH, 16777215.0f / 16777216.0f); D3D::context->RSSetViewports(1, &vp); } diff --git a/Source/Core/VideoBackends/D3D12/D3DState.cpp b/Source/Core/VideoBackends/D3D12/D3DState.cpp index 2902f3272f..36e997d895 100644 --- a/Source/Core/VideoBackends/D3D12/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DState.cpp @@ -329,7 +329,7 @@ D3D12_RASTERIZER_DESC StateCache::GetDesc12(RasterizerState state) 0, 0.f, 0, - true, + false, true, false, 0, diff --git a/Source/Core/VideoBackends/D3D12/Render.cpp b/Source/Core/VideoBackends/D3D12/Render.cpp index 6124534204..6e6e6a8f3c 100644 --- a/Source/Core/VideoBackends/D3D12/Render.cpp +++ b/Source/Core/VideoBackends/D3D12/Render.cpp @@ -484,12 +484,8 @@ void Renderer::SetViewport() D3D12_VIEWPORT vp = { x, y, width, height, - 1.0f - MathUtil::Clamp(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f, - 1.0f - - MathUtil::Clamp(xfmem.viewport.farZ - MathUtil::Clamp(xfmem.viewport.zRange, - 0.0f, 16777216.0f), - 0.0f, 16777215.0f) / - 16777216.0f}; + D3D12_MIN_DEPTH, + 16777215.0f / 16777216.0f }; D3D::current_command_list->RSSetViewports(1, &vp); } diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 13a34ce2e1..fb40705279 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -725,6 +725,7 @@ Renderer::Renderer() glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glEnable(GL_CLIP_DISTANCE0); + glEnable(GL_DEPTH_CLAMP); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment @@ -1137,7 +1138,7 @@ void Renderer::SetViewport() auto iceilf = [](float f) { return static_cast(ceilf(f)); }; glViewport(iceilf(X), iceilf(Y), iceilf(Width), iceilf(Height)); } - glDepthRangef(0.0f, 1.0f); + glDepthRangef(0.0f, 16777215.0f / 16777216.0f); } void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index abb79d90fc..518c75244c 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -407,10 +407,6 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da // the normal depth range of 0..1. out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION".w + o.pos.z * " I_PIXELCENTERCORRECTION".z;\n"); - // We have to clamp to 2^24 - 1 here, because we map our depth range to 0..2^24 to prevent round-trip errors. - // Thus we test for values that will result in 2^24 or higher after the perspective divide. - out.Write("if (o.pos.z / o.pos.w >= 1.0) o.pos.z = 16777215.0 / 16777216.0 * o.pos.w;\n"); - // write the true depth value, if the game uses depth textures pixel shaders will override with // the correct values // if not early z culling will improve speed From 4582853af48f67047e57b997bf923488bf444931 Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Sat, 6 Aug 2016 03:40:45 +0200 Subject: [PATCH 06/15] VertexShaderGen: Use reversed depth range. --- Source/Core/VideoBackends/OGL/Render.cpp | 2 +- Source/Core/VideoCommon/VertexShaderGen.cpp | 4 ++-- Source/Core/VideoCommon/VertexShaderManager.cpp | 7 +++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index fb40705279..692bf36e51 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -1138,7 +1138,7 @@ void Renderer::SetViewport() auto iceilf = [](float f) { return static_cast(ceilf(f)); }; glViewport(iceilf(X), iceilf(Y), iceilf(Width), iceilf(Height)); } - glDepthRangef(0.0f, 16777215.0f / 16777216.0f); + glDepthRangef(16777215.0f / 16777216.0f, 0.0f); } void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 518c75244c..9110cbfe99 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -405,7 +405,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da // We have to handle the depth range in the vertex shader, because some games will use a depth range beyond // the normal depth range of 0..1. - out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION".w + o.pos.z * " I_PIXELCENTERCORRECTION".z;\n"); + out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION".w - o.pos.z * " I_PIXELCENTERCORRECTION".z;\n"); // write the true depth value, if the game uses depth textures pixel shaders will override with // the correct values @@ -414,7 +414,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da { // this results in a scale from -1..0 to -1..1 after perspective // divide - out.Write("o.pos.z = o.pos.z * -2.0 - o.pos.w;\n"); + out.Write("o.pos.z = o.pos.z * 2.0 - o.pos.w;\n"); // the next steps of the OGL pipeline are: // (x_c,y_c,z_c,w_c) = o.pos //switch to OGL spec terminology diff --git a/Source/Core/VideoCommon/VertexShaderManager.cpp b/Source/Core/VideoCommon/VertexShaderManager.cpp index 83600463e9..dabc7870fd 100644 --- a/Source/Core/VideoCommon/VertexShaderManager.cpp +++ b/Source/Core/VideoCommon/VertexShaderManager.cpp @@ -387,9 +387,12 @@ void VertexShaderManager::SetConstants() constants.pixelcentercorrection[0] = pixel_center_correction * pixel_size_x; constants.pixelcentercorrection[1] = pixel_center_correction * pixel_size_y; - // The depth range is handled in the vertex shader. + // The depth range is handled in the vertex shader. We need to reverse + // the far value to get a reversed depth range mapping. This is necessary + // because we have the most precision at the near plane, while the console + // has the most percision at the far plane. constants.pixelcentercorrection[2] = xfmem.viewport.zRange / 16777215.0f; - constants.pixelcentercorrection[3] = xfmem.viewport.farZ / 16777215.0f; + constants.pixelcentercorrection[3] = 1.0f - xfmem.viewport.farZ / 16777215.0f; dirty = true; // This is so implementation-dependent that we can't have it here. From a141e91dd226885fc767d009938ca61a22f86558 Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Fri, 5 Aug 2016 22:31:34 +0200 Subject: [PATCH 07/15] OGL: Check for GL_DEPTH_CLAMP support. It's not available in OpenGL ES and officially it's not supported on OpenGL 3.0/3.1. Fallback to old depth range code if there is no method to disable depth clipping. It's more important to have correct clipping than to have accurate depth values. Inaccurate depth values can be fixed by slow depth. --- Source/Core/VideoBackends/D3D/main.cpp | 1 + Source/Core/VideoBackends/D3D12/main.cpp | 1 + Source/Core/VideoBackends/OGL/Render.cpp | 30 +++++++++++++++++---- Source/Core/VideoBackends/OGL/main.cpp | 1 + Source/Core/VideoCommon/VertexShaderGen.cpp | 24 ++++++++++++----- Source/Core/VideoCommon/VideoConfig.h | 1 + 6 files changed, 46 insertions(+), 12 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/main.cpp b/Source/Core/VideoBackends/D3D/main.cpp index e471e3715a..2471135afd 100644 --- a/Source/Core/VideoBackends/D3D/main.cpp +++ b/Source/Core/VideoBackends/D3D/main.cpp @@ -71,6 +71,7 @@ void VideoBackend::InitBackendInfo() g_Config.backend_info.bSupportsPostProcessing = false; g_Config.backend_info.bSupportsPaletteConversion = true; g_Config.backend_info.bSupportsClipControl = true; + g_Config.backend_info.bSupportsDepthClamp = true; IDXGIFactory* factory; IDXGIAdapter* ad; diff --git a/Source/Core/VideoBackends/D3D12/main.cpp b/Source/Core/VideoBackends/D3D12/main.cpp index 69a53603f1..f6e5512da1 100644 --- a/Source/Core/VideoBackends/D3D12/main.cpp +++ b/Source/Core/VideoBackends/D3D12/main.cpp @@ -74,6 +74,7 @@ void VideoBackend::InitBackendInfo() g_Config.backend_info.bSupportsPostProcessing = false; g_Config.backend_info.bSupportsPaletteConversion = true; g_Config.backend_info.bSupportsClipControl = true; + g_Config.backend_info.bSupportsDepthClamp = true; IDXGIFactory* factory; IDXGIAdapter* ad; diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 692bf36e51..5af9407763 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -481,6 +481,9 @@ Renderer::Renderer() g_Config.backend_info.bSupportsBindingLayout = GLExtensions::Supports("GL_ARB_shading_language_420pack"); + // Clip distance support is useless without a method to clamp the depth range + g_Config.backend_info.bSupportsDepthClamp = GLExtensions::Supports("GL_ARB_depth_clamp"); + g_ogl_config.bSupportsGLSLCache = GLExtensions::Supports("GL_ARB_get_program_binary"); g_ogl_config.bSupportsGLPinnedMemory = GLExtensions::Supports("GL_AMD_pinned_memory"); g_ogl_config.bSupportsGLSync = GLExtensions::Supports("GL_ARB_sync"); @@ -520,6 +523,9 @@ Renderer::Renderer() g_ogl_config.bSupportsGLSLCache = true; g_ogl_config.bSupportsGLSync = true; + // TODO: Implement support for GL_EXT_clip_cull_distance when there is an extension for depth clamping. + g_Config.backend_info.bSupportsDepthClamp = false; + if (strstr(g_ogl_config.glsl_version, "3.0")) { g_ogl_config.eSupportedGLSLVersion = GLSLES_300; @@ -669,7 +675,7 @@ Renderer::Renderer() g_ogl_config.gl_renderer, g_ogl_config.gl_version), 5000); - WARN_LOG(VIDEO, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s%s%s%s", + WARN_LOG(VIDEO, "Missing OGL Extensions: %s%s%s%s%s%s%s%s%s%s%s%s%s%s", g_ActiveConfig.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend ", g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? "" : "PrimitiveRestart ", g_ActiveConfig.backend_info.bSupportsEarlyZ ? "" : "EarlyZ ", @@ -681,7 +687,8 @@ Renderer::Renderer() g_ActiveConfig.backend_info.bSupportsSSAA ? "" : "SSAA ", g_ActiveConfig.backend_info.bSupportsGSInstancing ? "" : "GSInstancing ", g_ActiveConfig.backend_info.bSupportsClipControl ? "" : "ClipControl ", - g_ogl_config.bSupportsCopySubImage ? "" : "CopyImageSubData "); + g_ogl_config.bSupportsCopySubImage ? "" : "CopyImageSubData ", + g_ActiveConfig.backend_info.bSupportsDepthClamp ? "" : "DepthClamp "); s_last_multisamples = g_ActiveConfig.iMultisamples; s_MSAASamples = s_last_multisamples; @@ -724,8 +731,11 @@ Renderer::Renderer() glClearDepthf(1.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); - glEnable(GL_CLIP_DISTANCE0); - glEnable(GL_DEPTH_CLAMP); + if (g_ActiveConfig.backend_info.bSupportsDepthClamp) + { + glEnable(GL_CLIP_DISTANCE0); + glEnable(GL_DEPTH_CLAMP); + } glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment @@ -1117,6 +1127,12 @@ void Renderer::SetViewport() (float)scissorYOff); float Width = EFBToScaledXf(2.0f * xfmem.viewport.wd); float Height = EFBToScaledYf(-2.0f * xfmem.viewport.ht); + float GLNear = MathUtil::Clamp( + xfmem.viewport.farZ - + MathUtil::Clamp(xfmem.viewport.zRange, -16777216.0f, 16777216.0f), + 0.0f, 16777215.0f) / + 16777216.0f; + float GLFar = MathUtil::Clamp(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f; if (Width < 0) { X += Width; @@ -1138,7 +1154,11 @@ void Renderer::SetViewport() auto iceilf = [](float f) { return static_cast(ceilf(f)); }; glViewport(iceilf(X), iceilf(Y), iceilf(Width), iceilf(Height)); } - glDepthRangef(16777215.0f / 16777216.0f, 0.0f); + + if (g_ActiveConfig.backend_info.bSupportsDepthClamp) + glDepthRangef(16777215.0f / 16777216.0f, 0.0f); + else + glDepthRangef(GLFar, GLNear); } void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, diff --git a/Source/Core/VideoBackends/OGL/main.cpp b/Source/Core/VideoBackends/OGL/main.cpp index 5f667efb1d..d27b763a88 100644 --- a/Source/Core/VideoBackends/OGL/main.cpp +++ b/Source/Core/VideoBackends/OGL/main.cpp @@ -108,6 +108,7 @@ void VideoBackend::InitBackendInfo() g_Config.backend_info.bSupportsPrimitiveRestart = true; g_Config.backend_info.bSupportsPaletteConversion = true; g_Config.backend_info.bSupportsClipControl = true; + g_Config.backend_info.bSupportsDepthClamp = true; g_Config.backend_info.Adapters.clear(); diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 9110cbfe99..85359ac6ee 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -399,13 +399,22 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da out.Write("o.colors_1 = color1;\n"); } - // Since we're adjusting z for the depth range before the perspective divide, we have to do our - // own clipping. - out.Write("o.clipDist = o.pos.z + o.pos.w;\n"); + if (g_ActiveConfig.backend_info.bSupportsDepthClamp) + { + // Since we're adjusting z for the depth range before the perspective divide, we have to do our + // own clipping. + out.Write("o.clipDist = o.pos.z + o.pos.w;\n"); - // We have to handle the depth range in the vertex shader, because some games will use a depth range beyond - // the normal depth range of 0..1. - out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION".w - o.pos.z * " I_PIXELCENTERCORRECTION".z;\n"); + // We have to handle the depth range in the vertex shader, because some games will use a depth range beyond + // the normal depth range of 0..1. + out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION".w - o.pos.z * " I_PIXELCENTERCORRECTION".z;\n"); + } + else + { + // User-defined clipping is not supported, thus we rely on the API to handle the depth range for us. + // We still need to take care of the reversed depth, so we do that here. + out.Write("o.pos.z = -o.pos.z;\n"); + } // write the true depth value, if the game uses depth textures pixel shaders will override with // the correct values @@ -457,7 +466,8 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da out.Write("colors_1 = o.colors_1;\n"); } - out.Write("gl_ClipDistance[0] = o.clipDist;\n"); + if (g_ActiveConfig.backend_info.bSupportsDepthClamp) + out.Write("gl_ClipDistance[0] = o.clipDist;\n"); out.Write("gl_Position = o.pos;\n"); } else // D3D diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index 92be4726ef..c95706db53 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -171,6 +171,7 @@ struct VideoConfig final bool bSupportsPaletteConversion; bool bSupportsClipControl; // Needed by VertexShaderGen, so must stay in VideoCommon bool bSupportsSSAA; + bool bSupportsDepthClamp; // Needed by VertexShaderGen, so must stay in VideoCommon } backend_info; // Utility From 9596ec8971be8593b96ac67a76195b5ed23ff794 Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Thu, 11 Aug 2016 17:03:49 +0200 Subject: [PATCH 08/15] GeometryShaderGen: Pass-through clipping distance. --- Source/Core/VideoCommon/GeometryShaderGen.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp index 4d90e6f10d..03979d0bbe 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.cpp +++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp @@ -312,6 +312,8 @@ static void EmitVertex(ShaderCode& out, const geometry_shader_uid_data* uid_data if (ApiType == APIType::OpenGL) { out.Write("\tgl_Position = %s.pos;\n", vertex); + if (g_ActiveConfig.backend_info.bSupportsDepthClamp) + out.Write("\tgl_ClipDistance[0] = %s.clipDist;\n", vertex); AssignVSOutputMembers(out, "ps", vertex, uid_data->numTexGens, uid_data->pixel_lighting); } else From 6e2052fae6844da702cbfe0c5ddd4c42f4ad6fbd Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Thu, 11 Aug 2016 21:03:56 +0200 Subject: [PATCH 09/15] OGL: Disable clip distance on when not in a game-like state. --- Source/Core/VideoBackends/OGL/Render.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 5af9407763..0bcf262cac 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -1663,6 +1663,8 @@ void Renderer::ResetAPIState() glDisable(GL_BLEND); if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) glDisable(GL_COLOR_LOGIC_OP); + if (g_ActiveConfig.backend_info.bSupportsDepthClamp) + glDisable(GL_CLIP_DISTANCE0); glDepthMask(GL_FALSE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } @@ -1671,6 +1673,8 @@ void Renderer::RestoreAPIState() { // Gets us back into a more game-like state. glEnable(GL_SCISSOR_TEST); + if (g_ActiveConfig.backend_info.bSupportsDepthClamp) + glEnable(GL_CLIP_DISTANCE0); SetGenerationMode(); BPFunctions::SetScissor(); SetColorMask(); From 94927f360feb1989a7b63ec4d583f45a5767aa3b Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Fri, 12 Aug 2016 15:06:26 +0200 Subject: [PATCH 10/15] VideoCommon: Add a user-defined far clipping plane. --- Source/Core/VideoBackends/OGL/Render.cpp | 7 +++++++ Source/Core/VideoCommon/GeometryShaderGen.cpp | 5 ++++- Source/Core/VideoCommon/ShaderGenCommon.h | 6 ++++-- Source/Core/VideoCommon/VertexShaderGen.cpp | 8 ++++++-- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 0bcf262cac..658cc29b3c 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -734,6 +734,7 @@ Renderer::Renderer() if (g_ActiveConfig.backend_info.bSupportsDepthClamp) { glEnable(GL_CLIP_DISTANCE0); + glEnable(GL_CLIP_DISTANCE1); glEnable(GL_DEPTH_CLAMP); } @@ -1664,7 +1665,10 @@ void Renderer::ResetAPIState() if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) glDisable(GL_COLOR_LOGIC_OP); if (g_ActiveConfig.backend_info.bSupportsDepthClamp) + { glDisable(GL_CLIP_DISTANCE0); + glDisable(GL_CLIP_DISTANCE1); + } glDepthMask(GL_FALSE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } @@ -1674,7 +1678,10 @@ void Renderer::RestoreAPIState() // Gets us back into a more game-like state. glEnable(GL_SCISSOR_TEST); if (g_ActiveConfig.backend_info.bSupportsDepthClamp) + { glEnable(GL_CLIP_DISTANCE0); + glEnable(GL_CLIP_DISTANCE1); + } SetGenerationMode(); BPFunctions::SetScissor(); SetColorMask(); diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp index 03979d0bbe..2630a422fa 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.cpp +++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp @@ -313,7 +313,10 @@ static void EmitVertex(ShaderCode& out, const geometry_shader_uid_data* uid_data { out.Write("\tgl_Position = %s.pos;\n", vertex); if (g_ActiveConfig.backend_info.bSupportsDepthClamp) - out.Write("\tgl_ClipDistance[0] = %s.clipDist;\n", vertex); + { + out.Write("\tgl_ClipDistance[0] = %s.clipDist0;\n", vertex); + out.Write("\tgl_ClipDistance[1] = %s.clipDist1;\n", vertex); + } AssignVSOutputMembers(out, "ps", vertex, uid_data->numTexGens, uid_data->pixel_lighting); } else diff --git a/Source/Core/VideoCommon/ShaderGenCommon.h b/Source/Core/VideoCommon/ShaderGenCommon.h index 434099e85e..97c63ae2ea 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/ShaderGenCommon.h @@ -197,7 +197,8 @@ inline void GenerateVSOutputMembers(T& object, APIType api_type, u32 texgens, texgens + 2); } - DefineOutputMember(object, api_type, qualifier, "float", "clipDist", -1, "SV_ClipDistance"); + DefineOutputMember(object, api_type, qualifier, "float", "clipDist", 0, "SV_ClipDistance", 0); + DefineOutputMember(object, api_type, qualifier, "float", "clipDist", 1, "SV_ClipDistance", 1); } template @@ -219,7 +220,8 @@ inline void AssignVSOutputMembers(T& object, const char* a, const char* b, u32 t object.Write("\t%s.WorldPos = %s.WorldPos;\n", a, b); } - object.Write("\t%s.clipDist = %s.clipDist;\n", a, b); + object.Write("\t%s.clipDist0 = %s.clipDist0;\n", a, b); + object.Write("\t%s.clipDist1 = %s.clipDist1;\n", a, b); } // We use the flag "centroid" to fix some MSAA rendering bugs. With MSAA, the diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 85359ac6ee..5d0f838843 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -403,7 +403,8 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da { // Since we're adjusting z for the depth range before the perspective divide, we have to do our // own clipping. - out.Write("o.clipDist = o.pos.z + o.pos.w;\n"); + out.Write("o.clipDist0 = o.pos.z + o.pos.w;\n"); + out.Write("o.clipDist1 = o.pos.w * -o.pos.z;\n"); // We have to handle the depth range in the vertex shader, because some games will use a depth range beyond // the normal depth range of 0..1. @@ -467,7 +468,10 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da } if (g_ActiveConfig.backend_info.bSupportsDepthClamp) - out.Write("gl_ClipDistance[0] = o.clipDist;\n"); + { + out.Write("gl_ClipDistance[0] = o.clipDist0;\n"); + out.Write("gl_ClipDistance[1] = o.clipDist1;\n"); + } out.Write("gl_Position = o.pos;\n"); } else // D3D From afa251af427514510e3b2bf90255305716a9dac6 Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Fri, 12 Aug 2016 13:42:18 +0200 Subject: [PATCH 11/15] DriverDetails: Add bug for broken gl_ClipDistance on i965. --- Source/Core/VideoBackends/OGL/Render.cpp | 3 ++- Source/Core/VideoCommon/DriverDetails.cpp | 1 + Source/Core/VideoCommon/DriverDetails.h | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 658cc29b3c..77e3356255 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -482,7 +482,8 @@ Renderer::Renderer() GLExtensions::Supports("GL_ARB_shading_language_420pack"); // Clip distance support is useless without a method to clamp the depth range - g_Config.backend_info.bSupportsDepthClamp = GLExtensions::Supports("GL_ARB_depth_clamp"); + g_Config.backend_info.bSupportsDepthClamp = GLExtensions::Supports("GL_ARB_depth_clamp") && + !DriverDetails::HasBug(DriverDetails::BUG_BROKENCLIPDISTANCE); g_ogl_config.bSupportsGLSLCache = GLExtensions::Supports("GL_ARB_get_program_binary"); g_ogl_config.bSupportsGLPinnedMemory = GLExtensions::Supports("GL_AMD_pinned_memory"); diff --git a/Source/Core/VideoCommon/DriverDetails.cpp b/Source/Core/VideoCommon/DriverDetails.cpp index f65f0afa3e..6da311c4e2 100644 --- a/Source/Core/VideoCommon/DriverDetails.cpp +++ b/Source/Core/VideoCommon/DriverDetails.cpp @@ -74,6 +74,7 @@ static BugInfo m_known_bugs[] = { {OS_WINDOWS, VENDOR_INTEL, DRIVER_INTEL, Family::UNKNOWN, BUG_INTELBROKENBUFFERSTORAGE, 101810.3907, 101810.3960, true}, {OS_ALL, VENDOR_ATI, DRIVER_ATI, Family::UNKNOWN, BUG_SLOWGETBUFFERSUBDATA, -1.0, -1.0, true}, + {OS_ALL, VENDOR_MESA, DRIVER_I965, Family::UNKNOWN, BUG_BROKENCLIPDISTANCE, -1.0, -1.0, true}, }; static std::map m_bugs; diff --git a/Source/Core/VideoCommon/DriverDetails.h b/Source/Core/VideoCommon/DriverDetails.h index 9c705694c6..414ef03390 100644 --- a/Source/Core/VideoCommon/DriverDetails.h +++ b/Source/Core/VideoCommon/DriverDetails.h @@ -204,6 +204,14 @@ enum Bug // GPU memory to system memory. Use glMapBufferRange for BBox reads on AMD, and glGetBufferSubData // everywhere else. BUG_SLOWGETBUFFERSUBDATA, + + // Bug: Broken lines in geometry shaders when writing to gl_ClipDistance + // Affected Devices: Mesa i965 + // Started Version: -1 + // Ended Version: -1 + // Mesa hasn't tested geometry shaders on i965 with user-defined clipping planes. + // Causes misrenderings on a large amount of things that draw lines. + BUG_BROKENCLIPDISTANCE, }; // Initializes our internal vendor, device family, and driver version From 959d1879e578c1f29e8c95be445fa349b572191d Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Mon, 15 Aug 2016 13:07:56 +0200 Subject: [PATCH 12/15] VertexShaderGen: Fix far clipping. We should only check whether z > 0, we don't care about w. --- Source/Core/VideoCommon/VertexShaderGen.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 5d0f838843..42bd9da319 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -402,9 +402,9 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da if (g_ActiveConfig.backend_info.bSupportsDepthClamp) { // Since we're adjusting z for the depth range before the perspective divide, we have to do our - // own clipping. - out.Write("o.clipDist0 = o.pos.z + o.pos.w;\n"); - out.Write("o.clipDist1 = o.pos.w * -o.pos.z;\n"); + // own clipping. We want to clip so that -w <= z <= 0. + out.Write("o.clipDist0 = o.pos.z + o.pos.w;\n"); // Near: z < -w + out.Write("o.clipDist1 = -o.pos.z;\n"); // Far: z > 0 // We have to handle the depth range in the vertex shader, because some games will use a depth range beyond // the normal depth range of 0..1. From 8c1c7fc2da65eea1a8244ce196d94313f7fdfb1b Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Fri, 12 Aug 2016 13:55:35 +0200 Subject: [PATCH 13/15] Cosmetics. --- Source/Core/VideoBackends/D3D12/Render.cpp | 5 +---- Source/Core/VideoBackends/OGL/Render.cpp | 8 +++++--- Source/Core/VideoCommon/VertexShaderGen.cpp | 9 +++++---- Source/Core/VideoCommon/VideoConfig.h | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Source/Core/VideoBackends/D3D12/Render.cpp b/Source/Core/VideoBackends/D3D12/Render.cpp index 6e6e6a8f3c..09e7356259 100644 --- a/Source/Core/VideoBackends/D3D12/Render.cpp +++ b/Source/Core/VideoBackends/D3D12/Render.cpp @@ -482,10 +482,7 @@ void Renderer::SetViewport() width = (x + width <= GetTargetWidth()) ? width : (GetTargetWidth() - x); height = (y + height <= GetTargetHeight()) ? height : (GetTargetHeight() - y); - D3D12_VIEWPORT vp = { - x, y, width, height, - D3D12_MIN_DEPTH, - 16777215.0f / 16777216.0f }; + D3D12_VIEWPORT vp = {x, y, width, height, D3D12_MIN_DEPTH, 16777215.0f / 16777216.0f}; D3D::current_command_list->RSSetViewports(1, &vp); } diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 77e3356255..a47f0c1e40 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -482,8 +482,9 @@ Renderer::Renderer() GLExtensions::Supports("GL_ARB_shading_language_420pack"); // Clip distance support is useless without a method to clamp the depth range - g_Config.backend_info.bSupportsDepthClamp = GLExtensions::Supports("GL_ARB_depth_clamp") && - !DriverDetails::HasBug(DriverDetails::BUG_BROKENCLIPDISTANCE); + g_Config.backend_info.bSupportsDepthClamp = + GLExtensions::Supports("GL_ARB_depth_clamp") && + !DriverDetails::HasBug(DriverDetails::BUG_BROKENCLIPDISTANCE); g_ogl_config.bSupportsGLSLCache = GLExtensions::Supports("GL_ARB_get_program_binary"); g_ogl_config.bSupportsGLPinnedMemory = GLExtensions::Supports("GL_AMD_pinned_memory"); @@ -524,7 +525,8 @@ Renderer::Renderer() g_ogl_config.bSupportsGLSLCache = true; g_ogl_config.bSupportsGLSync = true; - // TODO: Implement support for GL_EXT_clip_cull_distance when there is an extension for depth clamping. + // TODO: Implement support for GL_EXT_clip_cull_distance when there is an extension for + // depth clamping. g_Config.backend_info.bSupportsDepthClamp = false; if (strstr(g_ogl_config.glsl_version, "3.0")) diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 42bd9da319..4603e22d7e 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -406,13 +406,14 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da out.Write("o.clipDist0 = o.pos.z + o.pos.w;\n"); // Near: z < -w out.Write("o.clipDist1 = -o.pos.z;\n"); // Far: z > 0 - // We have to handle the depth range in the vertex shader, because some games will use a depth range beyond - // the normal depth range of 0..1. - out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION".w - o.pos.z * " I_PIXELCENTERCORRECTION".z;\n"); + // We have to handle the depth range in the vertex shader, because some games will use a depth + // range beyond the normal depth range of 0..1. + out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION ".w - " + "o.pos.z * " I_PIXELCENTERCORRECTION ".z;\n"); } else { - // User-defined clipping is not supported, thus we rely on the API to handle the depth range for us. + // User-defined clipping is not supported, thus we rely on the API to handle the depth range. // We still need to take care of the reversed depth, so we do that here. out.Write("o.pos.z = -o.pos.z;\n"); } diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index c95706db53..3a1f984e87 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -171,7 +171,7 @@ struct VideoConfig final bool bSupportsPaletteConversion; bool bSupportsClipControl; // Needed by VertexShaderGen, so must stay in VideoCommon bool bSupportsSSAA; - bool bSupportsDepthClamp; // Needed by VertexShaderGen, so must stay in VideoCommon + bool bSupportsDepthClamp; // Needed by VertexShaderGen, so must stay in VideoCommon } backend_info; // Utility From 7078216b61777ff89350d1bdc66c7c032b0b2296 Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Mon, 15 Aug 2016 15:25:50 +0200 Subject: [PATCH 14/15] Improve documentation. --- Source/Core/VideoBackends/D3D/Render.cpp | 5 ++- Source/Core/VideoBackends/D3D12/Render.cpp | 6 ++- Source/Core/VideoBackends/OGL/Render.cpp | 6 ++- Source/Core/VideoCommon/RenderBase.cpp | 6 +++ Source/Core/VideoCommon/RenderBase.h | 2 + Source/Core/VideoCommon/VertexShaderGen.cpp | 40 +++++++++---------- .../Core/VideoCommon/VertexShaderManager.cpp | 5 ++- 7 files changed, 44 insertions(+), 26 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index d1cf55b982..a6301e53a2 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -578,7 +578,10 @@ void Renderer::SetViewport() Wd = (X + Wd <= GetTargetWidth()) ? Wd : (GetTargetWidth() - X); Ht = (Y + Ht <= GetTargetHeight()) ? Ht : (GetTargetHeight() - Y); - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(X, Y, Wd, Ht, D3D11_MIN_DEPTH, 16777215.0f / 16777216.0f); + // We do depth clipping and depth range in the vertex shader instead of relying + // on the graphics API. However we still need to ensure depth values don't exceed + // the maximum value supported by the console GPU. + D3D11_VIEWPORT vp = CD3D11_VIEWPORT(X, Y, Wd, Ht, D3D11_MIN_DEPTH, GX_MAX_DEPTH); D3D::context->RSSetViewports(1, &vp); } diff --git a/Source/Core/VideoBackends/D3D12/Render.cpp b/Source/Core/VideoBackends/D3D12/Render.cpp index 09e7356259..912cd4908d 100644 --- a/Source/Core/VideoBackends/D3D12/Render.cpp +++ b/Source/Core/VideoBackends/D3D12/Render.cpp @@ -482,8 +482,10 @@ void Renderer::SetViewport() width = (x + width <= GetTargetWidth()) ? width : (GetTargetWidth() - x); height = (y + height <= GetTargetHeight()) ? height : (GetTargetHeight() - y); - D3D12_VIEWPORT vp = {x, y, width, height, D3D12_MIN_DEPTH, 16777215.0f / 16777216.0f}; - + // We do depth clipping and depth range in the vertex shader instead of relying + // on the graphics API. However we still need to ensure depth values don't exceed + // the maximum value supported by the console GPU. + D3D12_VIEWPORT vp = {x, y, width, height, D3D12_MIN_DEPTH, GX_MAX_DEPTH}; D3D::current_command_list->RSSetViewports(1, &vp); } diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index a47f0c1e40..78d5d106b7 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -1159,8 +1159,12 @@ void Renderer::SetViewport() glViewport(iceilf(X), iceilf(Y), iceilf(Width), iceilf(Height)); } + // Set the reversed depth range. If we do depth clipping and depth range in the + // vertex shader we only need to ensure depth values don't exceed the maximum + // value supported by the console GPU. If not, we simply clamp the near/far values + // themselves to the maximum value as done above. if (g_ActiveConfig.backend_info.bSupportsDepthClamp) - glDepthRangef(16777215.0f / 16777216.0f, 0.0f); + glDepthRangef(GX_MAX_DEPTH, 0.0f); else glDepthRangef(GLFar, GLNear); } diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index fade0d00b9..3b50cd2313 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -86,6 +86,12 @@ unsigned int Renderer::efb_scale_numeratorY = 1; unsigned int Renderer::efb_scale_denominatorX = 1; unsigned int Renderer::efb_scale_denominatorY = 1; +// The maximum depth that is written to the depth buffer should never exceed this value. +// This is necessary because we use a 2^24 divisor for all our depth values to prevent +// floating-point round-trip errors. However the console GPU doesn't ever write a value +// to the depth buffer that exceeds 2^24 - 1. +const float Renderer::GX_MAX_DEPTH = 16777215.0f / 16777216.0f; + static float AspectToWidescreen(float aspect) { return aspect * ((16.0f / 9.0f) / (4.0f / 3.0f)); diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 81554f5e78..1ae3121637 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -176,6 +176,8 @@ protected: static std::unique_ptr m_post_processor; + static const float GX_MAX_DEPTH; + private: static PEControl::PixelFormat prev_efb_format; static unsigned int efb_scale_numeratorX; diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 4603e22d7e..a42f090716 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -399,43 +399,43 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da out.Write("o.colors_1 = color1;\n"); } + // Write the true depth value. If the game uses depth textures, then the pixel shader will + // override it with the correct values if not then early z culling will improve speed. if (g_ActiveConfig.backend_info.bSupportsDepthClamp) { + // If we can disable the incorrect depth clipping planes using depth clamping, then we can do + // our own depth clipping and calculate the depth range before the perspective divide. + // Since we're adjusting z for the depth range before the perspective divide, we have to do our - // own clipping. We want to clip so that -w <= z <= 0. + // own clipping. We want to clip so that -w <= z <= 0, which matches the console -1..0 range. out.Write("o.clipDist0 = o.pos.z + o.pos.w;\n"); // Near: z < -w out.Write("o.clipDist1 = -o.pos.z;\n"); // Far: z > 0 - // We have to handle the depth range in the vertex shader, because some games will use a depth - // range beyond the normal depth range of 0..1. + // Adjust z for the depth range. We're using an equation which incorperates a depth inversion, + // so we can map the console -1..0 range to the 0..1 range used in the depth buffer. + // We have to handle the depth range in the vertex shader instead of after the perspective + // divide, because some games will use a depth range larger than what is allowed by the + // graphics API. These large depth ranges will still be clipped to the 0..1 range, so these + // games effectively add a depth bias to the values written to the depth buffer. out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION ".w - " "o.pos.z * " I_PIXELCENTERCORRECTION ".z;\n"); } else { - // User-defined clipping is not supported, thus we rely on the API to handle the depth range. - // We still need to take care of the reversed depth, so we do that here. + // If we can't disable the incorrect depth clipping planes, then we need to rely on the + // graphics API to handle the depth range after the perspective divide. This can result in + // inaccurate depth values due to the missing depth bias, but that can be least corrected by + // overriding depth values in the pixel shader. We still need to take care of the reversed depth + // though, so we do that here. out.Write("o.pos.z = -o.pos.z;\n"); } - // write the true depth value, if the game uses depth textures pixel shaders will override with - // the correct values - // if not early z culling will improve speed if (!g_ActiveConfig.backend_info.bSupportsClipControl) { - // this results in a scale from -1..0 to -1..1 after perspective - // divide + // If the graphics API doesn't support a depth range of 0..1, then we need to map z to + // the -1..1 range. Unfortunately we have to use a substraction, which is a lossy floating-point + // operation that can introduce a round-trip error. out.Write("o.pos.z = o.pos.z * 2.0 - o.pos.w;\n"); - - // the next steps of the OGL pipeline are: - // (x_c,y_c,z_c,w_c) = o.pos //switch to OGL spec terminology - // clipping to -w_c <= (x_c,y_c,z_c) <= w_c - // (x_d,y_d,z_d) = (x_c,y_c,z_c)/w_c//perspective divide - // z_w = (f-n)/2*z_d + (n+f)/2 - // z_w now contains the value to go to the 0..1 depth buffer - - // trying to get the correct semantic while not using glDepthRange - // seems to get rather complicated } // The console GPU places the pixel center at 7/12 in screen space unless diff --git a/Source/Core/VideoCommon/VertexShaderManager.cpp b/Source/Core/VideoCommon/VertexShaderManager.cpp index dabc7870fd..9b1c3437fe 100644 --- a/Source/Core/VideoCommon/VertexShaderManager.cpp +++ b/Source/Core/VideoCommon/VertexShaderManager.cpp @@ -389,8 +389,9 @@ void VertexShaderManager::SetConstants() // The depth range is handled in the vertex shader. We need to reverse // the far value to get a reversed depth range mapping. This is necessary - // because we have the most precision at the near plane, while the console - // has the most percision at the far plane. + // because the standard depth range equation pushes all depth values towards + // the back of the depth buffer where conventionally depth buffers have the + // least precision. constants.pixelcentercorrection[2] = xfmem.viewport.zRange / 16777215.0f; constants.pixelcentercorrection[3] = 1.0f - xfmem.viewport.farZ / 16777215.0f; From e86d7cbc999223ca113af7b4c0aac6850c1854fe Mon Sep 17 00:00:00 2001 From: Jules Blok Date: Wed, 17 Aug 2016 20:12:44 +0200 Subject: [PATCH 15/15] OGL: Workaround gl_ClipDistance bug on Mesa i965. --- Source/Core/VideoBackends/OGL/Render.cpp | 4 +--- Source/Core/VideoCommon/DriverDetails.h | 7 ++++--- Source/Core/VideoCommon/GeometryShaderGen.cpp | 10 ++++++++++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 78d5d106b7..d637c308ca 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -482,9 +482,7 @@ Renderer::Renderer() GLExtensions::Supports("GL_ARB_shading_language_420pack"); // Clip distance support is useless without a method to clamp the depth range - g_Config.backend_info.bSupportsDepthClamp = - GLExtensions::Supports("GL_ARB_depth_clamp") && - !DriverDetails::HasBug(DriverDetails::BUG_BROKENCLIPDISTANCE); + g_Config.backend_info.bSupportsDepthClamp = GLExtensions::Supports("GL_ARB_depth_clamp"); g_ogl_config.bSupportsGLSLCache = GLExtensions::Supports("GL_ARB_get_program_binary"); g_ogl_config.bSupportsGLPinnedMemory = GLExtensions::Supports("GL_AMD_pinned_memory"); diff --git a/Source/Core/VideoCommon/DriverDetails.h b/Source/Core/VideoCommon/DriverDetails.h index 414ef03390..b6dcf87963 100644 --- a/Source/Core/VideoCommon/DriverDetails.h +++ b/Source/Core/VideoCommon/DriverDetails.h @@ -205,12 +205,13 @@ enum Bug // everywhere else. BUG_SLOWGETBUFFERSUBDATA, - // Bug: Broken lines in geometry shaders when writing to gl_ClipDistance + // Bug: Broken lines in geometry shaders when writing to gl_ClipDistance in the vertex shader // Affected Devices: Mesa i965 // Started Version: -1 // Ended Version: -1 - // Mesa hasn't tested geometry shaders on i965 with user-defined clipping planes. - // Causes misrenderings on a large amount of things that draw lines. + // Writing to gl_ClipDistance in both the vertex shader and the geometry shader will break + // the geometry shader. Current workaround is to make sure the geometry shader always consumes + // the gl_ClipDistance inputs from the vertex shader. BUG_BROKENCLIPDISTANCE, }; diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp index 2630a422fa..83b30943bc 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.cpp +++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp @@ -7,6 +7,7 @@ #include "Common/CommonTypes.h" #include "VideoCommon/BPMemory.h" +#include "VideoCommon/DriverDetails.h" #include "VideoCommon/GeometryShaderGen.h" #include "VideoCommon/LightingShaderGen.h" #include "VideoCommon/VideoCommon.h" @@ -211,6 +212,15 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid { out.Write("\tVS_OUTPUT f;\n"); AssignVSOutputMembers(out, "f", "vs[i]", uid_data->numTexGens, uid_data->pixel_lighting); + + if (g_ActiveConfig.backend_info.bSupportsDepthClamp && + DriverDetails::HasBug(DriverDetails::BUG_BROKENCLIPDISTANCE)) + { + // On certain GPUs we have to consume the clip distance from the vertex shader + // or else the other vertex shader outputs will get corrupted. + out.Write("\tf.clipDist0 = gl_in[i].gl_ClipDistance[0];\n"); + out.Write("\tf.clipDist1 = gl_in[i].gl_ClipDistance[1];\n"); + } } else {