Merge pull request #2986 from degasus/master

VideoBackends: Reimplement SSAA, now for D3D + OGL
This commit is contained in:
Ryan Houdek 2015-09-06 13:31:49 -05:00
commit d2ac382a14
12 changed files with 111 additions and 91 deletions

View File

@ -418,15 +418,8 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con
szr_enh->Add(CreateCheckBox(page_enh, _("Widescreen Hack"), wxGetTranslation(ws_hack_desc), vconfig.bWidescreenHack)); szr_enh->Add(CreateCheckBox(page_enh, _("Widescreen Hack"), wxGetTranslation(ws_hack_desc), vconfig.bWidescreenHack));
szr_enh->Add(CreateCheckBox(page_enh, _("Disable Fog"), wxGetTranslation(disable_fog_desc), vconfig.bDisableFog)); szr_enh->Add(CreateCheckBox(page_enh, _("Disable Fog"), wxGetTranslation(disable_fog_desc), vconfig.bDisableFog));
if (vconfig.backend_info.bSupportsSSAA)
{
ssaa_checkbox = CreateCheckBox(page_enh, _("SSAA"), wxGetTranslation(aa_desc), vconfig.bSSAA); ssaa_checkbox = CreateCheckBox(page_enh, _("SSAA"), wxGetTranslation(aa_desc), vconfig.bSSAA);
szr_enh->Add(ssaa_checkbox); szr_enh->Add(ssaa_checkbox);
}
else
{
ssaa_checkbox = nullptr;
}
wxStaticBoxSizer* const group_enh = new wxStaticBoxSizer(wxVERTICAL, page_enh, _("Enhancements")); wxStaticBoxSizer* const group_enh = new wxStaticBoxSizer(wxVERTICAL, page_enh, _("Enhancements"));
group_enh->Add(szr_enh, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); group_enh->Add(szr_enh, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);

View File

@ -193,8 +193,8 @@ protected:
// Anti-aliasing // Anti-aliasing
choice_aamode->Enable(vconfig.backend_info.AAModes.size() > 1); choice_aamode->Enable(vconfig.backend_info.AAModes.size() > 1);
text_aamode->Enable(vconfig.backend_info.AAModes.size() > 1); text_aamode->Enable(vconfig.backend_info.AAModes.size() > 1);
if (vconfig.backend_info.bSupportsSSAA && ssaa_checkbox) ssaa_checkbox->Enable(vconfig.backend_info.bSupportsSSAA && vconfig.iMultisampleMode > 0);
ssaa_checkbox->Enable(vconfig.iMultisampleMode > 0);
// XFB // XFB
virtual_xfb->Enable(vconfig.bUseXFB); virtual_xfb->Enable(vconfig.bUseXFB);

View File

@ -84,7 +84,6 @@ void InitBackendInfo()
g_Config.backend_info.bSupportsPostProcessing = false; g_Config.backend_info.bSupportsPostProcessing = false;
g_Config.backend_info.bSupportsPaletteConversion = true; g_Config.backend_info.bSupportsPaletteConversion = true;
g_Config.backend_info.bSupportsClipControl = true; g_Config.backend_info.bSupportsClipControl = true;
g_Config.backend_info.bSupportsSSAA = false;
IDXGIFactory* factory; IDXGIFactory* factory;
IDXGIAdapter* ad; IDXGIAdapter* ad;
@ -129,6 +128,9 @@ void InitBackendInfo()
// Requires the instance attribute (only available in shader model 5) // Requires the instance attribute (only available in shader model 5)
g_Config.backend_info.bSupportsGSInstancing = shader_model_5_supported; g_Config.backend_info.bSupportsGSInstancing = shader_model_5_supported;
// Sample shading requires shader model 5
g_Config.backend_info.bSupportsSSAA = shader_model_5_supported;
} }
g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description)); g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description));
ad->Release(); ad->Release();

View File

@ -94,9 +94,24 @@ bool cInterfaceGLX::Create(void *window_handle)
// Get an appropriate visual // Get an appropriate visual
XVisualInfo* vi = glXGetVisualFromFBConfig(dpy, fbconfig); XVisualInfo* vi = glXGetVisualFromFBConfig(dpy, fbconfig);
s_glxError = false;
XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler);
// Create a GLX context. // Create a GLX context.
// We try to get a 3.3 core profile, else we try it with anything we get. // We try to get a 4.0 core profile, else we try 3.3, else try it with anything we get.
int context_attribs[] = int context_attribs[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
None
};
ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs);
XSync(dpy, False);
if (!ctx || s_glxError)
{
int context_attribs_33[] =
{ {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 3,
@ -105,9 +120,10 @@ bool cInterfaceGLX::Create(void *window_handle)
None None
}; };
s_glxError = false; s_glxError = false;
XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler); ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs_33);
ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs);
XSync(dpy, False); XSync(dpy, False);
}
if (!ctx || s_glxError) if (!ctx || s_glxError)
{ {
int context_attribs_legacy[] = int context_attribs_legacy[] =
@ -119,12 +135,13 @@ bool cInterfaceGLX::Create(void *window_handle)
s_glxError = false; s_glxError = false;
ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs_legacy); ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, context_attribs_legacy);
XSync(dpy, False); XSync(dpy, False);
}
if (!ctx || s_glxError) if (!ctx || s_glxError)
{ {
ERROR_LOG(VIDEO, "Unable to create GL context."); ERROR_LOG(VIDEO, "Unable to create GL context.");
return false; return false;
} }
}
XSetErrorHandler(oldHandler); XSetErrorHandler(oldHandler);
XWindow.Initialize(dpy); XWindow.Initialize(dpy);

View File

@ -58,6 +58,10 @@ static std::string GetGLSLVersionString()
return "#version 140"; return "#version 140";
case GLSL_150: case GLSL_150:
return "#version 150"; return "#version 150";
case GLSL_330:
return "#version 330";
case GLSL_400:
return "#version 400";
default: default:
// Shouldn't ever hit this // Shouldn't ever hit this
return "#version ERROR"; return "#version ERROR";
@ -552,7 +556,6 @@ void ProgramShaderCache::CreateHeader()
"%s\n" // early-z "%s\n" // early-z
"%s\n" // 420pack "%s\n" // 420pack
"%s\n" // msaa "%s\n" // msaa
"%s\n" // sample shading
"%s\n" // Sampler binding "%s\n" // Sampler binding
"%s\n" // storage buffer "%s\n" // storage buffer
"%s\n" // shader5 "%s\n" // shader5
@ -589,10 +592,9 @@ void ProgramShaderCache::CreateHeader()
, !is_glsles && g_ActiveConfig.backend_info.bSupportsEarlyZ ? "#extension GL_ARB_shader_image_load_store : enable" : "" , !is_glsles && g_ActiveConfig.backend_info.bSupportsEarlyZ ? "#extension GL_ARB_shader_image_load_store : enable" : ""
, (g_ActiveConfig.backend_info.bSupportsBindingLayout && v < GLSLES_310) ? "#extension GL_ARB_shading_language_420pack : enable" : "" , (g_ActiveConfig.backend_info.bSupportsBindingLayout && v < GLSLES_310) ? "#extension GL_ARB_shading_language_420pack : enable" : ""
, (g_ogl_config.bSupportsMSAA && v < GLSL_150) ? "#extension GL_ARB_texture_multisample : enable" : "" , (g_ogl_config.bSupportsMSAA && v < GLSL_150) ? "#extension GL_ARB_texture_multisample : enable" : ""
, (v < GLSLES_300 && g_ActiveConfig.backend_info.bSupportsSSAA) ? "#extension GL_ARB_sample_shading : enable" : ""
, g_ActiveConfig.backend_info.bSupportsBindingLayout ? "#define SAMPLER_BINDING(x) layout(binding = x)" : "#define SAMPLER_BINDING(x)" , g_ActiveConfig.backend_info.bSupportsBindingLayout ? "#define SAMPLER_BINDING(x) layout(binding = x)" : "#define SAMPLER_BINDING(x)"
, g_ActiveConfig.backend_info.bSupportsBBox ? "#extension GL_ARB_shader_storage_buffer_object : enable" : "" , g_ActiveConfig.backend_info.bSupportsBBox ? "#extension GL_ARB_shader_storage_buffer_object : enable" : ""
, !is_glsles && g_ActiveConfig.backend_info.bSupportsGSInstancing ? "#extension GL_ARB_gpu_shader5 : enable" : "" , v < GLSL_400 && g_ActiveConfig.backend_info.bSupportsGSInstancing ? "#extension GL_ARB_gpu_shader5 : enable" : ""
, SupportedESPointSize.c_str() , SupportedESPointSize.c_str()
, g_ogl_config.bSupportsAEP ? "#extension GL_ANDROID_extension_pack_es31a : enable" : "" , g_ogl_config.bSupportsAEP ? "#extension GL_ANDROID_extension_pack_es31a : enable" : ""
, v < GLSL_140 && g_ActiveConfig.backend_info.bSupportsPaletteConversion ? "#extension GL_ARB_texture_buffer_object : enable" : "" , v < GLSL_140 && g_ActiveConfig.backend_info.bSupportsPaletteConversion ? "#extension GL_ARB_texture_buffer_object : enable" : ""

View File

@ -88,7 +88,6 @@ static RasterFont* s_pfont = nullptr;
// 1 for no MSAA. Use s_MSAASamples > 1 to check for MSAA. // 1 for no MSAA. Use s_MSAASamples > 1 to check for MSAA.
static int s_MSAASamples = 1; static int s_MSAASamples = 1;
static int s_last_multisample_mode = 0; static int s_last_multisample_mode = 0;
static bool s_last_ssaa_mode = false;
static bool s_last_stereo_mode = false; static bool s_last_stereo_mode = false;
static bool s_last_xfb_mode = false; static bool s_last_xfb_mode = false;
@ -136,27 +135,6 @@ static int GetNumMSAASamples(int MSAAMode)
return g_ogl_config.max_samples; return g_ogl_config.max_samples;
} }
static void ApplySSAASettings()
{
if (g_ActiveConfig.bSSAA)
{
if (g_ActiveConfig.backend_info.bSupportsSSAA)
{
glEnable(GL_SAMPLE_SHADING_ARB);
glMinSampleShading(1.0f);
}
else
{
// TODO: move this to InitBackendInfo
OSD::AddMessage("SSAA Anti Aliasing isn't supported by your GPU.", 10000);
}
}
else if (g_ActiveConfig.backend_info.bSupportsSSAA)
{
glDisable(GL_SAMPLE_SHADING_ARB);
}
}
static void GLAPIENTRY ErrorCallback( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, const void* userParam) static void GLAPIENTRY ErrorCallback( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char* message, const void* userParam)
{ {
const char *s_source; const char *s_source;
@ -483,8 +461,6 @@ Renderer::Renderer()
g_ogl_config.bSupportsGLBufferStorage = GLExtensions::Supports("GL_ARB_buffer_storage") || g_ogl_config.bSupportsGLBufferStorage = GLExtensions::Supports("GL_ARB_buffer_storage") ||
GLExtensions::Supports("GL_EXT_buffer_storage"); GLExtensions::Supports("GL_EXT_buffer_storage");
g_ogl_config.bSupportsMSAA = GLExtensions::Supports("GL_ARB_texture_multisample"); g_ogl_config.bSupportsMSAA = GLExtensions::Supports("GL_ARB_texture_multisample");
g_ActiveConfig.backend_info.bSupportsSSAA = GLExtensions::Supports("GL_ARB_sample_shading") ||
GLExtensions::Supports("GL_OES_sample_shading");
g_ogl_config.bSupportOGL31 = GLExtensions::Version() >= 310; g_ogl_config.bSupportOGL31 = GLExtensions::Version() >= 310;
g_ogl_config.bSupportViewportFloat = GLExtensions::Supports("GL_ARB_viewport_array"); g_ogl_config.bSupportViewportFloat = GLExtensions::Supports("GL_ARB_viewport_array");
g_ogl_config.bSupportsDebug = GLExtensions::Supports("GL_KHR_debug") || g_ogl_config.bSupportsDebug = GLExtensions::Supports("GL_KHR_debug") ||
@ -514,6 +490,7 @@ Renderer::Renderer()
g_Config.backend_info.bSupportsEarlyZ = true; g_Config.backend_info.bSupportsEarlyZ = true;
g_Config.backend_info.bSupportsGeometryShaders = g_ogl_config.bSupportsAEP; g_Config.backend_info.bSupportsGeometryShaders = g_ogl_config.bSupportsAEP;
g_Config.backend_info.bSupportsGSInstancing = g_Config.backend_info.bSupportsGeometryShaders && g_ogl_config.SupportedESPointSize > 0; g_Config.backend_info.bSupportsGSInstancing = g_Config.backend_info.bSupportsGeometryShaders && g_ogl_config.SupportedESPointSize > 0;
g_Config.backend_info.bSupportsSSAA = g_ogl_config.bSupportsAEP;
g_ogl_config.bSupportsMSAA = true; g_ogl_config.bSupportsMSAA = true;
g_ogl_config.bSupports2DTextureStorage = true; g_ogl_config.bSupports2DTextureStorage = true;
if (g_ActiveConfig.iStereoMode > 0 && g_ActiveConfig.iMultisampleMode > 1 && !g_ogl_config.bSupports3DTextureStorage) if (g_ActiveConfig.iStereoMode > 0 && g_ActiveConfig.iMultisampleMode > 1 && !g_ogl_config.bSupports3DTextureStorage)
@ -555,16 +532,28 @@ Renderer::Renderer()
g_ogl_config.eSupportedGLSLVersion = GLSL_130; g_ogl_config.eSupportedGLSLVersion = GLSL_130;
g_Config.backend_info.bSupportsEarlyZ = false; // layout keyword is only supported on glsl150+ g_Config.backend_info.bSupportsEarlyZ = false; // layout keyword is only supported on glsl150+
g_Config.backend_info.bSupportsGeometryShaders = false; // geometry shaders are only supported on glsl150+ g_Config.backend_info.bSupportsGeometryShaders = false; // geometry shaders are only supported on glsl150+
g_Config.backend_info.bSupportsSSAA = false; // sample shading is only supported on glsl400+
} }
else if (strstr(g_ogl_config.glsl_version, "1.40")) else if (strstr(g_ogl_config.glsl_version, "1.40"))
{ {
g_ogl_config.eSupportedGLSLVersion = GLSL_140; g_ogl_config.eSupportedGLSLVersion = GLSL_140;
g_Config.backend_info.bSupportsEarlyZ = false; // layout keyword is only supported on glsl150+ g_Config.backend_info.bSupportsEarlyZ = false; // layout keyword is only supported on glsl150+
g_Config.backend_info.bSupportsGeometryShaders = false; // geometry shaders are only supported on glsl150+ g_Config.backend_info.bSupportsGeometryShaders = false; // geometry shaders are only supported on glsl150+
g_Config.backend_info.bSupportsSSAA = false; // sample shading is only supported on glsl400+
}
else if (strstr(g_ogl_config.glsl_version, "1.50"))
{
g_ogl_config.eSupportedGLSLVersion = GLSL_150;
g_Config.backend_info.bSupportsSSAA = false; // sample shading is only supported on glsl400+
}
else if (strstr(g_ogl_config.glsl_version, "3.30"))
{
g_ogl_config.eSupportedGLSLVersion = GLSL_330;
g_Config.backend_info.bSupportsSSAA = false; // sample shading is only supported on glsl400+
} }
else else
{ {
g_ogl_config.eSupportedGLSLVersion = GLSL_150; g_ogl_config.eSupportedGLSLVersion = GLSL_400;
} }
// Desktop OpenGL can't have the Android Extension Pack // Desktop OpenGL can't have the Android Extension Pack
@ -638,9 +627,7 @@ Renderer::Renderer()
); );
s_last_multisample_mode = g_ActiveConfig.iMultisampleMode; s_last_multisample_mode = g_ActiveConfig.iMultisampleMode;
s_last_ssaa_mode = g_ActiveConfig.bSSAA;
s_MSAASamples = GetNumMSAASamples(s_last_multisample_mode); s_MSAASamples = GetNumMSAASamples(s_last_multisample_mode);
ApplySSAASettings();
s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0;
s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; s_last_xfb_mode = g_ActiveConfig.bUseRealXFB;
@ -1691,21 +1678,19 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co
{ {
TargetSizeChanged = true; TargetSizeChanged = true;
} }
if (TargetSizeChanged || xfbchanged || WindowResized || s_last_ssaa_mode != g_ActiveConfig.bSSAA || if (TargetSizeChanged || xfbchanged || WindowResized ||
(s_last_multisample_mode != g_ActiveConfig.iMultisampleMode) || (s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0))) (s_last_multisample_mode != g_ActiveConfig.iMultisampleMode) || (s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0)))
{ {
s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; s_last_xfb_mode = g_ActiveConfig.bUseRealXFB;
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
if (TargetSizeChanged || s_last_ssaa_mode != g_ActiveConfig.bSSAA || if (TargetSizeChanged ||
s_last_multisample_mode != g_ActiveConfig.iMultisampleMode || s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0)) s_last_multisample_mode != g_ActiveConfig.iMultisampleMode || s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0))
{ {
s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0;
s_last_multisample_mode = g_ActiveConfig.iMultisampleMode; s_last_multisample_mode = g_ActiveConfig.iMultisampleMode;
s_last_ssaa_mode = g_ActiveConfig.bSSAA;
s_MSAASamples = GetNumMSAASamples(s_last_multisample_mode); s_MSAASamples = GetNumMSAASamples(s_last_multisample_mode);
ApplySSAASettings();
delete g_framebuffer_manager; delete g_framebuffer_manager;
g_framebuffer_manager = new FramebufferManager(s_target_width, s_target_height, g_framebuffer_manager = new FramebufferManager(s_target_width, s_target_height,

View File

@ -16,7 +16,9 @@ enum GLSL_VERSION
{ {
GLSL_130, GLSL_130,
GLSL_140, GLSL_140,
GLSL_150, // and above GLSL_150,
GLSL_330,
GLSL_400, // and above
GLSLES_300, // GLES 3.0 GLSLES_300, // GLES 3.0
GLSLES_310, // GLES 3.1 GLSLES_310, // GLES 3.1
GLSLES_320, // GLES 3.2 GLSLES_320, // GLES 3.2

View File

@ -94,11 +94,11 @@ static inline void GenerateGeometryShader(T& out, u32 primitive_type, API_TYPE A
out.Write("#define InstanceID gl_InvocationID\n"); out.Write("#define InstanceID gl_InvocationID\n");
out.Write("in VertexData {\n"); out.Write("in VertexData {\n");
GenerateVSOutputMembers<T>(out, ApiType, g_ActiveConfig.backend_info.bSupportsBindingLayout ? "centroid" : "centroid in"); GenerateVSOutputMembers<T>(out, ApiType, GetInterpolationQualifier(ApiType, true, true));
out.Write("} vs[%d];\n", vertex_in); out.Write("} vs[%d];\n", vertex_in);
out.Write("out VertexData {\n"); out.Write("out VertexData {\n");
GenerateVSOutputMembers<T>(out, ApiType, g_ActiveConfig.backend_info.bSupportsBindingLayout ? "centroid" : "centroid out"); GenerateVSOutputMembers<T>(out, ApiType, GetInterpolationQualifier(ApiType, false, true));
if (g_ActiveConfig.iStereoMode > 0) if (g_ActiveConfig.iStereoMode > 0)
out.Write("\tflat int layer;\n"); out.Write("\tflat int layer;\n");

View File

@ -333,6 +333,8 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
warn_once = false; warn_once = false;
} }
uid_data->msaa = g_ActiveConfig.iMultisampleMode > 0;
uid_data->ssaa = g_ActiveConfig.iMultisampleMode > 0 && g_ActiveConfig.bSSAA;
if (ApiType == API_OPENGL) if (ApiType == API_OPENGL)
{ {
out.Write("out vec4 ocol0;\n"); out.Write("out vec4 ocol0;\n");
@ -342,19 +344,11 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
if (per_pixel_depth) if (per_pixel_depth)
out.Write("#define depth gl_FragDepth\n"); out.Write("#define depth gl_FragDepth\n");
// We use the flag "centroid" to fix some MSAA rendering bugs. With MSAA, the
// pixel shader will be executed for each pixel which has at least one passed sample.
// So there may be rendered pixels where the center of the pixel isn't in the primitive.
// As the pixel shader usually renders at the center of the pixel, this position may be
// outside the primitive. This will lead to sampling outside the texture, sign changes, ...
// As a workaround, we interpolate at the centroid of the coveraged pixel, which
// is always inside the primitive.
// Without MSAA, this flag is defined to have no effect.
uid_data->stereo = g_ActiveConfig.iStereoMode > 0; uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
{ {
out.Write("in VertexData {\n"); out.Write("in VertexData {\n");
GenerateVSOutputMembers<T>(out, ApiType, g_ActiveConfig.backend_info.bSupportsBindingLayout ? "centroid" : "centroid in"); GenerateVSOutputMembers<T>(out, ApiType, GetInterpolationQualifier(ApiType, true, true));
if (g_ActiveConfig.iStereoMode > 0) if (g_ActiveConfig.iStereoMode > 0)
out.Write("\tflat int layer;\n"); out.Write("\tflat int layer;\n");
@ -363,19 +357,19 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
} }
else else
{ {
out.Write("centroid in float4 colors_0;\n"); out.Write("%s in float4 colors_0;\n", GetInterpolationQualifier(ApiType));
out.Write("centroid in float4 colors_1;\n"); out.Write("%s in float4 colors_1;\n", GetInterpolationQualifier(ApiType));
// compute window position if needed because binding semantic WPOS is not widely supported // compute window position if needed because binding semantic WPOS is not widely supported
// Let's set up attributes // Let's set up attributes
for (unsigned int i = 0; i < numTexgen; ++i) for (unsigned int i = 0; i < numTexgen; ++i)
{ {
out.Write("centroid in float3 uv%d;\n", i); out.Write("%s in float3 uv%d;\n", GetInterpolationQualifier(ApiType), i);
} }
out.Write("centroid in float4 clipPos;\n"); out.Write("%s in float4 clipPos;\n", GetInterpolationQualifier(ApiType));
if (g_ActiveConfig.bEnablePixelLighting) if (g_ActiveConfig.bEnablePixelLighting)
{ {
out.Write("centroid in float3 Normal;\n"); out.Write("%s in float3 Normal;\n", GetInterpolationQualifier(ApiType));
out.Write("centroid in float3 WorldPos;\n"); out.Write("%s in float3 WorldPos;\n", GetInterpolationQualifier(ApiType));
} }
} }
@ -396,17 +390,17 @@ static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_T
dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : SV_Target1," : "", dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : SV_Target1," : "",
per_pixel_depth ? "\n out float depth : SV_Depth," : ""); per_pixel_depth ? "\n out float depth : SV_Depth," : "");
out.Write(" in centroid float4 colors_0 : COLOR0,\n"); out.Write(" in %s float4 colors_0 : COLOR0,\n", GetInterpolationQualifier(ApiType));
out.Write(" in centroid float4 colors_1 : COLOR1\n"); out.Write(" in %s float4 colors_1 : COLOR1\n", GetInterpolationQualifier(ApiType));
// compute window position if needed because binding semantic WPOS is not widely supported // compute window position if needed because binding semantic WPOS is not widely supported
for (unsigned int i = 0; i < numTexgen; ++i) for (unsigned int i = 0; i < numTexgen; ++i)
out.Write(",\n in centroid float3 uv%d : TEXCOORD%d", i, i); out.Write(",\n in %s float3 uv%d : TEXCOORD%d", GetInterpolationQualifier(ApiType), i, i);
out.Write(",\n in centroid float4 clipPos : TEXCOORD%d", numTexgen); out.Write(",\n in %s float4 clipPos : TEXCOORD%d", GetInterpolationQualifier(ApiType), numTexgen);
if (g_ActiveConfig.bEnablePixelLighting) if (g_ActiveConfig.bEnablePixelLighting)
{ {
out.Write(",\n in centroid float3 Normal : TEXCOORD%d", numTexgen + 1); out.Write(",\n in %s float3 Normal : TEXCOORD%d", GetInterpolationQualifier(ApiType), numTexgen + 1);
out.Write(",\n in centroid float3 WorldPos : TEXCOORD%d", numTexgen + 2); out.Write(",\n in %s float3 WorldPos : TEXCOORD%d", GetInterpolationQualifier(ApiType), numTexgen + 2);
} }
uid_data->stereo = g_ActiveConfig.iStereoMode > 0; uid_data->stereo = g_ActiveConfig.iStereoMode > 0;
if (g_ActiveConfig.iStereoMode > 0) if (g_ActiveConfig.iStereoMode > 0)

View File

@ -48,9 +48,11 @@ struct pixel_shader_uid_data
u32 early_ztest : 1; u32 early_ztest : 1;
u32 bounding_box : 1; u32 bounding_box : 1;
// TODO: 31 bits of padding is a waste. Can we free up some bits elseware? // TODO: 29 bits of padding is a waste. Can we free up some bits elseware?
u32 zfreeze : 1; u32 zfreeze : 1;
u32 pad : 31; u32 msaa : 1;
u32 ssaa : 1;
u32 pad : 29;
u32 texMtxInfo_n_projection : 8; // 8x1 bit u32 texMtxInfo_n_projection : 8; // 8x1 bit
u32 tevindref_bi0 : 3; u32 tevindref_bi0 : 3;

View File

@ -279,6 +279,29 @@ static inline void AssignVSOutputMembers(T& object, const char* a, const char* b
} }
} }
// We use the flag "centroid" to fix some MSAA rendering bugs. With MSAA, the
// pixel shader will be executed for each pixel which has at least one passed sample.
// So there may be rendered pixels where the center of the pixel isn't in the primitive.
// As the pixel shader usually renders at the center of the pixel, this position may be
// outside the primitive. This will lead to sampling outside the texture, sign changes, ...
// As a workaround, we interpolate at the centroid of the coveraged pixel, which
// is always inside the primitive.
// Without MSAA, this flag is defined to have no effect.
static inline const char* GetInterpolationQualifier(API_TYPE api_type, bool in = true, bool in_out = false)
{
if (!g_ActiveConfig.iMultisampleMode)
return "";
if (!g_ActiveConfig.bSSAA)
{
if (in_out && api_type == API_OPENGL && !g_ActiveConfig.backend_info.bSupportsBindingLayout)
return in ? "centroid in" : "centroid out";
return "centroid";
}
return "sample";
}
// Constant variable names // Constant variable names
#define I_COLORS "color" #define I_COLORS "color"
#define I_KCOLORS "k" #define I_KCOLORS "k"

View File

@ -77,7 +77,7 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
{ {
out.Write("out VertexData {\n"); out.Write("out VertexData {\n");
GenerateVSOutputMembers<T>(out, api_type, g_ActiveConfig.backend_info.bSupportsBindingLayout ? "centroid" : "centroid out"); GenerateVSOutputMembers<T>(out, api_type, GetInterpolationQualifier(api_type, false, true));
out.Write("} vs;\n"); out.Write("} vs;\n");
} }
else else
@ -87,17 +87,17 @@ static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_typ
{ {
if (i < xfmem.numTexGen.numTexGens) if (i < xfmem.numTexGen.numTexGens)
{ {
out.Write("centroid out float3 uv%d;\n", i); out.Write("%s out float3 uv%d;\n", GetInterpolationQualifier(api_type), i);
} }
} }
out.Write("centroid out float4 clipPos;\n"); out.Write("%s out float4 clipPos;\n", GetInterpolationQualifier(api_type));
if (g_ActiveConfig.bEnablePixelLighting) if (g_ActiveConfig.bEnablePixelLighting)
{ {
out.Write("centroid out float3 Normal;\n"); out.Write("%s out float3 Normal;\n", GetInterpolationQualifier(api_type));
out.Write("centroid out float3 WorldPos;\n"); out.Write("%s out float3 WorldPos;\n", GetInterpolationQualifier(api_type));
} }
out.Write("centroid out float4 colors_0;\n"); out.Write("%s out float4 colors_0;\n", GetInterpolationQualifier(api_type));
out.Write("centroid out float4 colors_1;\n"); out.Write("%s out float4 colors_1;\n", GetInterpolationQualifier(api_type));
} }
out.Write("void main()\n{\n"); out.Write("void main()\n{\n");