From a9d08a31a682484210aae9514b54b0a67f7a44d2 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Sat, 18 Feb 2017 18:22:41 -0600 Subject: [PATCH] Add configurable toggle that rounds vertices to the nearest pixel when w=1. This fixes some games at higher IRs. --- Source/Core/DolphinWX/VideoConfigDiag.cpp | 8 ++++++ Source/Core/DolphinWX/VideoConfigDiag.h | 12 +++++++++ Source/Core/VideoCommon/ConstantManager.h | 1 + Source/Core/VideoCommon/ShaderGenCommon.h | 4 ++- Source/Core/VideoCommon/VertexShaderGen.cpp | 25 +++++++++++++++++++ Source/Core/VideoCommon/VertexShaderGen.h | 3 ++- .../Core/VideoCommon/VertexShaderManager.cpp | 15 +++++++++-- Source/Core/VideoCommon/VideoConfig.cpp | 3 +++ Source/Core/VideoCommon/VideoConfig.h | 1 + 9 files changed, 68 insertions(+), 4 deletions(-) diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp index 49a004b73c..a69a366802 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp @@ -284,6 +284,10 @@ static wxString true_color_desc = wxTRANSLATE("Forces the game to render the RGB color channels in 24-bit, thereby increasing " "quality by reducing color banding.\nIt has no impact on performance and causes " "few graphical issues.\n\n\nIf unsure, leave this checked."); +static wxString vertex_rounding_desc = + wxTRANSLATE("Round 2D vertices to whole pixels. Fixes some " + "games at higher internal resolutions. This setting is disabled and turned off " + "at 1x IR.\n\nIf unsure, leave this unchecked."); static wxString gpu_texture_decoding_desc = wxTRANSLATE("Enables texture decoding using the GPU instead of the CPU. This may result in " "performance gains in some scenarios, or systems where the CPU is the bottleneck." @@ -818,6 +822,10 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title) szr_other->Add(CreateCheckBox(page_hacks, _("Disable Bounding Box"), wxGetTranslation(disable_bbox_desc), vconfig.bBBoxEnable, true)); + vertex_rounding_checkbox = + CreateCheckBox(page_hacks, _("Vertex Rounding"), wxGetTranslation(vertex_rounding_desc), + vconfig.bVertexRounding); + szr_other->Add(vertex_rounding_checkbox); wxStaticBoxSizer* const group_other = new wxStaticBoxSizer(wxVERTICAL, page_hacks, _("Other")); diff --git a/Source/Core/DolphinWX/VideoConfigDiag.h b/Source/Core/DolphinWX/VideoConfigDiag.h index e02591956c..a3ec361fce 100644 --- a/Source/Core/DolphinWX/VideoConfigDiag.h +++ b/Source/Core/DolphinWX/VideoConfigDiag.h @@ -239,6 +239,17 @@ protected: progressive_scan_checkbox->Disable(); render_to_main_checkbox->Disable(); } + + // Don't enable 'vertex rounding' at native + if (vconfig.iEFBScale == SCALE_1X) + { + vertex_rounding_checkbox->Enable(false); + } + else + { + vertex_rounding_checkbox->Enable(true); + } + ev.Skip(); } @@ -286,6 +297,7 @@ protected: SettingCheckBox* cache_hires_textures; wxCheckBox* progressive_scan_checkbox; + wxCheckBox* vertex_rounding_checkbox; wxChoice* choice_ppshader; diff --git a/Source/Core/VideoCommon/ConstantManager.h b/Source/Core/VideoCommon/ConstantManager.h index cb12a1df07..c3b7004e69 100644 --- a/Source/Core/VideoCommon/ConstantManager.h +++ b/Source/Core/VideoCommon/ConstantManager.h @@ -45,6 +45,7 @@ struct VertexShaderConstants float4 normalmatrices[32]; float4 posttransformmatrices[64]; float4 pixelcentercorrection; + float4 viewport; }; struct GeometryShaderConstants diff --git a/Source/Core/VideoCommon/ShaderGenCommon.h b/Source/Core/VideoCommon/ShaderGenCommon.h index 267887a814..f70d6288e6 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/ShaderGenCommon.h @@ -275,6 +275,7 @@ inline const char* GetInterpolationQualifier(bool msaa, bool ssaa, #define I_NORMALMATRICES "cnmtx" #define I_POSTTRANSFORMMATRICES "cpostmtx" #define I_PIXELCENTERCORRECTION "cpixelcenter" +#define I_VIEWPORT_SIZE "cviewport" #define I_STEREOPARAMS "cstereo" #define I_LINEPTPARAMS "clinept" @@ -288,4 +289,5 @@ static const char s_shader_uniforms[] = "\tfloat4 " I_POSNORMALMATRIX "[6];\n" "\tfloat4 " I_TRANSFORMMATRICES "[64];\n" "\tfloat4 " I_NORMALMATRICES "[32];\n" "\tfloat4 " I_POSTTRANSFORMMATRICES "[64];\n" - "\tfloat4 " I_PIXELCENTERCORRECTION ";\n"; + "\tfloat4 " I_PIXELCENTERCORRECTION ";\n" + "\tfloat2 " I_VIEWPORT_SIZE ";\n"; diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 7fc31e1763..b590303679 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -28,6 +28,8 @@ VertexShaderUid GetVertexShaderUid() uid_data->numTexGens = xfmem.numTexGen.numTexGens; uid_data->components = VertexLoaderManager::g_current_components; uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting; + uid_data->vertex_rounding = + g_ActiveConfig.bVertexRounding && g_ActiveConfig.iEFBScale != SCALE_1X; uid_data->msaa = g_ActiveConfig.iMultisamples > 1; uid_data->ssaa = g_ActiveConfig.iMultisamples > 1 && g_ActiveConfig.bSSAA; uid_data->numColorChans = xfmem.numChan.numColorChans; @@ -465,6 +467,29 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da // get rasterized correctly. out.Write("o.pos.xy = o.pos.xy - o.pos.w * " I_PIXELCENTERCORRECTION ".xy;\n"); + if (uid_data->vertex_rounding) + { + // By now our position is in clip space + // however, higher resolutions than the Wii outputs + // cause an additional pixel offset + // due to a higher pixel density + // we need to correct this by converting our + // clip-space position into the Wii's screen-space + // acquire the right pixel and then convert it back + out.Write("if (o.pos.w == 1.0f)\n"); + out.Write("{\n"); + + out.Write("\tfloat ss_pixel_x = ((o.pos.x + 1.0f) * (" I_VIEWPORT_SIZE ".x * 0.5f));\n"); + out.Write("\tfloat ss_pixel_y = ((o.pos.y + 1.0f) * (" I_VIEWPORT_SIZE ".y * 0.5f));\n"); + + out.Write("\tss_pixel_x = round(ss_pixel_x);\n"); + out.Write("\tss_pixel_y = round(ss_pixel_y);\n"); + + out.Write("\to.pos.x = ((ss_pixel_x / (" I_VIEWPORT_SIZE ".x * 0.5f)) - 1.0f);\n"); + out.Write("\to.pos.y = ((ss_pixel_y / (" I_VIEWPORT_SIZE ".y * 0.5f)) - 1.0f);\n"); + out.Write("}\n"); + } + if (api_type == APIType::OpenGL || api_type == APIType::Vulkan) { if (g_ActiveConfig.backend_info.bSupportsGeometryShaders || api_type == APIType::Vulkan) diff --git a/Source/Core/VideoCommon/VertexShaderGen.h b/Source/Core/VideoCommon/VertexShaderGen.h index 4b9e9d1d39..0fa8e88815 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.h +++ b/Source/Core/VideoCommon/VertexShaderGen.h @@ -43,7 +43,8 @@ struct vertex_shader_uid_data u32 texMtxInfo_n_projection : 16; // Stored separately to guarantee that the texMtxInfo struct is // 8 bits wide u32 ssaa : 1; - u32 pad : 15; + u32 vertex_rounding : 1; + u32 pad : 14; struct { diff --git a/Source/Core/VideoCommon/VertexShaderManager.cpp b/Source/Core/VideoCommon/VertexShaderManager.cpp index 36bace7426..76a91e0f05 100644 --- a/Source/Core/VideoCommon/VertexShaderManager.cpp +++ b/Source/Core/VideoCommon/VertexShaderManager.cpp @@ -382,8 +382,16 @@ void VertexShaderManager::SetConstants() // NOTE: If we ever emulate antialiasing, the sample locations set by // BP registers 0x01-0x04 need to be considered here. const float pixel_center_correction = 7.0f / 12.0f - 0.5f; - const float pixel_size_x = 2.f / g_renderer->EFBToScaledXf(2.f * xfmem.viewport.wd); - const float pixel_size_y = 2.f / g_renderer->EFBToScaledXf(2.f * xfmem.viewport.ht); + const bool bUseVertexRounding = + g_ActiveConfig.bVertexRounding && g_ActiveConfig.iEFBScale != SCALE_1X; + const float viewport_width = bUseVertexRounding ? + (2.f * xfmem.viewport.wd) : + g_renderer->EFBToScaledXf(2.f * xfmem.viewport.wd); + const float viewport_height = bUseVertexRounding ? + (2.f * xfmem.viewport.ht) : + g_renderer->EFBToScaledXf(2.f * xfmem.viewport.ht); + const float pixel_size_x = 2.f / viewport_width; + const float pixel_size_y = 2.f / viewport_height; constants.pixelcentercorrection[0] = pixel_center_correction * pixel_size_x; constants.pixelcentercorrection[1] = pixel_center_correction * pixel_size_y; @@ -391,6 +399,9 @@ void VertexShaderManager::SetConstants() constants.pixelcentercorrection[2] = 1.0f; constants.pixelcentercorrection[3] = 0.0f; + constants.viewport[0] = (2.f * xfmem.viewport.wd); + constants.viewport[1] = (2.f * xfmem.viewport.ht); + if (g_renderer->UseVertexDepthRange()) { // Oversized depth ranges are handled in the vertex shader. We need to reverse diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp index 08b814fd28..604bdb4bdd 100644 --- a/Source/Core/VideoCommon/VideoConfig.cpp +++ b/Source/Core/VideoCommon/VideoConfig.cpp @@ -125,6 +125,7 @@ void VideoConfig::Load(const std::string& ini_file) hacks->Get("EFBToTextureEnable", &bSkipEFBCopyToRam, true); hacks->Get("EFBScaledCopy", &bCopyEFBScaled, true); hacks->Get("EFBEmulateFormatChanges", &bEFBEmulateFormatChanges, false); + hacks->Get("VertexRounding", &bVertexRounding, false); // hacks which are disabled by default iPhackvalue[0] = 0; @@ -228,6 +229,7 @@ void VideoConfig::GameIniLoad() CHECK_SETTING("Video_Hacks", "EFBToTextureEnable", bSkipEFBCopyToRam); CHECK_SETTING("Video_Hacks", "EFBScaledCopy", bCopyEFBScaled); CHECK_SETTING("Video_Hacks", "EFBEmulateFormatChanges", bEFBEmulateFormatChanges); + CHECK_SETTING("Video_Hacks", "VertexRounding", bVertexRounding); CHECK_SETTING("Video", "ProjectionHack", iPhackvalue[0]); CHECK_SETTING("Video", "PH_SZNear", iPhackvalue[1]); @@ -350,6 +352,7 @@ void VideoConfig::Save(const std::string& ini_file) hacks->Set("EFBToTextureEnable", bSkipEFBCopyToRam); hacks->Set("EFBScaledCopy", bCopyEFBScaled); hacks->Set("EFBEmulateFormatChanges", bEFBEmulateFormatChanges); + hacks->Set("VertexRounding", bVertexRounding); iniFile.Save(ini_file); } diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index c70cf104c8..c628722a3a 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -127,6 +127,7 @@ struct VideoConfig final float fAspectRatioHackW, fAspectRatioHackH; bool bEnablePixelLighting; bool bFastDepthCalc; + bool bVertexRounding; int iLog; // CONF_ bits int iSaveTargetId; // TODO: Should be dropped