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.
This commit is contained in:
Ryan Houdek 2016-03-07 18:05:52 -06:00
parent 370e91d4c0
commit 3ab7806e24
4 changed files with 42 additions and 43 deletions

View File

@ -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<T>(out, ApiType);
GenerateVSOutputMembers<T>(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<T>(out, ApiType, GetInterpolationQualifier(ApiType, true, true));
GenerateVSOutputMembers<T>(out, ApiType, "in", GetInterpolationQualifier());
out.Write("} vs[%d];\n", vertex_in);
out.Write("out VertexData {\n");
GenerateVSOutputMembers<T>(out, ApiType, GetInterpolationQualifier(ApiType, false, true));
GenerateVSOutputMembers<T>(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");

View File

@ -282,7 +282,7 @@ static T GeneratePixelShader(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType)
}
out.Write("struct VS_OUTPUT {\n");
GenerateVSOutputMembers<T>(out, ApiType);
GenerateVSOutputMembers<T>(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<T>(out, ApiType, GetInterpolationQualifier(ApiType, true, true));
GenerateVSOutputMembers<T>(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)

View File

@ -214,12 +214,12 @@ private:
};
template<class T>
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<class T>
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";
}

View File

@ -41,7 +41,7 @@ static T GenerateVertexShader(API_TYPE api_type)
out.Write("};\n");
out.Write("struct VS_OUTPUT {\n");
GenerateVSOutputMembers<T>(out, api_type);
GenerateVSOutputMembers<T>(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<T>(out, api_type, GetInterpolationQualifier(api_type, false, true));
GenerateVSOutputMembers<T>(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");