From 3ab7806e242d631f2fb034a23f354764ef6b9ee9 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Mon, 7 Mar 2016 18:05:52 -0600 Subject: [PATCH] Workaround OS X video driver bug #24983074 OS X's shader compiler has a bug with interface blocks where interface block members don't properly inherit the layout qualifier from the interface block. Work around this limitation by explicitly stating the layout qualifier on both the interface block and every single member inside of that block. --- Source/Core/VideoCommon/GeometryShaderGen.cpp | 9 +++--- Source/Core/VideoCommon/PixelShaderGen.cpp | 31 ++++++++++--------- Source/Core/VideoCommon/ShaderGenCommon.h | 28 +++++++---------- Source/Core/VideoCommon/VertexShaderGen.cpp | 17 +++++----- 4 files changed, 42 insertions(+), 43 deletions(-) diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp index 057e697ed8..de76557d5e 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.cpp +++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp @@ -82,7 +82,7 @@ static T GenerateGeometryShader(u32 primitive_type, API_TYPE ApiType) uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting; out.Write("struct VS_OUTPUT {\n"); - GenerateVSOutputMembers(out, ApiType); + GenerateVSOutputMembers(out, ApiType, ""); out.Write("};\n"); if (ApiType == API_OPENGL) @@ -90,15 +90,16 @@ static T GenerateGeometryShader(u32 primitive_type, API_TYPE ApiType) if (g_ActiveConfig.backend_info.bSupportsGSInstancing) out.Write("#define InstanceID gl_InvocationID\n"); + out.Write("// The interface block qualifier is duplicated to its member due to Apple OS X bug 24983074\n"); out.Write("in VertexData {\n"); - GenerateVSOutputMembers(out, ApiType, GetInterpolationQualifier(ApiType, true, true)); + GenerateVSOutputMembers(out, ApiType, "in", GetInterpolationQualifier()); out.Write("} vs[%d];\n", vertex_in); out.Write("out VertexData {\n"); - GenerateVSOutputMembers(out, ApiType, GetInterpolationQualifier(ApiType, false, true)); + GenerateVSOutputMembers(out, ApiType, "out", GetInterpolationQualifier()); if (g_ActiveConfig.iStereoMode > 0) - out.Write("\tflat int layer;\n"); + out.Write("\tflat out int layer;\n"); out.Write("} ps;\n"); diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index f9781c5217..a7cdcc3b4a 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -282,7 +282,7 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType) } out.Write("struct VS_OUTPUT {\n"); - GenerateVSOutputMembers(out, ApiType); + GenerateVSOutputMembers(out, ApiType, ""); out.Write("};\n"); const bool forced_early_z = g_ActiveConfig.backend_info.bSupportsEarlyZ && bpmem.UseEarlyDepthTest() @@ -354,29 +354,30 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType) uid_data->stereo = g_ActiveConfig.iStereoMode > 0; if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) { + out.Write("// The interface block qualifier is duplicated to its member due to Apple OS X bug 24983074\n"); out.Write("in VertexData {\n"); - GenerateVSOutputMembers(out, ApiType, GetInterpolationQualifier(ApiType, true, true)); + GenerateVSOutputMembers(out, ApiType, "in", GetInterpolationQualifier()); if (g_ActiveConfig.iStereoMode > 0) - out.Write("\tflat int layer;\n"); + out.Write("\tflat in int layer;\n"); out.Write("};\n"); } else { - out.Write("%s in float4 colors_0;\n", GetInterpolationQualifier(ApiType)); - out.Write("%s in float4 colors_1;\n", GetInterpolationQualifier(ApiType)); + out.Write("%s in float4 colors_0;\n", GetInterpolationQualifier()); + out.Write("%s in float4 colors_1;\n", GetInterpolationQualifier()); // compute window position if needed because binding semantic WPOS is not widely supported // Let's set up attributes for (unsigned int i = 0; i < numTexgen; ++i) { - out.Write("%s in float3 uv%d;\n", GetInterpolationQualifier(ApiType), i); + out.Write("%s in float3 uv%d;\n", GetInterpolationQualifier(), i); } - out.Write("%s in float4 clipPos;\n", GetInterpolationQualifier(ApiType)); + out.Write("%s in float4 clipPos;\n", GetInterpolationQualifier()); if (g_ActiveConfig.bEnablePixelLighting) { - out.Write("%s in float3 Normal;\n", GetInterpolationQualifier(ApiType)); - out.Write("%s in float3 WorldPos;\n", GetInterpolationQualifier(ApiType)); + out.Write("%s in float3 Normal;\n", GetInterpolationQualifier()); + out.Write("%s in float3 WorldPos;\n", GetInterpolationQualifier()); } } @@ -397,17 +398,17 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType) dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "\n out float4 ocol1 : SV_Target1," : "", per_pixel_depth ? "\n out float depth : SV_Depth," : ""); - out.Write(" in %s float4 colors_0 : COLOR0,\n", GetInterpolationQualifier(ApiType)); - out.Write(" in %s float4 colors_1 : COLOR1\n", GetInterpolationQualifier(ApiType)); + out.Write(" in %s float4 colors_0 : COLOR0,\n", GetInterpolationQualifier()); + out.Write(" in %s float4 colors_1 : COLOR1\n", GetInterpolationQualifier()); // compute window position if needed because binding semantic WPOS is not widely supported for (unsigned int i = 0; i < numTexgen; ++i) - out.Write(",\n in %s float3 uv%d : TEXCOORD%d", GetInterpolationQualifier(ApiType), i, i); - out.Write(",\n in %s float4 clipPos : TEXCOORD%d", GetInterpolationQualifier(ApiType), numTexgen); + out.Write(",\n in %s float3 uv%d : TEXCOORD%d", GetInterpolationQualifier(), i, i); + out.Write(",\n in %s float4 clipPos : TEXCOORD%d", GetInterpolationQualifier(), numTexgen); if (g_ActiveConfig.bEnablePixelLighting) { - out.Write(",\n in %s float3 Normal : TEXCOORD%d", GetInterpolationQualifier(ApiType), numTexgen + 1); - out.Write(",\n in %s float3 WorldPos : TEXCOORD%d", GetInterpolationQualifier(ApiType), numTexgen + 2); + out.Write(",\n in %s float3 Normal : TEXCOORD%d", GetInterpolationQualifier(), numTexgen + 1); + out.Write(",\n in %s float3 WorldPos : TEXCOORD%d", GetInterpolationQualifier(), numTexgen + 2); } uid_data->stereo = g_ActiveConfig.iStereoMode > 0; if (g_ActiveConfig.iStereoMode > 0) diff --git a/Source/Core/VideoCommon/ShaderGenCommon.h b/Source/Core/VideoCommon/ShaderGenCommon.h index a6e7ce0b36..9283cdc8cc 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/ShaderGenCommon.h @@ -214,12 +214,12 @@ private: }; template -inline void DefineOutputMember(T& object, API_TYPE api_type, const char* qualifier, const char* type, const char* name, int var_index, const char* semantic = "", int semantic_index = -1) +inline void DefineOutputMember(T& object, API_TYPE api_type, const char* qualifier, const char* in_out, const char* type, const char* name, int var_index, const char* semantic = "", int semantic_index = -1) { if (qualifier != nullptr) - object.Write("\t%s %s %s", qualifier, type, name); + object.Write("\t%s %s %s %s", qualifier, in_out, type, name); else - object.Write("\t%s %s", type, name); + object.Write("\t%s %s %s", in_out, type, name); if (var_index != -1) object.Write("%d", var_index); @@ -236,21 +236,21 @@ inline void DefineOutputMember(T& object, API_TYPE api_type, const char* qualifi } template -inline void GenerateVSOutputMembers(T& object, API_TYPE api_type, const char* qualifier = nullptr) +inline void GenerateVSOutputMembers(T& object, API_TYPE api_type, const char* in_out, const char* qualifier = nullptr) { - DefineOutputMember(object, api_type, qualifier, "float4", "pos", -1, "POSITION"); - DefineOutputMember(object, api_type, qualifier, "float4", "colors_", 0, "COLOR", 0); - DefineOutputMember(object, api_type, qualifier, "float4", "colors_", 1, "COLOR", 1); + DefineOutputMember(object, api_type, qualifier, in_out, "float4", "pos", -1, "POSITION"); + DefineOutputMember(object, api_type, qualifier, in_out, "float4", "colors_", 0, "COLOR", 0); + DefineOutputMember(object, api_type, qualifier, in_out, "float4", "colors_", 1, "COLOR", 1); for (unsigned int i = 0; i < xfmem.numTexGen.numTexGens; ++i) - DefineOutputMember(object, api_type, qualifier, "float3", "tex", i, "TEXCOORD", i); + DefineOutputMember(object, api_type, qualifier, in_out, "float3", "tex", i, "TEXCOORD", i); - DefineOutputMember(object, api_type, qualifier, "float4", "clipPos", -1, "TEXCOORD", xfmem.numTexGen.numTexGens); + DefineOutputMember(object, api_type, qualifier, in_out, "float4", "clipPos", -1, "TEXCOORD", xfmem.numTexGen.numTexGens); if (g_ActiveConfig.bEnablePixelLighting) { - DefineOutputMember(object, api_type, qualifier, "float3", "Normal", -1, "TEXCOORD", xfmem.numTexGen.numTexGens + 1); - DefineOutputMember(object, api_type, qualifier, "float3", "WorldPos", -1, "TEXCOORD", xfmem.numTexGen.numTexGens + 2); + DefineOutputMember(object, api_type, qualifier, in_out, "float3", "Normal", -1, "TEXCOORD", xfmem.numTexGen.numTexGens + 1); + DefineOutputMember(object, api_type, qualifier, in_out, "float3", "WorldPos", -1, "TEXCOORD", xfmem.numTexGen.numTexGens + 2); } } @@ -281,17 +281,13 @@ inline void AssignVSOutputMembers(T& object, const char* a, const char* b) // 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. -inline const char* GetInterpolationQualifier(API_TYPE api_type, bool in = true, bool in_out = false) +inline const char* GetInterpolationQualifier() { if (g_ActiveConfig.iMultisamples <= 1) 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"; } diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 9a9a23b5b9..427656766e 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -41,7 +41,7 @@ static T GenerateVertexShader(API_TYPE api_type) out.Write("};\n"); out.Write("struct VS_OUTPUT {\n"); - GenerateVSOutputMembers(out, api_type); + GenerateVSOutputMembers(out, api_type, ""); out.Write("};\n"); uid_data->numTexGens = xfmem.numTexGen.numTexGens; @@ -74,8 +74,9 @@ static T GenerateVertexShader(API_TYPE api_type) if (g_ActiveConfig.backend_info.bSupportsGeometryShaders) { + out.Write("// The interface block qualifier is duplicated to its member due to Apple OS X bug 24983074\n"); out.Write("out VertexData {\n"); - GenerateVSOutputMembers(out, api_type, GetInterpolationQualifier(api_type, false, true)); + GenerateVSOutputMembers(out, api_type, "out", GetInterpolationQualifier()); out.Write("} vs;\n"); } else @@ -85,17 +86,17 @@ static T GenerateVertexShader(API_TYPE api_type) { if (i < xfmem.numTexGen.numTexGens) { - out.Write("%s out float3 uv%u;\n", GetInterpolationQualifier(api_type), i); + out.Write("%s out float3 uv%u;\n", GetInterpolationQualifier(), i); } } - out.Write("%s out float4 clipPos;\n", GetInterpolationQualifier(api_type)); + out.Write("%s out float4 clipPos;\n", GetInterpolationQualifier()); if (g_ActiveConfig.bEnablePixelLighting) { - out.Write("%s out float3 Normal;\n", GetInterpolationQualifier(api_type)); - out.Write("%s out float3 WorldPos;\n", GetInterpolationQualifier(api_type)); + out.Write("%s out float3 Normal;\n", GetInterpolationQualifier()); + out.Write("%s out float3 WorldPos;\n", GetInterpolationQualifier()); } - out.Write("%s out float4 colors_0;\n", GetInterpolationQualifier(api_type)); - out.Write("%s out float4 colors_1;\n", GetInterpolationQualifier(api_type)); + out.Write("%s out float4 colors_0;\n", GetInterpolationQualifier()); + out.Write("%s out float4 colors_1;\n", GetInterpolationQualifier()); } out.Write("void main()\n{\n");