From 82c27182a8a15903a0082890e6b188435ec957b4 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 24 Jun 2017 18:18:53 +1000 Subject: [PATCH 01/10] ShaderGen: Remove host state from shader uids --- Source/Core/VideoCommon/GeometryShaderGen.cpp | 113 +++++++++--------- Source/Core/VideoCommon/GeometryShaderGen.h | 10 +- Source/Core/VideoCommon/PixelShaderGen.cpp | 86 ++++++------- Source/Core/VideoCommon/PixelShaderGen.h | 9 +- Source/Core/VideoCommon/VertexShaderGen.cpp | 46 ++++--- Source/Core/VideoCommon/VertexShaderGen.h | 6 +- Source/Core/VideoCommon/VideoConfig.cpp | 16 +++ Source/Core/VideoCommon/VideoConfig.h | 7 ++ 8 files changed, 139 insertions(+), 154 deletions(-) diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp index 5695e9c256..0e7a23b979 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.cpp +++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp @@ -18,10 +18,12 @@ static const char* primitives_ogl[] = {"points", "lines", "triangles"}; static const char* primitives_d3d[] = {"point", "line", "triangle"}; -template -static void EmitVertex(T& out, const char* vertex, APIType ApiType, bool first_vertex = false); -template -static void EndPrimitive(T& out, APIType ApiType); +bool geometry_shader_uid_data::IsPassthrough() const +{ + const bool stereo = g_ActiveConfig.iStereoMode > 0; + const bool wireframe = g_ActiveConfig.bWireFrame; + return primitive_type == PRIMITIVE_TRIANGLES && !stereo && !wireframe; +} GeometryShaderUid GetGeometryShaderUid(u32 primitive_type) { @@ -30,30 +32,31 @@ GeometryShaderUid GetGeometryShaderUid(u32 primitive_type) memset(uid_data, 0, sizeof(geometry_shader_uid_data)); uid_data->primitive_type = primitive_type; - uid_data->wireframe = g_ActiveConfig.bWireFrame; - uid_data->msaa = g_ActiveConfig.iMultisamples > 1; - uid_data->ssaa = g_ActiveConfig.iMultisamples > 1 && g_ActiveConfig.bSSAA; - uid_data->stereo = g_ActiveConfig.iStereoMode > 0; uid_data->numTexGens = xfmem.numTexGen.numTexGens; - uid_data->pixel_lighting = g_ActiveConfig.bEnablePixelLighting; return out; } static void EmitVertex(ShaderCode& out, const geometry_shader_uid_data* uid_data, - const char* vertex, APIType ApiType, bool first_vertex = false); -static void EndPrimitive(ShaderCode& out, const geometry_shader_uid_data* uid_data, - APIType ApiType); + const char* vertex, APIType ApiType, bool wireframe, bool pixel_lighting, + bool first_vertex = false); +static void EndPrimitive(ShaderCode& out, const geometry_shader_uid_data* uid_data, APIType ApiType, + bool wireframe, bool pixel_lighting); ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid_data* uid_data) { ShaderCode out; // Non-uid template parameters will write to the dummy data (=> gets optimized out) + const bool wireframe = g_ActiveConfig.bWireFrame; + const bool pixel_lighting = g_ActiveConfig.bEnablePixelLighting; + const bool msaa = g_ActiveConfig.IsMSAAEnabled(); + const bool ssaa = g_ActiveConfig.IsSSAAEnabled(); + const bool stereo = g_ActiveConfig.IsStereoEnabled(); const unsigned int vertex_in = uid_data->primitive_type + 1; unsigned int vertex_out = uid_data->primitive_type == PRIMITIVE_TRIANGLES ? 3 : 4; - if (uid_data->wireframe) + if (wireframe) vertex_out++; if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) @@ -62,16 +65,15 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid if (g_ActiveConfig.backend_info.bSupportsGSInstancing) { out.Write("layout(%s, invocations = %d) in;\n", primitives_ogl[uid_data->primitive_type], - uid_data->stereo ? 2 : 1); - out.Write("layout(%s_strip, max_vertices = %d) out;\n", - uid_data->wireframe ? "line" : "triangle", vertex_out); + stereo ? 2 : 1); + out.Write("layout(%s_strip, max_vertices = %d) out;\n", wireframe ? "line" : "triangle", + vertex_out); } else { out.Write("layout(%s) in;\n", primitives_ogl[uid_data->primitive_type]); - out.Write("layout(%s_strip, max_vertices = %d) out;\n", - uid_data->wireframe ? "line" : "triangle", - uid_data->stereo ? vertex_out * 2 : vertex_out); + out.Write("layout(%s_strip, max_vertices = %d) out;\n", wireframe ? "line" : "triangle", + stereo ? vertex_out * 2 : vertex_out); } } @@ -89,8 +91,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid "};\n"); out.Write("struct VS_OUTPUT {\n"); - GenerateVSOutputMembers(out, ApiType, uid_data->numTexGens, uid_data->pixel_lighting, - ""); + GenerateVSOutputMembers(out, ApiType, uid_data->numTexGens, pixel_lighting, ""); out.Write("};\n"); if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) @@ -99,17 +100,15 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid out.Write("#define InstanceID gl_InvocationID\n"); out.Write("VARYING_LOCATION(0) in VertexData {\n"); - GenerateVSOutputMembers( - out, ApiType, uid_data->numTexGens, uid_data->pixel_lighting, - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa, true, true)); + GenerateVSOutputMembers(out, ApiType, uid_data->numTexGens, pixel_lighting, + GetInterpolationQualifier(msaa, ssaa, true, true)); out.Write("} vs[%d];\n", vertex_in); out.Write("VARYING_LOCATION(0) out VertexData {\n"); - GenerateVSOutputMembers( - out, ApiType, uid_data->numTexGens, uid_data->pixel_lighting, - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa, true, false)); + GenerateVSOutputMembers(out, ApiType, uid_data->numTexGens, pixel_lighting, + GetInterpolationQualifier(msaa, ssaa, true, false)); - if (uid_data->stereo) + if (stereo) out.Write("\tflat int layer;\n"); out.Write("} ps;\n"); @@ -121,25 +120,25 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid out.Write("struct VertexData {\n"); out.Write("\tVS_OUTPUT o;\n"); - if (uid_data->stereo) + if (stereo) out.Write("\tuint layer : SV_RenderTargetArrayIndex;\n"); out.Write("};\n"); if (g_ActiveConfig.backend_info.bSupportsGSInstancing) { - out.Write("[maxvertexcount(%d)]\n[instance(%d)]\n", vertex_out, uid_data->stereo ? 2 : 1); + out.Write("[maxvertexcount(%d)]\n[instance(%d)]\n", vertex_out, stereo ? 2 : 1); out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream output, in uint " "InstanceID : SV_GSInstanceID)\n{\n", primitives_d3d[uid_data->primitive_type], vertex_in, - uid_data->wireframe ? "Line" : "Triangle"); + wireframe ? "Line" : "Triangle"); } else { - out.Write("[maxvertexcount(%d)]\n", uid_data->stereo ? vertex_out * 2 : vertex_out); + out.Write("[maxvertexcount(%d)]\n", stereo ? vertex_out * 2 : vertex_out); out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream output)\n{\n", primitives_d3d[uid_data->primitive_type], vertex_in, - uid_data->wireframe ? "Line" : "Triangle"); + wireframe ? "Line" : "Triangle"); } out.Write("\tVertexData ps;\n"); @@ -150,8 +149,8 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) { out.Write("\tVS_OUTPUT start, end;\n"); - AssignVSOutputMembers(out, "start", "vs[0]", uid_data->numTexGens, uid_data->pixel_lighting); - AssignVSOutputMembers(out, "end", "vs[1]", uid_data->numTexGens, uid_data->pixel_lighting); + AssignVSOutputMembers(out, "start", "vs[0]", uid_data->numTexGens, pixel_lighting); + AssignVSOutputMembers(out, "end", "vs[1]", uid_data->numTexGens, pixel_lighting); } else { @@ -181,7 +180,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) { out.Write("\tVS_OUTPUT center;\n"); - AssignVSOutputMembers(out, "center", "vs[0]", uid_data->numTexGens, uid_data->pixel_lighting); + AssignVSOutputMembers(out, "center", "vs[0]", uid_data->numTexGens, pixel_lighting); } else { @@ -194,7 +193,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid ".x, -" I_LINEPTPARAMS ".w / " I_LINEPTPARAMS ".y) * center.pos.w;\n"); } - if (uid_data->stereo) + if (stereo) { // If the GPU supports invocation we don't need a for loop and can simply use the // invocation identifier to determine which layer we're rendering. @@ -204,7 +203,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid out.Write("\tfor (int eye = 0; eye < 2; ++eye) {\n"); } - if (uid_data->wireframe) + if (wireframe) out.Write("\tVS_OUTPUT first;\n"); out.Write("\tfor (int i = 0; i < %d; ++i) {\n", vertex_in); @@ -212,7 +211,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) { out.Write("\tVS_OUTPUT f;\n"); - AssignVSOutputMembers(out, "f", "vs[i]", uid_data->numTexGens, uid_data->pixel_lighting); + AssignVSOutputMembers(out, "f", "vs[i]", uid_data->numTexGens, pixel_lighting); if (g_ActiveConfig.backend_info.bSupportsDepthClamp && DriverDetails::HasBug(DriverDetails::BUG_BROKEN_CLIP_DISTANCE)) @@ -228,7 +227,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid out.Write("\tVS_OUTPUT f = o[i];\n"); } - if (uid_data->stereo) + if (stereo) { // Select the output layer out.Write("\tps.layer = eye;\n"); @@ -264,8 +263,8 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid } out.Write("\t}\n"); - EmitVertex(out, uid_data, "l", ApiType, true); - EmitVertex(out, uid_data, "r", ApiType); + EmitVertex(out, uid_data, "l", ApiType, wireframe, pixel_lighting, true); + EmitVertex(out, uid_data, "r", ApiType, wireframe, pixel_lighting); } else if (uid_data->primitive_type == PRIMITIVE_POINTS) { @@ -293,21 +292,21 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid } out.Write("\t}\n"); - EmitVertex(out, uid_data, "ll", ApiType, true); - EmitVertex(out, uid_data, "lr", ApiType); - EmitVertex(out, uid_data, "ul", ApiType); - EmitVertex(out, uid_data, "ur", ApiType); + EmitVertex(out, uid_data, "ll", ApiType, wireframe, pixel_lighting, true); + EmitVertex(out, uid_data, "lr", ApiType, wireframe, pixel_lighting); + EmitVertex(out, uid_data, "ul", ApiType, wireframe, pixel_lighting); + EmitVertex(out, uid_data, "ur", ApiType, wireframe, pixel_lighting); } else { - EmitVertex(out, uid_data, "f", ApiType, true); + EmitVertex(out, uid_data, "f", ApiType, wireframe, pixel_lighting, true); } out.Write("\t}\n"); - EndPrimitive(out, uid_data, ApiType); + EndPrimitive(out, uid_data, ApiType, wireframe, pixel_lighting); - if (uid_data->stereo && !g_ActiveConfig.backend_info.bSupportsGSInstancing) + if (stereo && !g_ActiveConfig.backend_info.bSupportsGSInstancing) out.Write("\t}\n"); out.Write("}\n"); @@ -316,9 +315,10 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid } static void EmitVertex(ShaderCode& out, const geometry_shader_uid_data* uid_data, - const char* vertex, APIType ApiType, bool first_vertex) + const char* vertex, APIType ApiType, bool wireframe, bool pixel_lighting, + bool first_vertex) { - if (uid_data->wireframe && first_vertex) + if (wireframe && first_vertex) out.Write("\tif (i == 0) first = %s;\n", vertex); if (ApiType == APIType::OpenGL) @@ -329,14 +329,14 @@ static void EmitVertex(ShaderCode& out, const geometry_shader_uid_data* uid_data 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); + AssignVSOutputMembers(out, "ps", vertex, uid_data->numTexGens, pixel_lighting); } else if (ApiType == APIType::Vulkan) { // Vulkan NDC space has Y pointing down (right-handed NDC space). out.Write("\tgl_Position = %s.pos;\n", vertex); out.Write("\tgl_Position.y = -gl_Position.y;\n"); - AssignVSOutputMembers(out, "ps", vertex, uid_data->numTexGens, uid_data->pixel_lighting); + AssignVSOutputMembers(out, "ps", vertex, uid_data->numTexGens, pixel_lighting); } else { @@ -349,10 +349,11 @@ static void EmitVertex(ShaderCode& out, const geometry_shader_uid_data* uid_data out.Write("\toutput.Append(ps);\n"); } -static void EndPrimitive(ShaderCode& out, const geometry_shader_uid_data* uid_data, APIType ApiType) +static void EndPrimitive(ShaderCode& out, const geometry_shader_uid_data* uid_data, APIType ApiType, + bool wireframe, bool pixel_lighting) { - if (uid_data->wireframe) - EmitVertex(out, uid_data, "first", ApiType); + if (wireframe) + EmitVertex(out, uid_data, "first", ApiType, wireframe, pixel_lighting); if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) out.Write("\tEndPrimitive();\n"); diff --git a/Source/Core/VideoCommon/GeometryShaderGen.h b/Source/Core/VideoCommon/GeometryShaderGen.h index 03b58a0367..8c00886bc6 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.h +++ b/Source/Core/VideoCommon/GeometryShaderGen.h @@ -15,18 +15,10 @@ enum class APIType; struct geometry_shader_uid_data { u32 NumValues() const { return sizeof(geometry_shader_uid_data); } - bool IsPassthrough() const - { - return primitive_type == PRIMITIVE_TRIANGLES && !stereo && !wireframe; - } + bool IsPassthrough() const; - u32 stereo : 1; u32 numTexGens : 4; - u32 pixel_lighting : 1; u32 primitive_type : 2; - u32 wireframe : 1; - u32 msaa : 1; - u32 ssaa : 1; }; #pragma pack() diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index cec2c5183d..0dd4e868c6 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -170,7 +170,6 @@ PixelShaderUid GetPixelShaderUid() uid_data->genMode_numindstages = bpmem.genMode.numindstages; uid_data->genMode_numtevstages = bpmem.genMode.numtevstages; uid_data->genMode_numtexgens = bpmem.genMode.numtexgens; - uid_data->per_pixel_lighting = g_ActiveConfig.bEnablePixelLighting; uid_data->bounding_box = g_ActiveConfig.BBoxUseFragmentShaderImplementation() && g_ActiveConfig.bBBoxEnable && BoundingBox::active; uid_data->rgba6_format = @@ -192,13 +191,9 @@ PixelShaderUid GetPixelShaderUid() uid_data->per_pixel_depth = per_pixel_depth; uid_data->forced_early_z = forced_early_z; - uid_data->fast_depth_calc = g_ActiveConfig.bFastDepthCalc; - uid_data->msaa = g_ActiveConfig.iMultisamples > 1; - uid_data->ssaa = g_ActiveConfig.iMultisamples > 1 && g_ActiveConfig.bSSAA; - uid_data->stereo = g_ActiveConfig.iStereoMode > 0; if (!uid_data->forced_early_z && bpmem.UseEarlyDepthTest() && - (!uid_data->fast_depth_calc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED)) + (!g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED)) { static bool warn_once = true; if (warn_once) @@ -209,7 +204,7 @@ PixelShaderUid GetPixelShaderUid() warn_once = false; } - if (uid_data->per_pixel_lighting) + if (g_ActiveConfig.bEnablePixelLighting) { // The lighting shader only needs the two color bits of the 23bit component bit array. uid_data->components = @@ -297,7 +292,7 @@ PixelShaderUid GetPixelShaderUid() } #define MY_STRUCT_OFFSET(str, elem) ((u32)((u64) & (str).elem - (u64) & (str))) - uid_data->num_values = (uid_data->per_pixel_lighting) ? + uid_data->num_values = (g_ActiveConfig.bEnablePixelLighting) ? sizeof(*uid_data) : MY_STRUCT_OFFSET(*uid_data, stagehash[numStages]); @@ -339,7 +334,7 @@ PixelShaderUid GetPixelShaderUid() } static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n, - APIType ApiType); + APIType ApiType, bool stereo); static void WriteTevRegular(ShaderCode& out, const char* components, int bias, int op, int clamp, int shift, bool alpha); static void SampleTexture(ShaderCode& out, const char* texcoords, const char* texswap, int texmap, @@ -354,7 +349,11 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* { ShaderCode out; - u32 numStages = uid_data->genMode_numtevstages + 1; + const bool per_pixel_lighting = g_ActiveConfig.bEnablePixelLighting; + const bool msaa = g_ActiveConfig.IsMSAAEnabled(); + const bool ssaa = g_ActiveConfig.IsSSAAEnabled(); + const bool stereo = g_ActiveConfig.IsStereoEnabled(); + const u32 numStages = uid_data->genMode_numtevstages + 1; out.Write("//Pixel Shader for TEV stages\n"); out.Write("//%i TEV stages, %i texgens, %i IND stages\n", numStages, uid_data->genMode_numtexgens, @@ -422,7 +421,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* "\tfloat4 " I_EFBSCALE ";\n" "};\n"); - if (uid_data->per_pixel_lighting) + if (per_pixel_lighting) { out.Write("%s", s_lighting_struct); @@ -450,8 +449,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* } out.Write("struct VS_OUTPUT {\n"); - GenerateVSOutputMembers(out, ApiType, uid_data->genMode_numtexgens, uid_data->per_pixel_lighting, - ""); + GenerateVSOutputMembers(out, ApiType, uid_data->genMode_numtexgens, per_pixel_lighting, ""); out.Write("};\n"); if (uid_data->forced_early_z) @@ -534,36 +532,29 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* if (g_ActiveConfig.backend_info.bSupportsGeometryShaders || ApiType == APIType::Vulkan) { out.Write("VARYING_LOCATION(0) in VertexData {\n"); - GenerateVSOutputMembers( - out, ApiType, uid_data->genMode_numtexgens, uid_data->per_pixel_lighting, - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa, true, true)); + GenerateVSOutputMembers(out, ApiType, uid_data->genMode_numtexgens, per_pixel_lighting, + GetInterpolationQualifier(msaa, ssaa, true, true)); - if (uid_data->stereo) + if (stereo) out.Write("\tflat int layer;\n"); out.Write("};\n"); } else { - out.Write("%s in float4 colors_0;\n", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa)); - out.Write("%s in float4 colors_1;\n", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa)); + out.Write("%s in float4 colors_0;\n", GetInterpolationQualifier(msaa, ssaa)); + out.Write("%s in float4 colors_1;\n", GetInterpolationQualifier(msaa, ssaa)); // compute window position if needed because binding semantic WPOS is not widely supported // Let's set up attributes for (unsigned int i = 0; i < uid_data->genMode_numtexgens; ++i) { - out.Write("%s in float3 uv%d;\n", GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa), - i); + out.Write("%s in float3 uv%d;\n", GetInterpolationQualifier(msaa, ssaa), i); } - out.Write("%s in float4 clipPos;\n", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa)); - if (uid_data->per_pixel_lighting) + out.Write("%s in float4 clipPos;\n", GetInterpolationQualifier(msaa, ssaa)); + if (per_pixel_lighting) { - out.Write("%s in float3 Normal;\n", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa)); - out.Write("%s in float3 WorldPos;\n", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa)); + out.Write("%s in float3 Normal;\n", GetInterpolationQualifier(msaa, ssaa)); + out.Write("%s in float3 WorldPos;\n", GetInterpolationQualifier(msaa, ssaa)); } } @@ -585,30 +576,24 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* " in float4 rawpos : SV_Position,\n", uid_data->per_pixel_depth ? " out float depth : SV_Depth,\n" : ""); - out.Write(" in %s float4 colors_0 : COLOR0,\n", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa)); - out.Write(" in %s float4 colors_1 : COLOR1\n", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa)); + out.Write(" in %s float4 colors_0 : COLOR0,\n", GetInterpolationQualifier(msaa, ssaa)); + out.Write(" in %s float4 colors_1 : COLOR1\n", GetInterpolationQualifier(msaa, ssaa)); // compute window position if needed because binding semantic WPOS is not widely supported for (unsigned int i = 0; i < uid_data->genMode_numtexgens; ++i) - out.Write(",\n in %s float3 uv%d : TEXCOORD%d", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa), i, i); - out.Write(",\n in %s float4 clipPos : TEXCOORD%d", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa), + out.Write(",\n in %s float3 uv%d : TEXCOORD%d", GetInterpolationQualifier(msaa, ssaa), i, i); + out.Write(",\n in %s float4 clipPos : TEXCOORD%d", GetInterpolationQualifier(msaa, ssaa), uid_data->genMode_numtexgens); - if (uid_data->per_pixel_lighting) + if (per_pixel_lighting) { - out.Write(",\n in %s float3 Normal : TEXCOORD%d", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa), + out.Write(",\n in %s float3 Normal : TEXCOORD%d", GetInterpolationQualifier(msaa, ssaa), uid_data->genMode_numtexgens + 1); - out.Write(",\n in %s float3 WorldPos : TEXCOORD%d", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa), + out.Write(",\n in %s float3 WorldPos : TEXCOORD%d", GetInterpolationQualifier(msaa, ssaa), uid_data->genMode_numtexgens + 2); } out.Write(",\n in float clipDist0 : SV_ClipDistance0\n"); out.Write(",\n in float clipDist1 : SV_ClipDistance1\n"); - if (uid_data->stereo) + if (stereo) out.Write(",\n in uint layer : SV_RenderTargetArrayIndex\n"); out.Write(" ) {\n"); } @@ -630,7 +615,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* out.Write("\tfloat4 col0 = colors_0;\n"); out.Write("\tfloat4 col1 = colors_1;\n"); - if (uid_data->per_pixel_lighting) + if (per_pixel_lighting) { out.Write("\tfloat3 _norm0 = normalize(Normal.xyz);\n\n"); out.Write("\tfloat3 pos = WorldPos;\n"); @@ -682,12 +667,12 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* out.Write("\ttempcoord = int2(0, 0);\n"); out.Write("\tint3 iindtex%d = ", i); - SampleTexture(out, "float2(tempcoord)", "abg", texmap, uid_data->stereo, ApiType); + SampleTexture(out, "float2(tempcoord)", "abg", texmap, stereo, ApiType); } } for (unsigned int i = 0; i < numStages; i++) - WriteStage(out, uid_data, i, ApiType); // build the equation for this stage + WriteStage(out, uid_data, i, ApiType, stereo); // build the equation for this stage { // The results of the last texenv stage are put onto the screen, @@ -728,7 +713,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* out.Write("\tint zCoord = int(" I_ZSLOPE ".z + " I_ZSLOPE ".x * screenpos.x + " I_ZSLOPE ".y * screenpos.y);\n"); } - else if (!uid_data->fast_depth_calc) + else if (!g_ActiveConfig.bFastDepthCalc) { // FastDepth means to trust the depth generated in perspective division. // It should be correct, but it seems not to be as accurate as required. TODO: Find out why! @@ -814,7 +799,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* } static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, int n, - APIType ApiType) + APIType ApiType, bool stereo) { auto& stage = uid_data->stagehash[n]; out.Write("\n\t// TEV stage %d\n", n); @@ -1013,8 +998,7 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i out.Write("\ttevcoord.xy = int2(0, 0);\n"); } out.Write("\ttextemp = "); - SampleTexture(out, "float2(tevcoord.xy)", texswap, stage.tevorders_texmap, uid_data->stereo, - ApiType); + SampleTexture(out, "float2(tevcoord.xy)", texswap, stage.tevorders_texmap, stereo, ApiType); } else { diff --git a/Source/Core/VideoCommon/PixelShaderGen.h b/Source/Core/VideoCommon/PixelShaderGen.h index 2c19d38d87..4ba7405cd7 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.h +++ b/Source/Core/VideoCommon/PixelShaderGen.h @@ -18,11 +18,10 @@ struct pixel_shader_uid_data u32 num_values; // TODO: Shouldn't be a u32 u32 NumValues() const { return num_values; } u32 components : 2; - u32 pad0 : 1; + u32 pad0 : 2; u32 useDstAlpha : 1; u32 Pretest : 2; u32 nIndirectStagesUsed : 4; - u32 stereo : 1; u32 genMode_numtexgens : 4; u32 genMode_numtevstages : 4; u32 genMode_numindstages : 3; @@ -35,20 +34,16 @@ struct pixel_shader_uid_data u32 fog_fsel : 3; u32 fog_RangeBaseEnabled : 1; u32 ztex_op : 2; - u32 fast_depth_calc : 1; u32 per_pixel_depth : 1; - u32 per_pixel_lighting : 1; u32 forced_early_z : 1; u32 early_ztest : 1; u32 late_ztest : 1; u32 bounding_box : 1; u32 zfreeze : 1; - u32 msaa : 1; - u32 ssaa : 1; u32 numColorChans : 2; u32 rgba6_format : 1; u32 dither : 1; - u32 pad : 12; + u32 pad : 16; u32 texMtxInfo_n_projection : 8; // 8x1 bit u32 tevindref_bi0 : 3; diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 9fe4bfcada..a69245bda7 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -26,11 +26,6 @@ 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; GetLightingShaderUid(uid_data->lighting); @@ -84,6 +79,12 @@ VertexShaderUid GetVertexShaderUid() ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_data* uid_data) { ShaderCode out; + + const bool per_pixel_lighting = g_ActiveConfig.bEnablePixelLighting; + const bool msaa = g_ActiveConfig.IsMSAAEnabled(); + const bool ssaa = g_ActiveConfig.IsSSAAEnabled(); + const bool vertex_rounding = g_ActiveConfig.UseVertexRounding(); + out.Write("%s", s_lighting_struct); // uniforms @@ -96,7 +97,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da out.Write("};\n"); out.Write("struct VS_OUTPUT {\n"); - GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, uid_data->pixel_lighting, ""); + GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, per_pixel_lighting, ""); out.Write("};\n"); if (api_type == APIType::OpenGL || api_type == APIType::Vulkan) @@ -130,9 +131,8 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da if (g_ActiveConfig.backend_info.bSupportsGeometryShaders || api_type == APIType::Vulkan) { out.Write("VARYING_LOCATION(0) out VertexData {\n"); - GenerateVSOutputMembers( - out, api_type, uid_data->numTexGens, uid_data->pixel_lighting, - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa, true, false)); + GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, per_pixel_lighting, + GetInterpolationQualifier(msaa, ssaa, true, false)); out.Write("} vs;\n"); } else @@ -142,23 +142,17 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da { if (i < uid_data->numTexGens) { - out.Write("%s out float3 uv%u;\n", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa), i); + out.Write("%s out float3 uv%u;\n", GetInterpolationQualifier(msaa, ssaa), i); } } - out.Write("%s out float4 clipPos;\n", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa)); - if (uid_data->pixel_lighting) + out.Write("%s out float4 clipPos;\n", GetInterpolationQualifier(msaa, ssaa)); + if (per_pixel_lighting) { - out.Write("%s out float3 Normal;\n", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa)); - out.Write("%s out float3 WorldPos;\n", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa)); + out.Write("%s out float3 Normal;\n", GetInterpolationQualifier(msaa, ssaa)); + out.Write("%s out float3 WorldPos;\n", GetInterpolationQualifier(msaa, ssaa)); } - out.Write("%s out float4 colors_0;\n", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa)); - out.Write("%s out float4 colors_1;\n", - GetInterpolationQualifier(uid_data->msaa, uid_data->ssaa)); + out.Write("%s out float4 colors_0;\n", GetInterpolationQualifier(msaa, ssaa)); + out.Write("%s out float4 colors_1;\n", GetInterpolationQualifier(msaa, ssaa)); } out.Write("void main()\n{\n"); @@ -406,7 +400,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da // clipPos/w needs to be done in pixel shader, not here out.Write("o.clipPos = o.pos;\n"); - if (uid_data->pixel_lighting) + if (per_pixel_lighting) { out.Write("o.Normal = _norm0;\n"); out.Write("o.WorldPos = pos.xyz;\n"); @@ -466,7 +460,7 @@ 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) + if (vertex_rounding) { // By now our position is in clip space // however, higher resolutions than the Wii outputs @@ -493,7 +487,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da { if (g_ActiveConfig.backend_info.bSupportsGeometryShaders || api_type == APIType::Vulkan) { - AssignVSOutputMembers(out, "vs", "o", uid_data->numTexGens, uid_data->pixel_lighting); + AssignVSOutputMembers(out, "vs", "o", uid_data->numTexGens, per_pixel_lighting); } else { @@ -502,7 +496,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da for (unsigned int i = 0; i < uid_data->numTexGens; ++i) out.Write("uv%d.xyz = o.tex%d;\n", i, i); out.Write("clipPos = o.clipPos;\n"); - if (uid_data->pixel_lighting) + if (per_pixel_lighting) { out.Write("Normal = o.Normal;\n"); out.Write("WorldPos = o.WorldPos;\n"); diff --git a/Source/Core/VideoCommon/VertexShaderGen.h b/Source/Core/VideoCommon/VertexShaderGen.h index 0fa8e88815..8c6f14f0e6 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.h +++ b/Source/Core/VideoCommon/VertexShaderGen.h @@ -37,14 +37,10 @@ struct vertex_shader_uid_data u32 numTexGens : 4; u32 numColorChans : 2; u32 dualTexTrans_enabled : 1; - u32 pixel_lighting : 1; - u32 msaa : 1; u32 texMtxInfo_n_projection : 16; // Stored separately to guarantee that the texMtxInfo struct is // 8 bits wide - u32 ssaa : 1; - u32 vertex_rounding : 1; - u32 pad : 14; + u32 pad : 18; struct { diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp index 7dc68abb72..d53e903cee 100644 --- a/Source/Core/VideoCommon/VideoConfig.cpp +++ b/Source/Core/VideoCommon/VideoConfig.cpp @@ -187,3 +187,19 @@ bool VideoConfig::IsVSync() { return bVSync && !Core::GetIsThrottlerTempDisabled(); } + +bool VideoConfig::IsStereoEnabled() const +{ + return iStereoMode > 0; +} + +bool VideoConfig::IsMSAAEnabled() const +{ + return iMultisamples > 1; +} + +bool VideoConfig::IsSSAAEnabled() const +{ + return iMultisamples > 1 && bSSAA && backend_info.bSupportsSSAA; +} + diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index e706cea1c3..dd7dd88fa4 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -223,6 +223,13 @@ struct VideoConfig final { return backend_info.bSupportsGPUTextureDecoding && bEnableGPUTextureDecoding; } + bool UseVertexRounding() const { return bVertexRounding && iEFBScale != SCALE_1X; } + bool IsStereoEnabled() const; + bool IsMSAAEnabled() const; + bool IsSSAAEnabled() const; + // Host config contains the settings which can influence generated shaders. + u32 GetHostConfigBits() const; + std::string GetHostConfigFilename() const; }; extern VideoConfig g_Config; From d1381f5021815c36d2fdd98087b6522c995428cc Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 24 Jun 2017 18:55:08 +1000 Subject: [PATCH 02/10] VideoConfig: Add host config union Contains all host state that can affect shadergen. --- Source/Core/VideoCommon/VideoConfig.cpp | 58 +++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp index d53e903cee..78784c5c9c 100644 --- a/Source/Core/VideoCommon/VideoConfig.cpp +++ b/Source/Core/VideoCommon/VideoConfig.cpp @@ -5,6 +5,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/StringUtil.h" #include "Core/Config/GraphicsSettings.h" #include "Core/Core.h" #include "Core/Movie.h" @@ -203,3 +204,60 @@ bool VideoConfig::IsSSAAEnabled() const return iMultisamples > 1 && bSSAA && backend_info.bSupportsSSAA; } +union HostConfigBits +{ + u32 bits; + + struct + { + u32 msaa : 1; + u32 ssaa : 1; + u32 stereo : 1; + u32 wireframe : 1; + u32 per_pixel_lighting : 1; + u32 vertex_rounding : 1; + u32 fast_depth_calc : 1; + u32 bounding_box : 1; + u32 backend_dual_source_blend : 1; + u32 backend_geometry_shaders : 1; + u32 backend_early_z : 1; + u32 backend_bbox : 1; + u32 backend_gs_instancing : 1; + u32 backend_clip_control : 1; + u32 backend_ssaa : 1; + u32 backend_atomics : 1; + u32 backend_depth_clamp : 1; + u32 backend_reversed_depth_range : 1; + u32 pad : 14; + }; +}; + +u32 VideoConfig::GetHostConfigBits() const +{ + HostConfigBits bits = {}; + bits.msaa = IsMSAAEnabled(); + bits.ssaa = IsSSAAEnabled(); + bits.stereo = IsStereoEnabled(); + bits.wireframe = bWireFrame; + bits.per_pixel_lighting = bEnablePixelLighting; + bits.vertex_rounding = UseVertexRounding(); + bits.fast_depth_calc = bFastDepthCalc; + bits.bounding_box = bBBoxEnable; + bits.backend_dual_source_blend = backend_info.bSupportsDualSourceBlend; + bits.backend_geometry_shaders = backend_info.bSupportsGeometryShaders; + bits.backend_early_z = backend_info.bSupportsEarlyZ; + bits.backend_bbox = backend_info.bSupportsBBox; + bits.backend_gs_instancing = backend_info.bSupportsGSInstancing; + bits.backend_clip_control = backend_info.bSupportsClipControl; + bits.backend_ssaa = backend_info.bSupportsSSAA; + bits.backend_atomics = backend_info.bSupportsFragmentStoresAndAtomics; + bits.backend_depth_clamp = backend_info.bSupportsDepthClamp; + bits.backend_reversed_depth_range = backend_info.bSupportsReversedDepthRange; + return bits.bits; +} + +std::string VideoConfig::GetHostConfigFilename() const +{ + u32 bits = GetHostConfigBits(); + return StringFromFormat("%08X", bits); +} From 62a901508b1fd23eb386a3d108950ab061bbc19a Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 24 Jun 2017 19:20:34 +1000 Subject: [PATCH 03/10] OGL: Reload shader cache when relevant video config changes --- .../VideoBackends/OGL/ProgramShaderCache.cpp | 142 +++++++++++------- .../VideoBackends/OGL/ProgramShaderCache.h | 5 + Source/Core/VideoBackends/OGL/Render.cpp | 10 ++ Source/Core/VideoBackends/OGL/Render.h | 3 + 4 files changed, 103 insertions(+), 57 deletions(-) diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp index 4f1db6e0c2..3fd3573bb4 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp @@ -504,29 +504,7 @@ void ProgramShaderCache::Init() // Read our shader cache, only if supported and enabled if (g_ogl_config.bSupportsGLSLCache && g_ActiveConfig.bShaderCache) - { - GLint Supported; - glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &Supported); - if (!Supported) - { - ERROR_LOG(VIDEO, "GL_ARB_get_program_binary is supported, but no binary format is known. So " - "disable shader cache."); - g_ogl_config.bSupportsGLSLCache = false; - } - else - { - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - - std::string cache_filename = - StringFromFormat("%sogl-%s-shaders.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), - SConfig::GetInstance().GetGameID().c_str()); - - ProgramShaderCacheInserter inserter; - g_program_disk_cache.OpenAndRead(cache_filename, inserter); - } - SETSTAT(stats.numPixelShadersAlive, pshaders.size()); - } + LoadProgramBinaries(); CreateHeader(); @@ -534,47 +512,99 @@ void ProgramShaderCache::Init() last_entry = nullptr; } +void ProgramShaderCache::Reload() +{ + const bool use_cache = g_ogl_config.bSupportsGLSLCache && g_ActiveConfig.bShaderCache; + if (use_cache) + SaveProgramBinaries(); + + g_program_disk_cache.Close(); + DestroyShaders(); + + if (use_cache) + LoadProgramBinaries(); + + CurrentProgram = 0; + last_entry = nullptr; + last_uid = {}; +} + void ProgramShaderCache::Shutdown() { // store all shaders in cache on disk - if (g_ogl_config.bSupportsGLSLCache) + if (g_ogl_config.bSupportsGLSLCache && g_ActiveConfig.bShaderCache) + SaveProgramBinaries(); + g_program_disk_cache.Close(); + + DestroyShaders(); + s_buffer.reset(); +} + +void ProgramShaderCache::LoadProgramBinaries() +{ + GLint Supported; + glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &Supported); + if (!Supported) { - for (auto& entry : pshaders) + ERROR_LOG(VIDEO, "GL_ARB_get_program_binary is supported, but no binary format is known. So " + "disable shader cache."); + g_ogl_config.bSupportsGLSLCache = false; + } + else + { + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + + std::string host_part = g_ActiveConfig.GetHostConfigFilename(); + std::string cache_filename = + StringFromFormat("%sogl-%s-%s-shaders.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), + SConfig::GetInstance().GetGameID().c_str(), host_part.c_str()); + + ProgramShaderCacheInserter inserter; + g_program_disk_cache.OpenAndRead(cache_filename, inserter); + } + SETSTAT(stats.numPixelShadersAlive, pshaders.size()); +} + +void ProgramShaderCache::SaveProgramBinaries() +{ + for (auto& entry : pshaders) + { + // Clear any prior error code + glGetError(); + + if (entry.second.in_cache) { - // Clear any prior error code - glGetError(); - - if (entry.second.in_cache) - { - continue; - } - - GLint link_status = GL_FALSE, delete_status = GL_TRUE, binary_size = 0; - glGetProgramiv(entry.second.shader.glprogid, GL_LINK_STATUS, &link_status); - glGetProgramiv(entry.second.shader.glprogid, GL_DELETE_STATUS, &delete_status); - glGetProgramiv(entry.second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size); - if (glGetError() != GL_NO_ERROR || link_status == GL_FALSE || delete_status == GL_TRUE || - !binary_size) - { - continue; - } - - std::vector data(binary_size + sizeof(GLenum)); - u8* binary = &data[sizeof(GLenum)]; - GLenum* prog_format = (GLenum*)&data[0]; - glGetProgramBinary(entry.second.shader.glprogid, binary_size, nullptr, prog_format, binary); - if (glGetError() != GL_NO_ERROR) - { - continue; - } - - g_program_disk_cache.Append(entry.first, &data[0], binary_size + sizeof(GLenum)); + continue; } - g_program_disk_cache.Sync(); - g_program_disk_cache.Close(); + GLint link_status = GL_FALSE, delete_status = GL_TRUE, binary_size = 0; + glGetProgramiv(entry.second.shader.glprogid, GL_LINK_STATUS, &link_status); + glGetProgramiv(entry.second.shader.glprogid, GL_DELETE_STATUS, &delete_status); + glGetProgramiv(entry.second.shader.glprogid, GL_PROGRAM_BINARY_LENGTH, &binary_size); + if (glGetError() != GL_NO_ERROR || link_status == GL_FALSE || delete_status == GL_TRUE || + !binary_size) + { + continue; + } + + std::vector data(binary_size + sizeof(GLenum)); + u8* binary = &data[sizeof(GLenum)]; + GLenum* prog_format = (GLenum*)&data[0]; + glGetProgramBinary(entry.second.shader.glprogid, binary_size, nullptr, prog_format, binary); + if (glGetError() != GL_NO_ERROR) + { + continue; + } + + g_program_disk_cache.Append(entry.first, &data[0], binary_size + sizeof(GLenum)); } + g_program_disk_cache.Sync(); +} + +void ProgramShaderCache::DestroyShaders() +{ glUseProgram(0); for (auto& entry : pshaders) @@ -582,8 +612,6 @@ void ProgramShaderCache::Shutdown() entry.second.Destroy(); } pshaders.clear(); - - s_buffer.reset(); } void ProgramShaderCache::CreateHeader() diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h index 7af4a2c38e..7b29c24314 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h @@ -72,6 +72,7 @@ public: static void UploadConstants(); static void Init(); + static void Reload(); static void Shutdown(); static void CreateHeader(); @@ -82,6 +83,10 @@ private: void Read(const SHADERUID& key, const u8* value, u32 value_size) override; }; + static void LoadProgramBinaries(); + static void SaveProgramBinaries(); + static void DestroyShaders(); + typedef std::map PCache; static PCache pshaders; static PCacheEntry* last_entry; diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 3282489369..50a3d366cc 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -688,6 +688,7 @@ Renderer::Renderer() s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; + m_last_host_config_bits = g_ActiveConfig.GetHostConfigBits(); // Handle VSync on/off s_vsync = g_ActiveConfig.IsVSync(); @@ -1469,6 +1470,15 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, UpdateActiveConfig(); g_texture_cache->OnConfigChanged(g_ActiveConfig); + // Invalidate shader cache when the host config changes. + u32 new_host_config_bits = g_ActiveConfig.GetHostConfigBits(); + if (new_host_config_bits != m_last_host_config_bits) + { + OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL); + ProgramShaderCache::Reload(); + m_last_host_config_bits = new_host_config_bits; + } + // For testing zbuffer targets. // Renderer::SetZBufferRender(); // SaveTexture("tex.png", GL_TEXTURE_2D, s_FakeZTarget, diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index 8ec6a21e0d..dd1de56b6a 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -148,5 +148,8 @@ private: std::array m_last_frame_height = {}; bool m_last_frame_exported = false; AVIDump::Frame m_last_frame_state; + + // last host config state + u32 m_last_host_config_bits = 0; }; } From 228ddb8abab02105e02233647834bde2528d9ba9 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 24 Jun 2017 19:29:03 +1000 Subject: [PATCH 04/10] D3D11: Reload shader cache when relevant config changes --- .../VideoBackends/D3D/GeometryShaderCache.cpp | 32 +++++++++++++------ .../VideoBackends/D3D/GeometryShaderCache.h | 3 ++ .../VideoBackends/D3D/PixelShaderCache.cpp | 32 +++++++++++++------ .../Core/VideoBackends/D3D/PixelShaderCache.h | 3 ++ Source/Core/VideoBackends/D3D/Render.cpp | 11 +++++++ Source/Core/VideoBackends/D3D/Render.h | 2 ++ .../VideoBackends/D3D/VertexShaderCache.cpp | 32 +++++++++++++------ .../VideoBackends/D3D/VertexShaderCache.h | 3 ++ 8 files changed, 88 insertions(+), 30 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp index 6dbd3d3dde..951b4287da 100644 --- a/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp @@ -158,18 +158,29 @@ void GeometryShaderCache::Init() Clear(); if (g_ActiveConfig.bShaderCache) - { - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + LoadShaderCache(); +} - std::string cache_filename = - StringFromFormat("%sdx11-%s-gs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), - SConfig::GetInstance().GetGameID().c_str()); - GeometryShaderCacheInserter inserter; - g_gs_disk_cache.OpenAndRead(cache_filename, inserter); - } +void GeometryShaderCache::LoadShaderCache() +{ + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - last_entry = nullptr; + std::string cache_filename = StringFromFormat( + "%sdx11-%s-%s-gs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), + SConfig::GetInstance().GetGameID().c_str(), g_ActiveConfig.GetHostConfigFilename().c_str()); + GeometryShaderCacheInserter inserter; + g_gs_disk_cache.OpenAndRead(cache_filename, inserter); +} + +void GeometryShaderCache::Reload() +{ + g_gs_disk_cache.Sync(); + g_gs_disk_cache.Close(); + Clear(); + + if (g_ActiveConfig.bShaderCache) + LoadShaderCache(); } // ONLY to be used during shutdown. @@ -180,6 +191,7 @@ void GeometryShaderCache::Clear() GeometryShaders.clear(); last_entry = nullptr; + last_uid = {}; } void GeometryShaderCache::Shutdown() diff --git a/Source/Core/VideoBackends/D3D/GeometryShaderCache.h b/Source/Core/VideoBackends/D3D/GeometryShaderCache.h index 72024e52f5..e6eca3b2e0 100644 --- a/Source/Core/VideoBackends/D3D/GeometryShaderCache.h +++ b/Source/Core/VideoBackends/D3D/GeometryShaderCache.h @@ -15,6 +15,7 @@ class GeometryShaderCache { public: static void Init(); + static void Reload(); static void Clear(); static void Shutdown(); static bool SetShader(u32 primitive_type); // TODO: Should be renamed to LoadShader @@ -38,6 +39,8 @@ private: typedef std::map GSCache; + static void LoadShaderCache(); + static GSCache GeometryShaders; static const GSCacheEntry* last_entry; static GeometryShaderUid last_uid; diff --git a/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp b/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp index 289e9a32f9..d3bdce59f1 100644 --- a/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp @@ -498,18 +498,29 @@ void PixelShaderCache::Init() SETSTAT(stats.numPixelShadersAlive, 0); if (g_ActiveConfig.bShaderCache) - { - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + LoadShaderCache(); +} - std::string cache_filename = - StringFromFormat("%sdx11-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), - SConfig::GetInstance().GetGameID().c_str()); - PixelShaderCacheInserter inserter; - g_ps_disk_cache.OpenAndRead(cache_filename, inserter); - } +void PixelShaderCache::LoadShaderCache() +{ + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - last_entry = nullptr; + std::string cache_filename = StringFromFormat( + "%sdx11-%s-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), + SConfig::GetInstance().GetGameID().c_str(), g_ActiveConfig.GetHostConfigFilename().c_str()); + PixelShaderCacheInserter inserter; + g_ps_disk_cache.OpenAndRead(cache_filename, inserter); +} + +void PixelShaderCache::Reload() +{ + g_ps_disk_cache.Sync(); + g_ps_disk_cache.Close(); + Clear(); + + if (g_ActiveConfig.bShaderCache) + LoadShaderCache(); } // ONLY to be used during shutdown. @@ -520,6 +531,7 @@ void PixelShaderCache::Clear() PixelShaders.clear(); last_entry = nullptr; + last_uid = {}; } // Used in Swap() when AA mode has changed diff --git a/Source/Core/VideoBackends/D3D/PixelShaderCache.h b/Source/Core/VideoBackends/D3D/PixelShaderCache.h index d3d4106a53..fb1b79ad6c 100644 --- a/Source/Core/VideoBackends/D3D/PixelShaderCache.h +++ b/Source/Core/VideoBackends/D3D/PixelShaderCache.h @@ -15,6 +15,7 @@ class PixelShaderCache { public: static void Init(); + static void Reload(); static void Clear(); static void Shutdown(); static bool SetShader(); // TODO: Should be renamed to LoadShader @@ -46,6 +47,8 @@ private: typedef std::map PSCache; + static void LoadShaderCache(); + static PSCache PixelShaders; static const PSCacheEntry* last_entry; static PixelShaderUid last_uid; diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index df4aad0e28..31bd6a82bb 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -242,6 +242,7 @@ Renderer::Renderer() : ::Renderer(D3D::GetBackBufferWidth(), D3D::GetBackBufferH s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; s_last_fullscreen_mode = D3D::GetFullscreenState(); + m_last_host_config_bits = g_ActiveConfig.GetHostConfigBits(); g_framebuffer_manager = std::make_unique(m_target_width, m_target_height); SetupDeviceObjects(); @@ -894,6 +895,16 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, D3D11_CLEAR_DEPTH, 0.f, 0); } + u32 new_host_config_bits = g_ActiveConfig.GetHostConfigBits(); + if (new_host_config_bits != m_last_host_config_bits) + { + OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL); + VertexShaderCache::Reload(); + GeometryShaderCache::Reload(); + PixelShaderCache::Reload(); + m_last_host_config_bits = new_host_config_bits; + } + // begin next frame RestoreAPIState(); D3D::BeginFrame(); diff --git a/Source/Core/VideoBackends/D3D/Render.h b/Source/Core/VideoBackends/D3D/Render.h index e5b429f2ab..a72c9308a2 100644 --- a/Source/Core/VideoBackends/D3D/Render.h +++ b/Source/Core/VideoBackends/D3D/Render.h @@ -64,5 +64,7 @@ public: private: void BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, u32 src_width, u32 src_height, float Gamma); + + u32 m_last_host_config_bits = 0; }; } diff --git a/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp b/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp index 1ca0982e6f..77aa06b2f4 100644 --- a/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp @@ -159,18 +159,29 @@ void VertexShaderCache::Init() SETSTAT(stats.numVertexShadersAlive, 0); if (g_ActiveConfig.bShaderCache) - { - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + LoadShaderCache(); +} - std::string cache_filename = - StringFromFormat("%sdx11-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), - SConfig::GetInstance().GetGameID().c_str()); - VertexShaderCacheInserter inserter; - g_vs_disk_cache.OpenAndRead(cache_filename, inserter); - } +void VertexShaderCache::LoadShaderCache() +{ + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - last_entry = nullptr; + std::string cache_filename = StringFromFormat( + "%sdx11-%s-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), + SConfig::GetInstance().GetGameID().c_str(), g_ActiveConfig.GetHostConfigFilename().c_str()); + VertexShaderCacheInserter inserter; + g_vs_disk_cache.OpenAndRead(cache_filename, inserter); +} + +void VertexShaderCache::Reload() +{ + g_vs_disk_cache.Sync(); + g_vs_disk_cache.Close(); + Clear(); + + if (g_ActiveConfig.bShaderCache) + LoadShaderCache(); } void VertexShaderCache::Clear() @@ -180,6 +191,7 @@ void VertexShaderCache::Clear() vshaders.clear(); last_entry = nullptr; + last_uid = {}; } void VertexShaderCache::Shutdown() diff --git a/Source/Core/VideoBackends/D3D/VertexShaderCache.h b/Source/Core/VideoBackends/D3D/VertexShaderCache.h index ba006bb954..514e807192 100644 --- a/Source/Core/VideoBackends/D3D/VertexShaderCache.h +++ b/Source/Core/VideoBackends/D3D/VertexShaderCache.h @@ -17,6 +17,7 @@ class VertexShaderCache { public: static void Init(); + static void Reload(); static void Clear(); static void Shutdown(); static bool SetShader(); // TODO: Should be renamed to LoadShader @@ -53,6 +54,8 @@ private: }; typedef std::map VSCache; + static void LoadShaderCache(); + static VSCache vshaders; static const VSCacheEntry* last_entry; static VertexShaderUid last_uid; From d9a3b29a0776ef64e33883bdd7aef237c31ff7da Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 21 Jun 2017 00:05:45 +1000 Subject: [PATCH 05/10] Vulkan: Emit input/output locations for EFB poke geometry shader --- Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp index 3f76d180b0..be751f636e 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp @@ -1274,12 +1274,12 @@ bool FramebufferManager::CompilePokeShaders() layout(triangles) in; layout(triangle_strip, max_vertices = EFB_LAYERS * 3) out; - in VertexData + VARYING_LOCATION(0) in VertexData { vec4 col0; } in_data[]; - out VertexData + VARYING_LOCATION(0) out VertexData { vec4 col0; } out_data; From a8343cc19a3728d4a44c279dff167503a6eaecfc Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 24 Jun 2017 19:43:58 +1000 Subject: [PATCH 06/10] Vulkan: Don't save pipeline cache if shader cache is disabled We still create a pipeline cache object, since that speeds up driver's creation of pipelines at runtime. However, we should not save it. --- .../Core/VideoBackends/Vulkan/ObjectCache.cpp | 87 ++++++++++++------- .../Core/VideoBackends/Vulkan/ObjectCache.h | 3 +- Source/Core/VideoBackends/Vulkan/main.cpp | 3 +- 3 files changed, 58 insertions(+), 35 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp index 4fadbfcfc4..ad138cc754 100644 --- a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp @@ -49,9 +49,17 @@ bool ObjectCache::Initialize() if (!CreatePipelineLayouts()) return false; - LoadShaderCaches(); - if (!CreatePipelineCache(true)) - return false; + if (g_ActiveConfig.bShaderCache) + { + LoadShaderCaches(); + if (!LoadPipelineCache()) + return false; + } + else + { + if (!CreatePipelineCache()) + return false; + } if (!CreateUtilityShaderVertexFormat()) return false; @@ -465,26 +473,44 @@ public: void Read(const u32& key, const u8* value, u32 value_size) override {} }; -bool ObjectCache::CreatePipelineCache(bool load_from_disk) +bool ObjectCache::CreatePipelineCache() +{ + m_pipeline_cache_filename = GetDiskCacheFileName("pipeline"); + + VkPipelineCacheCreateInfo info = { + VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType + nullptr, // const void* pNext + 0, // VkPipelineCacheCreateFlags flags + 0, // size_t initialDataSize + nullptr // const void* pInitialData + }; + + VkResult res = + vkCreatePipelineCache(g_vulkan_context->GetDevice(), &info, nullptr, &m_pipeline_cache); + if (res == VK_SUCCESS) + return true; + + LOG_VULKAN_ERROR(res, "vkCreatePipelineCache failed: "); + return false; +} + +bool ObjectCache::LoadPipelineCache() { // We have to keep the pipeline cache file name around since when we save it // we delete the old one, by which time the game's unique ID is already cleared. m_pipeline_cache_filename = GetDiskCacheFileName("pipeline"); std::vector disk_data; - if (load_from_disk) - { - LinearDiskCache disk_cache; - PipelineCacheReadCallback read_callback(&disk_data); - if (disk_cache.OpenAndRead(m_pipeline_cache_filename, read_callback) != 1) - disk_data.clear(); - } + LinearDiskCache disk_cache; + PipelineCacheReadCallback read_callback(&disk_data); + if (disk_cache.OpenAndRead(m_pipeline_cache_filename, read_callback) != 1) + disk_data.clear(); if (!disk_data.empty() && !ValidatePipelineCache(disk_data.data(), disk_data.size())) { // Don't use this data. In fact, we should delete it to prevent it from being used next time. File::Delete(m_pipeline_cache_filename); - disk_data.clear(); + return CreatePipelineCache(); } VkPipelineCacheCreateInfo info = { @@ -492,7 +518,7 @@ bool ObjectCache::CreatePipelineCache(bool load_from_disk) nullptr, // const void* pNext 0, // VkPipelineCacheCreateFlags flags disk_data.size(), // size_t initialDataSize - !disk_data.empty() ? disk_data.data() : nullptr, // const void* pInitialData + disk_data.data() // const void* pInitialData }; VkResult res = @@ -502,14 +528,7 @@ bool ObjectCache::CreatePipelineCache(bool load_from_disk) // Failed to create pipeline cache, try with it empty. LOG_VULKAN_ERROR(res, "vkCreatePipelineCache failed, trying empty cache: "); - info.initialDataSize = 0; - info.pInitialData = nullptr; - res = vkCreatePipelineCache(g_vulkan_context->GetDevice(), &info, nullptr, &m_pipeline_cache); - if (res == VK_SUCCESS) - return true; - - LOG_VULKAN_ERROR(res, "vkCreatePipelineCache failed: "); - return false; + return CreatePipelineCache(); } // Based on Vulkan 1.0 specification, @@ -644,19 +663,16 @@ struct ShaderCacheReader : public LinearDiskCacheReader void ObjectCache::LoadShaderCaches() { - if (g_ActiveConfig.bShaderCache) + ShaderCacheReader vs_reader(m_vs_cache.shader_map); + m_vs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("vs"), vs_reader); + + ShaderCacheReader ps_reader(m_ps_cache.shader_map); + m_ps_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("ps"), ps_reader); + + if (g_vulkan_context->SupportsGeometryShaders()) { - ShaderCacheReader vs_reader(m_vs_cache.shader_map); - m_vs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("vs"), vs_reader); - - ShaderCacheReader ps_reader(m_ps_cache.shader_map); - m_ps_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("ps"), ps_reader); - - if (g_vulkan_context->SupportsGeometryShaders()) - { - ShaderCacheReader gs_reader(m_gs_cache.shader_map); - m_gs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("gs"), gs_reader); - } + ShaderCacheReader gs_reader(m_gs_cache.shader_map); + m_gs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("gs"), gs_reader); } SETSTAT(stats.numPixelShadersCreated, static_cast(m_ps_cache.shader_map.size())); @@ -684,6 +700,11 @@ void ObjectCache::DestroyShaderCaches() if (g_vulkan_context->SupportsGeometryShaders()) DestroyShaderCache(m_gs_cache); + + SETSTAT(stats.numPixelShadersCreated, 0); + SETSTAT(stats.numPixelShadersAlive, 0); + SETSTAT(stats.numVertexShadersCreated, 0); + SETSTAT(stats.numVertexShadersAlive, 0); } VkShaderModule ObjectCache::GetVertexShaderForUid(const VertexShaderUid& uid) diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.h b/Source/Core/VideoBackends/Vulkan/ObjectCache.h index 97c457a7f8..8d7f4f6cc7 100644 --- a/Source/Core/VideoBackends/Vulkan/ObjectCache.h +++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.h @@ -163,7 +163,8 @@ public: std::string GetDiskCacheFileName(const char* type); private: - bool CreatePipelineCache(bool load_from_disk); + bool CreatePipelineCache(); + bool LoadPipelineCache(); bool ValidatePipelineCache(const u8* data, size_t data_length); void DestroyPipelineCache(); void LoadShaderCaches(); diff --git a/Source/Core/VideoBackends/Vulkan/main.cpp b/Source/Core/VideoBackends/Vulkan/main.cpp index 6eaaa09b4c..2fdcae7e98 100644 --- a/Source/Core/VideoBackends/Vulkan/main.cpp +++ b/Source/Core/VideoBackends/Vulkan/main.cpp @@ -290,7 +290,8 @@ void VideoBackend::Video_Cleanup() g_command_buffer_mgr->WaitForGPUIdle(); // Save all cached pipelines out to disk for next time. - g_object_cache->SavePipelineCache(); + if (g_ActiveConfig.bShaderCache) + g_object_cache->SavePipelineCache(); g_perf_query.reset(); g_texture_cache.reset(); From b380f292b47c8b1a3e1711a665a3469074715485 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 24 Jun 2017 19:58:14 +1000 Subject: [PATCH 07/10] Vulkan: Reload pipeline cache when relevant host config changes --- .../Core/VideoBackends/Vulkan/ObjectCache.cpp | 41 +++++++++++++++---- .../Core/VideoBackends/Vulkan/ObjectCache.h | 5 ++- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 26 +++++------- .../VideoBackends/Vulkan/StateTracker.cpp | 18 +++++++- .../Core/VideoBackends/Vulkan/StateTracker.h | 5 ++- 5 files changed, 67 insertions(+), 28 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp index ad138cc754..d63533b7f4 100644 --- a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp @@ -446,10 +446,14 @@ void ObjectCache::ClearPipelineCache() m_compute_pipeline_objects.clear(); } -std::string ObjectCache::GetDiskCacheFileName(const char* type) +std::string ObjectCache::GetDiskCacheFileName(const char* type, bool include_gameid, + bool include_host_config) { - return StringFromFormat("%svulkan-%s-%s.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), - SConfig::GetInstance().GetGameID().c_str(), type); + return StringFromFormat( + "%svulkan-%s%s%s%s%s.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), type, + include_gameid ? "-" : "", include_gameid ? SConfig::GetInstance().GetGameID().c_str() : "", + include_host_config ? "-" : "", + include_host_config ? g_ActiveConfig.GetHostConfigFilename().c_str() : ""); } class PipelineCacheReadCallback : public LinearDiskCacheReader @@ -475,7 +479,10 @@ public: bool ObjectCache::CreatePipelineCache() { - m_pipeline_cache_filename = GetDiskCacheFileName("pipeline"); + // Vulkan pipeline caches can be shared between games for shader compile time reduction. + // This assumes that drivers don't create all pipelines in the cache on load time, only + // when a lookup occurs that matches a pipeline (or pipeline data) in the cache. + m_pipeline_cache_filename = GetDiskCacheFileName("pipeline", false, true); VkPipelineCacheCreateInfo info = { VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType @@ -498,7 +505,7 @@ bool ObjectCache::LoadPipelineCache() { // We have to keep the pipeline cache file name around since when we save it // we delete the old one, by which time the game's unique ID is already cleared. - m_pipeline_cache_filename = GetDiskCacheFileName("pipeline"); + m_pipeline_cache_filename = GetDiskCacheFileName("pipeline", false, true); std::vector disk_data; LinearDiskCache disk_cache; @@ -664,15 +671,15 @@ struct ShaderCacheReader : public LinearDiskCacheReader void ObjectCache::LoadShaderCaches() { ShaderCacheReader vs_reader(m_vs_cache.shader_map); - m_vs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("vs"), vs_reader); + m_vs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("vs", true, true), vs_reader); ShaderCacheReader ps_reader(m_ps_cache.shader_map); - m_ps_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("ps"), ps_reader); + m_ps_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("ps", true, true), ps_reader); if (g_vulkan_context->SupportsGeometryShaders()) { ShaderCacheReader gs_reader(m_gs_cache.shader_map); - m_gs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("gs"), gs_reader); + m_gs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("gs", true, true), gs_reader); } SETSTAT(stats.numPixelShadersCreated, static_cast(m_ps_cache.shader_map.size())); @@ -684,6 +691,7 @@ void ObjectCache::LoadShaderCaches() template static void DestroyShaderCache(T& cache) { + cache.disk_cache.Sync(); cache.disk_cache.Close(); for (const auto& it : cache.shader_map) { @@ -825,6 +833,23 @@ void ObjectCache::RecompileSharedShaders() PanicAlert("Failed to recompile shared shaders."); } +void ObjectCache::ReloadShaderAndPipelineCaches() +{ + SavePipelineCache(); + DestroyShaderCaches(); + DestroyPipelineCache(); + + if (g_ActiveConfig.bShaderCache) + { + LoadShaderCaches(); + LoadPipelineCache(); + } + else + { + CreatePipelineCache(); + } +} + bool ObjectCache::CreateDescriptorSetLayouts() { static const VkDescriptorSetLayoutBinding ubo_set_bindings[] = { diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.h b/Source/Core/VideoBackends/Vulkan/ObjectCache.h index 8d7f4f6cc7..58476f16ab 100644 --- a/Source/Core/VideoBackends/Vulkan/ObjectCache.h +++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.h @@ -154,13 +154,16 @@ public: // Recompile shared shaders, call when stereo mode changes. void RecompileSharedShaders(); + // Reload pipeline cache. This will destroy all pipelines. + void ReloadShaderAndPipelineCaches(); + // Shared shader accessors VkShaderModule GetScreenQuadVertexShader() const { return m_screen_quad_vertex_shader; } VkShaderModule GetPassthroughVertexShader() const { return m_passthrough_vertex_shader; } VkShaderModule GetScreenQuadGeometryShader() const { return m_screen_quad_geometry_shader; } VkShaderModule GetPassthroughGeometryShader() const { return m_passthrough_geometry_shader; } // Gets the filename of the specified type of cache object (e.g. vertex shader, pipeline). - std::string GetDiskCacheFileName(const char* type); + std::string GetDiskCacheFileName(const char* type, bool include_gameid, bool include_host_config); private: bool CreatePipelineCache(); diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 9a26df8548..e2690ab253 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -114,7 +114,7 @@ bool Renderer::Initialize() } // Ensure all pipelines previously used by the game have been created. - StateTracker::GetInstance()->LoadPipelineUIDCache(); + StateTracker::GetInstance()->ReloadPipelineUIDCache(); // Initialize post processing. m_post_processor = std::make_unique(); @@ -1126,13 +1126,11 @@ void Renderer::CheckForSurfaceChange() void Renderer::CheckForConfigChanges() { // Save the video config so we can compare against to determine which settings have changed. - u32 old_multisamples = g_ActiveConfig.iMultisamples; + u32 old_host_bits = g_ActiveConfig.GetHostConfigBits(); int old_anisotropy = g_ActiveConfig.iMaxAnisotropy; - int old_stereo_mode = g_ActiveConfig.iStereoMode; int old_aspect_ratio = g_ActiveConfig.iAspectRatio; int old_efb_scale = g_ActiveConfig.iEFBScale; bool old_force_filtering = g_ActiveConfig.bForceFiltering; - bool old_ssaa = g_ActiveConfig.bSSAA; bool old_use_xfb = g_ActiveConfig.bUseXFB; bool old_use_realxfb = g_ActiveConfig.bUseRealXFB; @@ -1142,11 +1140,9 @@ void Renderer::CheckForConfigChanges() UpdateActiveConfig(); // Determine which (if any) settings have changed. - bool msaa_changed = old_multisamples != g_ActiveConfig.iMultisamples; - bool ssaa_changed = old_ssaa != g_ActiveConfig.bSSAA; + bool host_bits_changed = old_host_bits != g_ActiveConfig.GetHostConfigBits(); bool anisotropy_changed = old_anisotropy != g_ActiveConfig.iMaxAnisotropy; bool force_texture_filtering_changed = old_force_filtering != g_ActiveConfig.bForceFiltering; - bool stereo_changed = old_stereo_mode != g_ActiveConfig.iStereoMode; bool efb_scale_changed = old_efb_scale != g_ActiveConfig.iEFBScale; bool aspect_changed = old_aspect_ratio != g_ActiveConfig.iAspectRatio; bool use_xfb_changed = old_use_xfb != g_ActiveConfig.bUseXFB; @@ -1164,23 +1160,21 @@ void Renderer::CheckForConfigChanges() // MSAA samples changed, we need to recreate the EFB render pass. // If the stereoscopy mode changed, we need to recreate the buffers as well. - if (msaa_changed || stereo_changed) + // SSAA changed on/off, we have to recompile shaders. + // Changing stereoscopy from off<->on also requires shaders to be recompiled. + if (host_bits_changed) { + OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL); g_command_buffer_mgr->WaitForGPUIdle(); FramebufferManager::GetInstance()->RecreateRenderPass(); FramebufferManager::GetInstance()->ResizeEFBTextures(); BindEFBToStateTracker(); - } - - // SSAA changed on/off, we can leave the buffers/render pass, but have to recompile shaders. - // Changing stereoscopy from off<->on also requires shaders to be recompiled. - if (msaa_changed || ssaa_changed || stereo_changed) - { - g_command_buffer_mgr->WaitForGPUIdle(); RecompileShaders(); FramebufferManager::GetInstance()->RecompileShaders(); + g_object_cache->ReloadShaderAndPipelineCaches(); g_object_cache->RecompileSharedShaders(); - StateTracker::GetInstance()->LoadPipelineUIDCache(); + StateTracker::GetInstance()->InvalidateShaderPointers(); + StateTracker::GetInstance()->ReloadPipelineUIDCache(); } // For vsync, we need to change the present mode, which means recreating the swap chain. diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp index 7299e981a9..01b6065f3c 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp @@ -115,7 +115,20 @@ bool StateTracker::Initialize() return true; } -void StateTracker::LoadPipelineUIDCache() +void StateTracker::InvalidateShaderPointers() +{ + // Clear UIDs, forcing a false match next time. + m_vs_uid = {}; + m_gs_uid = {}; + m_ps_uid = {}; + + // Invalidate shader pointers. + m_pipeline_state.vs = VK_NULL_HANDLE; + m_pipeline_state.gs = VK_NULL_HANDLE; + m_pipeline_state.ps = VK_NULL_HANDLE; +} + +void StateTracker::ReloadPipelineUIDCache() { class PipelineInserter final : public LinearDiskCacheReader { @@ -130,7 +143,8 @@ void StateTracker::LoadPipelineUIDCache() StateTracker* this_ptr; }; - std::string filename = g_object_cache->GetDiskCacheFileName("pipeline-uid"); + // UID caches don't contain any host state, so use a single uid cache per gameid. + std::string filename = g_object_cache->GetDiskCacheFileName("pipeline-uid", true, false); PipelineInserter inserter(this); // OpenAndRead calls Close() first, which will flush all data to disk when reloading. diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.h b/Source/Core/VideoBackends/Vulkan/StateTracker.h index 0b16d52661..ef09608fe8 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.h +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.h @@ -117,7 +117,10 @@ public: bool IsWithinRenderArea(s32 x, s32 y, u32 width, u32 height) const; // Reloads the UID cache, ensuring all pipelines used by the game so far have been created. - void LoadPipelineUIDCache(); + void ReloadPipelineUIDCache(); + + // Clears shader pointers, ensuring that now-deleted modules are not used. + void InvalidateShaderPointers(); private: // Serialized version of PipelineInfo, used when loading/saving the pipeline UID cache. From 7c5bbafdd119e3b8975d7b49411dd89e7770baab Mon Sep 17 00:00:00 2001 From: Stenzek Date: Fri, 30 Jun 2017 14:37:41 +1000 Subject: [PATCH 08/10] Vulkan: Don't save/load pipeline UID cache when shader cache is disabled --- Source/Core/VideoBackends/Vulkan/StateTracker.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp index 01b6065f3c..97ad7d4461 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp @@ -143,13 +143,16 @@ void StateTracker::ReloadPipelineUIDCache() StateTracker* this_ptr; }; + m_uid_cache.Sync(); + m_uid_cache.Close(); + // UID caches don't contain any host state, so use a single uid cache per gameid. std::string filename = g_object_cache->GetDiskCacheFileName("pipeline-uid", true, false); - PipelineInserter inserter(this); - - // OpenAndRead calls Close() first, which will flush all data to disk when reloading. - // This assertion must hold true, otherwise data corruption will result. - m_uid_cache.OpenAndRead(filename, inserter); + if (g_ActiveConfig.bShaderCache) + { + PipelineInserter inserter(this); + m_uid_cache.OpenAndRead(filename, inserter); + } } void StateTracker::AppendToPipelineUIDCache(const PipelineInfo& info) @@ -887,7 +890,7 @@ VkPipeline StateTracker::GetPipelineAndCacheUID(const PipelineInfo& info) auto result = g_object_cache->GetPipelineWithCacheResult(info); // Add to the UID cache if it is a new pipeline. - if (!result.second) + if (!result.second && g_ActiveConfig.bShaderCache) AppendToPipelineUIDCache(info); return result.first; From d01b0bf60fba2101e45cfac1e5747edcdbab5fc1 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 19 Jul 2017 20:35:17 +1000 Subject: [PATCH 09/10] VideoCommon: Move shader cache filename generation to common --- .../VideoBackends/D3D/GeometryShaderCache.cpp | 9 +--- .../VideoBackends/D3D/PixelShaderCache.cpp | 9 +--- .../VideoBackends/D3D/VertexShaderCache.cpp | 9 +--- .../VideoBackends/OGL/ProgramShaderCache.cpp | 8 +--- .../Core/VideoBackends/Vulkan/ObjectCache.cpp | 25 +++++------ .../Core/VideoBackends/Vulkan/ObjectCache.h | 3 -- .../VideoBackends/Vulkan/StateTracker.cpp | 3 +- Source/Core/VideoCommon/VideoConfig.cpp | 42 +++++++++++++++++-- Source/Core/VideoCommon/VideoConfig.h | 4 +- 9 files changed, 61 insertions(+), 51 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp index 951b4287da..90bcca4bb6 100644 --- a/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp @@ -163,14 +163,9 @@ void GeometryShaderCache::Init() void GeometryShaderCache::LoadShaderCache() { - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - - std::string cache_filename = StringFromFormat( - "%sdx11-%s-%s-gs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), - SConfig::GetInstance().GetGameID().c_str(), g_ActiveConfig.GetHostConfigFilename().c_str()); GeometryShaderCacheInserter inserter; - g_gs_disk_cache.OpenAndRead(cache_filename, inserter); + g_gs_disk_cache.OpenAndRead(g_ActiveConfig.GetDiskCacheFileName(APIType::D3D, "GS", true, true), + inserter); } void GeometryShaderCache::Reload() diff --git a/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp b/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp index d3bdce59f1..bf31114f47 100644 --- a/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp @@ -503,14 +503,9 @@ void PixelShaderCache::Init() void PixelShaderCache::LoadShaderCache() { - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - - std::string cache_filename = StringFromFormat( - "%sdx11-%s-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), - SConfig::GetInstance().GetGameID().c_str(), g_ActiveConfig.GetHostConfigFilename().c_str()); PixelShaderCacheInserter inserter; - g_ps_disk_cache.OpenAndRead(cache_filename, inserter); + g_ps_disk_cache.OpenAndRead(g_ActiveConfig.GetDiskCacheFileName(APIType::D3D, "PS", true, true), + inserter); } void PixelShaderCache::Reload() diff --git a/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp b/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp index 77aa06b2f4..4addad9326 100644 --- a/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp @@ -164,14 +164,9 @@ void VertexShaderCache::Init() void VertexShaderCache::LoadShaderCache() { - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - - std::string cache_filename = StringFromFormat( - "%sdx11-%s-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), - SConfig::GetInstance().GetGameID().c_str(), g_ActiveConfig.GetHostConfigFilename().c_str()); VertexShaderCacheInserter inserter; - g_vs_disk_cache.OpenAndRead(cache_filename, inserter); + g_vs_disk_cache.OpenAndRead(g_ActiveConfig.GetDiskCacheFileName(APIType::D3D, "VS", true, true), + inserter); } void VertexShaderCache::Reload() diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp index 3fd3573bb4..98b7695533 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp @@ -552,14 +552,8 @@ void ProgramShaderCache::LoadProgramBinaries() } else { - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - - std::string host_part = g_ActiveConfig.GetHostConfigFilename(); std::string cache_filename = - StringFromFormat("%sogl-%s-%s-shaders.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), - SConfig::GetInstance().GetGameID().c_str(), host_part.c_str()); - + g_ActiveConfig.GetDiskCacheFileName(APIType::OpenGL, "ProgramBinaries", true, true); ProgramShaderCacheInserter inserter; g_program_disk_cache.OpenAndRead(cache_filename, inserter); } diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp index d63533b7f4..15c73c5098 100644 --- a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp @@ -446,16 +446,6 @@ void ObjectCache::ClearPipelineCache() m_compute_pipeline_objects.clear(); } -std::string ObjectCache::GetDiskCacheFileName(const char* type, bool include_gameid, - bool include_host_config) -{ - return StringFromFormat( - "%svulkan-%s%s%s%s%s.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), type, - include_gameid ? "-" : "", include_gameid ? SConfig::GetInstance().GetGameID().c_str() : "", - include_host_config ? "-" : "", - include_host_config ? g_ActiveConfig.GetHostConfigFilename().c_str() : ""); -} - class PipelineCacheReadCallback : public LinearDiskCacheReader { public: @@ -482,7 +472,8 @@ bool ObjectCache::CreatePipelineCache() // Vulkan pipeline caches can be shared between games for shader compile time reduction. // This assumes that drivers don't create all pipelines in the cache on load time, only // when a lookup occurs that matches a pipeline (or pipeline data) in the cache. - m_pipeline_cache_filename = GetDiskCacheFileName("pipeline", false, true); + m_pipeline_cache_filename = + g_ActiveConfig.GetDiskCacheFileName(APIType::Vulkan, "Pipeline", false, true); VkPipelineCacheCreateInfo info = { VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType @@ -505,7 +496,8 @@ bool ObjectCache::LoadPipelineCache() { // We have to keep the pipeline cache file name around since when we save it // we delete the old one, by which time the game's unique ID is already cleared. - m_pipeline_cache_filename = GetDiskCacheFileName("pipeline", false, true); + m_pipeline_cache_filename = + g_ActiveConfig.GetDiskCacheFileName(APIType::Vulkan, "Pipeline", false, true); std::vector disk_data; LinearDiskCache disk_cache; @@ -671,15 +663,18 @@ struct ShaderCacheReader : public LinearDiskCacheReader void ObjectCache::LoadShaderCaches() { ShaderCacheReader vs_reader(m_vs_cache.shader_map); - m_vs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("vs", true, true), vs_reader); + m_vs_cache.disk_cache.OpenAndRead( + g_ActiveConfig.GetDiskCacheFileName(APIType::Vulkan, "VS", true, true), vs_reader); ShaderCacheReader ps_reader(m_ps_cache.shader_map); - m_ps_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("ps", true, true), ps_reader); + m_ps_cache.disk_cache.OpenAndRead( + g_ActiveConfig.GetDiskCacheFileName(APIType::Vulkan, "PS", true, true), ps_reader); if (g_vulkan_context->SupportsGeometryShaders()) { ShaderCacheReader gs_reader(m_gs_cache.shader_map); - m_gs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("gs", true, true), gs_reader); + m_gs_cache.disk_cache.OpenAndRead( + g_ActiveConfig.GetDiskCacheFileName(APIType::Vulkan, "GS", true, true), gs_reader); } SETSTAT(stats.numPixelShadersCreated, static_cast(m_ps_cache.shader_map.size())); diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.h b/Source/Core/VideoBackends/Vulkan/ObjectCache.h index 58476f16ab..53f0485698 100644 --- a/Source/Core/VideoBackends/Vulkan/ObjectCache.h +++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.h @@ -162,9 +162,6 @@ public: VkShaderModule GetPassthroughVertexShader() const { return m_passthrough_vertex_shader; } VkShaderModule GetScreenQuadGeometryShader() const { return m_screen_quad_geometry_shader; } VkShaderModule GetPassthroughGeometryShader() const { return m_passthrough_geometry_shader; } - // Gets the filename of the specified type of cache object (e.g. vertex shader, pipeline). - std::string GetDiskCacheFileName(const char* type, bool include_gameid, bool include_host_config); - private: bool CreatePipelineCache(); bool LoadPipelineCache(); diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp index 97ad7d4461..32ab5b8c86 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp @@ -147,7 +147,8 @@ void StateTracker::ReloadPipelineUIDCache() m_uid_cache.Close(); // UID caches don't contain any host state, so use a single uid cache per gameid. - std::string filename = g_object_cache->GetDiskCacheFileName("pipeline-uid", true, false); + std::string filename = + g_ActiveConfig.GetDiskCacheFileName(APIType::Vulkan, "PipelineUID", true, false); if (g_ActiveConfig.bShaderCache) { PipelineInserter inserter(this); diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp index 78784c5c9c..86cd38bfd8 100644 --- a/Source/Core/VideoCommon/VideoConfig.cpp +++ b/Source/Core/VideoCommon/VideoConfig.cpp @@ -4,9 +4,12 @@ #include +#include "Common/CommonPaths.h" #include "Common/CommonTypes.h" +#include "Common/FileUtil.h" #include "Common/StringUtil.h" #include "Core/Config/GraphicsSettings.h" +#include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/Movie.h" #include "VideoCommon/OnScreenDisplay.h" @@ -256,8 +259,41 @@ u32 VideoConfig::GetHostConfigBits() const return bits.bits; } -std::string VideoConfig::GetHostConfigFilename() const +std::string VideoConfig::GetDiskCacheFileName(APIType api_type, const char* type, + bool include_gameid, bool include_host_config) const { - u32 bits = GetHostConfigBits(); - return StringFromFormat("%08X", bits); + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + + std::string filename = File::GetUserPath(D_SHADERCACHE_IDX); + switch (api_type) + { + case APIType::D3D: + filename += "D3D"; + break; + case APIType::OpenGL: + filename += "OpenGL"; + break; + case APIType::Vulkan: + filename += "Vulkan"; + break; + } + + filename += '-'; + filename += type; + + if (include_gameid) + { + filename += '-'; + filename += SConfig::GetInstance().GetGameID(); + } + + if (include_host_config) + { + // We're using 18 bits, so 5 hex characters. + filename += StringFromFormat("-%05X", GetHostConfigBits()); + } + + filename += ".cache"; + return filename; } diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index dd7dd88fa4..46415463d1 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -229,7 +229,9 @@ struct VideoConfig final bool IsSSAAEnabled() const; // Host config contains the settings which can influence generated shaders. u32 GetHostConfigBits() const; - std::string GetHostConfigFilename() const; + // Gets the filename of the specified type of cache object (e.g. vertex shader, pipeline). + std::string GetDiskCacheFileName(APIType api_type, const char* type, bool include_gameid, + bool include_host_config) const; }; extern VideoConfig g_Config; From 3ea9d86faa2544b8c1c235db9456f271baf42fec Mon Sep 17 00:00:00 2001 From: Stenzek Date: Thu, 20 Jul 2017 17:10:02 +1000 Subject: [PATCH 10/10] ShaderGen: Pass host config to shader generation functions Also moves the host config checks to common. --- .../VideoBackends/D3D/GeometryShaderCache.cpp | 6 +- .../VideoBackends/D3D/PixelShaderCache.cpp | 6 +- Source/Core/VideoBackends/D3D/Render.cpp | 6 +- Source/Core/VideoBackends/D3D/Render.h | 2 - .../VideoBackends/D3D/VertexShaderCache.cpp | 6 +- Source/Core/VideoBackends/Null/ShaderCache.h | 6 +- .../VideoBackends/OGL/ProgramShaderCache.cpp | 9 +- Source/Core/VideoBackends/OGL/Render.cpp | 12 +- Source/Core/VideoBackends/OGL/Render.h | 3 - .../Core/VideoBackends/Vulkan/ObjectCache.cpp | 27 ++--- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 5 +- .../VideoBackends/Vulkan/StateTracker.cpp | 3 +- Source/Core/VideoCommon/CMakeLists.txt | 1 + Source/Core/VideoCommon/GeometryShaderGen.cpp | 64 +++++----- Source/Core/VideoCommon/GeometryShaderGen.h | 3 +- Source/Core/VideoCommon/PixelShaderGen.cpp | 17 +-- Source/Core/VideoCommon/PixelShaderGen.h | 3 +- Source/Core/VideoCommon/RenderBase.cpp | 14 +++ Source/Core/VideoCommon/RenderBase.h | 4 + Source/Core/VideoCommon/ShaderGenCommon.cpp | 75 ++++++++++++ Source/Core/VideoCommon/ShaderGenCommon.h | 35 ++++++ Source/Core/VideoCommon/VertexShaderGen.cpp | 19 +-- Source/Core/VideoCommon/VertexShaderGen.h | 3 +- Source/Core/VideoCommon/VideoCommon.vcxproj | 1 + .../VideoCommon/VideoCommon.vcxproj.filters | 3 + Source/Core/VideoCommon/VideoConfig.cpp | 109 ------------------ Source/Core/VideoCommon/VideoConfig.h | 8 -- 27 files changed, 231 insertions(+), 219 deletions(-) create mode 100644 Source/Core/VideoCommon/ShaderGenCommon.cpp diff --git a/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp index 90bcca4bb6..f6fd869b8c 100644 --- a/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp @@ -164,8 +164,7 @@ void GeometryShaderCache::Init() void GeometryShaderCache::LoadShaderCache() { GeometryShaderCacheInserter inserter; - g_gs_disk_cache.OpenAndRead(g_ActiveConfig.GetDiskCacheFileName(APIType::D3D, "GS", true, true), - inserter); + g_gs_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "GS", true, true), inserter); } void GeometryShaderCache::Reload() @@ -237,7 +236,8 @@ bool GeometryShaderCache::SetShader(u32 primitive_type) } // Need to compile a new shader - ShaderCode code = GenerateGeometryShaderCode(APIType::D3D, uid.GetUidData()); + ShaderCode code = + GenerateGeometryShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData()); D3DBlob* pbytecode; if (!D3D::CompileGeometryShader(code.GetBuffer(), &pbytecode)) diff --git a/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp b/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp index bf31114f47..6bb02b890a 100644 --- a/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/PixelShaderCache.cpp @@ -504,8 +504,7 @@ void PixelShaderCache::Init() void PixelShaderCache::LoadShaderCache() { PixelShaderCacheInserter inserter; - g_ps_disk_cache.OpenAndRead(g_ActiveConfig.GetDiskCacheFileName(APIType::D3D, "PS", true, true), - inserter); + g_ps_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "PS", true, true), inserter); } void PixelShaderCache::Reload() @@ -590,7 +589,8 @@ bool PixelShaderCache::SetShader() } // Need to compile a new shader - ShaderCode code = GeneratePixelShaderCode(APIType::D3D, uid.GetUidData()); + ShaderCode code = + GeneratePixelShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData()); D3DBlob* pbytecode; if (!D3D::CompilePixelShader(code.GetBuffer(), &pbytecode)) diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 31bd6a82bb..d3a5b78cc3 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -242,7 +242,6 @@ Renderer::Renderer() : ::Renderer(D3D::GetBackBufferWidth(), D3D::GetBackBufferH s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; s_last_fullscreen_mode = D3D::GetFullscreenState(); - m_last_host_config_bits = g_ActiveConfig.GetHostConfigBits(); g_framebuffer_manager = std::make_unique(m_target_width, m_target_height); SetupDeviceObjects(); @@ -895,14 +894,11 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, D3D11_CLEAR_DEPTH, 0.f, 0); } - u32 new_host_config_bits = g_ActiveConfig.GetHostConfigBits(); - if (new_host_config_bits != m_last_host_config_bits) + if (CheckForHostConfigChanges()) { - OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL); VertexShaderCache::Reload(); GeometryShaderCache::Reload(); PixelShaderCache::Reload(); - m_last_host_config_bits = new_host_config_bits; } // begin next frame diff --git a/Source/Core/VideoBackends/D3D/Render.h b/Source/Core/VideoBackends/D3D/Render.h index a72c9308a2..e5b429f2ab 100644 --- a/Source/Core/VideoBackends/D3D/Render.h +++ b/Source/Core/VideoBackends/D3D/Render.h @@ -64,7 +64,5 @@ public: private: void BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, u32 src_width, u32 src_height, float Gamma); - - u32 m_last_host_config_bits = 0; }; } diff --git a/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp b/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp index 4addad9326..023caedba0 100644 --- a/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/VertexShaderCache.cpp @@ -165,8 +165,7 @@ void VertexShaderCache::Init() void VertexShaderCache::LoadShaderCache() { VertexShaderCacheInserter inserter; - g_vs_disk_cache.OpenAndRead(g_ActiveConfig.GetDiskCacheFileName(APIType::D3D, "VS", true, true), - inserter); + g_vs_disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::D3D, "VS", true, true), inserter); } void VertexShaderCache::Reload() @@ -229,7 +228,8 @@ bool VertexShaderCache::SetShader() return (entry.shader != nullptr); } - ShaderCode code = GenerateVertexShaderCode(APIType::D3D, uid.GetUidData()); + ShaderCode code = + GenerateVertexShaderCode(APIType::D3D, ShaderHostConfig::GetCurrent(), uid.GetUidData()); D3DBlob* pbytecode = nullptr; D3D::CompileVertexShader(code.GetBuffer(), &pbytecode); diff --git a/Source/Core/VideoBackends/Null/ShaderCache.h b/Source/Core/VideoBackends/Null/ShaderCache.h index 8759820568..68627f9e2c 100644 --- a/Source/Core/VideoBackends/Null/ShaderCache.h +++ b/Source/Core/VideoBackends/Null/ShaderCache.h @@ -46,7 +46,7 @@ protected: } ShaderCode GenerateCode(APIType api_type, VertexShaderUid uid) override { - return GenerateVertexShaderCode(api_type, uid.GetUidData()); + return GenerateVertexShaderCode(api_type, ShaderHostConfig::GetCurrent(), uid.GetUidData()); } }; @@ -62,7 +62,7 @@ protected: } ShaderCode GenerateCode(APIType api_type, GeometryShaderUid uid) override { - return GenerateGeometryShaderCode(api_type, uid.GetUidData()); + return GenerateGeometryShaderCode(api_type, ShaderHostConfig::GetCurrent(), uid.GetUidData()); } }; @@ -78,7 +78,7 @@ protected: } ShaderCode GenerateCode(APIType api_type, PixelShaderUid uid) override { - return GeneratePixelShaderCode(api_type, uid.GetUidData()); + return GeneratePixelShaderCode(api_type, ShaderHostConfig::GetCurrent(), uid.GetUidData()); } }; diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp index 98b7695533..67e335f515 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp @@ -217,12 +217,13 @@ SHADER* ProgramShaderCache::SetShader(u32 primitive_type) last_entry = &newentry; newentry.in_cache = 0; - ShaderCode vcode = GenerateVertexShaderCode(APIType::OpenGL, uid.vuid.GetUidData()); - ShaderCode pcode = GeneratePixelShaderCode(APIType::OpenGL, uid.puid.GetUidData()); + ShaderHostConfig host_config = ShaderHostConfig::GetCurrent(); + ShaderCode vcode = GenerateVertexShaderCode(APIType::OpenGL, host_config, uid.vuid.GetUidData()); + ShaderCode pcode = GeneratePixelShaderCode(APIType::OpenGL, host_config, uid.puid.GetUidData()); ShaderCode gcode; if (g_ActiveConfig.backend_info.bSupportsGeometryShaders && !uid.guid.GetUidData()->IsPassthrough()) - gcode = GenerateGeometryShaderCode(APIType::OpenGL, uid.guid.GetUidData()); + gcode = GenerateGeometryShaderCode(APIType::OpenGL, host_config, uid.guid.GetUidData()); #if defined(_DEBUG) || defined(DEBUGFAST) if (g_ActiveConfig.iLog & CONF_SAVESHADERS) @@ -553,7 +554,7 @@ void ProgramShaderCache::LoadProgramBinaries() else { std::string cache_filename = - g_ActiveConfig.GetDiskCacheFileName(APIType::OpenGL, "ProgramBinaries", true, true); + GetDiskShaderCacheFileName(APIType::OpenGL, "ProgramBinaries", true, true); ProgramShaderCacheInserter inserter; g_program_disk_cache.OpenAndRead(cache_filename, inserter); } diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 50a3d366cc..4392da994c 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -43,6 +43,7 @@ #include "VideoCommon/PixelEngine.h" #include "VideoCommon/PixelShaderManager.h" #include "VideoCommon/RenderState.h" +#include "VideoCommon/ShaderGenCommon.h" #include "VideoCommon/VertexShaderManager.h" #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoConfig.h" @@ -664,6 +665,9 @@ Renderer::Renderer() g_Config.VerifyValidity(); UpdateActiveConfig(); + // Since we modify the config here, we need to update the last host bits, it may have changed. + m_last_host_config_bits = ShaderHostConfig::GetCurrent().bits; + OSD::AddMessage(StringFromFormat("Video Info: %s, %s, %s", g_ogl_config.gl_vendor, g_ogl_config.gl_renderer, g_ogl_config.gl_version), 5000); @@ -688,7 +692,6 @@ Renderer::Renderer() s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; - m_last_host_config_bits = g_ActiveConfig.GetHostConfigBits(); // Handle VSync on/off s_vsync = g_ActiveConfig.IsVSync(); @@ -1471,13 +1474,8 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, g_texture_cache->OnConfigChanged(g_ActiveConfig); // Invalidate shader cache when the host config changes. - u32 new_host_config_bits = g_ActiveConfig.GetHostConfigBits(); - if (new_host_config_bits != m_last_host_config_bits) - { - OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL); + if (CheckForHostConfigChanges()) ProgramShaderCache::Reload(); - m_last_host_config_bits = new_host_config_bits; - } // For testing zbuffer targets. // Renderer::SetZBufferRender(); diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index dd1de56b6a..8ec6a21e0d 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -148,8 +148,5 @@ private: std::array m_last_frame_height = {}; bool m_last_frame_exported = false; AVIDump::Frame m_last_frame_state; - - // last host config state - u32 m_last_host_config_bits = 0; }; } diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp index 15c73c5098..7f7dc93ccf 100644 --- a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp @@ -472,8 +472,7 @@ bool ObjectCache::CreatePipelineCache() // Vulkan pipeline caches can be shared between games for shader compile time reduction. // This assumes that drivers don't create all pipelines in the cache on load time, only // when a lookup occurs that matches a pipeline (or pipeline data) in the cache. - m_pipeline_cache_filename = - g_ActiveConfig.GetDiskCacheFileName(APIType::Vulkan, "Pipeline", false, true); + m_pipeline_cache_filename = GetDiskShaderCacheFileName(APIType::Vulkan, "Pipeline", false, true); VkPipelineCacheCreateInfo info = { VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType @@ -496,8 +495,7 @@ bool ObjectCache::LoadPipelineCache() { // We have to keep the pipeline cache file name around since when we save it // we delete the old one, by which time the game's unique ID is already cleared. - m_pipeline_cache_filename = - g_ActiveConfig.GetDiskCacheFileName(APIType::Vulkan, "Pipeline", false, true); + m_pipeline_cache_filename = GetDiskShaderCacheFileName(APIType::Vulkan, "Pipeline", false, true); std::vector disk_data; LinearDiskCache disk_cache; @@ -663,18 +661,18 @@ struct ShaderCacheReader : public LinearDiskCacheReader void ObjectCache::LoadShaderCaches() { ShaderCacheReader vs_reader(m_vs_cache.shader_map); - m_vs_cache.disk_cache.OpenAndRead( - g_ActiveConfig.GetDiskCacheFileName(APIType::Vulkan, "VS", true, true), vs_reader); + m_vs_cache.disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::Vulkan, "VS", true, true), + vs_reader); ShaderCacheReader ps_reader(m_ps_cache.shader_map); - m_ps_cache.disk_cache.OpenAndRead( - g_ActiveConfig.GetDiskCacheFileName(APIType::Vulkan, "PS", true, true), ps_reader); + m_ps_cache.disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::Vulkan, "PS", true, true), + ps_reader); if (g_vulkan_context->SupportsGeometryShaders()) { ShaderCacheReader gs_reader(m_gs_cache.shader_map); - m_gs_cache.disk_cache.OpenAndRead( - g_ActiveConfig.GetDiskCacheFileName(APIType::Vulkan, "GS", true, true), gs_reader); + m_gs_cache.disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::Vulkan, "GS", true, true), + gs_reader); } SETSTAT(stats.numPixelShadersCreated, static_cast(m_ps_cache.shader_map.size())); @@ -719,7 +717,8 @@ VkShaderModule ObjectCache::GetVertexShaderForUid(const VertexShaderUid& uid) // Not in the cache, so compile the shader. ShaderCompiler::SPIRVCodeVector spv; VkShaderModule module = VK_NULL_HANDLE; - ShaderCode source_code = GenerateVertexShaderCode(APIType::Vulkan, uid.GetUidData()); + ShaderCode source_code = + GenerateVertexShaderCode(APIType::Vulkan, ShaderHostConfig::GetCurrent(), uid.GetUidData()); if (ShaderCompiler::CompileVertexShader(&spv, source_code.GetBuffer().c_str(), source_code.GetBuffer().length())) { @@ -749,7 +748,8 @@ VkShaderModule ObjectCache::GetGeometryShaderForUid(const GeometryShaderUid& uid // Not in the cache, so compile the shader. ShaderCompiler::SPIRVCodeVector spv; VkShaderModule module = VK_NULL_HANDLE; - ShaderCode source_code = GenerateGeometryShaderCode(APIType::Vulkan, uid.GetUidData()); + ShaderCode source_code = + GenerateGeometryShaderCode(APIType::Vulkan, ShaderHostConfig::GetCurrent(), uid.GetUidData()); if (ShaderCompiler::CompileGeometryShader(&spv, source_code.GetBuffer().c_str(), source_code.GetBuffer().length())) { @@ -774,7 +774,8 @@ VkShaderModule ObjectCache::GetPixelShaderForUid(const PixelShaderUid& uid) // Not in the cache, so compile the shader. ShaderCompiler::SPIRVCodeVector spv; VkShaderModule module = VK_NULL_HANDLE; - ShaderCode source_code = GeneratePixelShaderCode(APIType::Vulkan, uid.GetUidData()); + ShaderCode source_code = + GeneratePixelShaderCode(APIType::Vulkan, ShaderHostConfig::GetCurrent(), uid.GetUidData()); if (ShaderCompiler::CompileFragmentShader(&spv, source_code.GetBuffer().c_str(), source_code.GetBuffer().length())) { diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index e2690ab253..599792d493 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -1126,7 +1126,6 @@ void Renderer::CheckForSurfaceChange() void Renderer::CheckForConfigChanges() { // Save the video config so we can compare against to determine which settings have changed. - u32 old_host_bits = g_ActiveConfig.GetHostConfigBits(); int old_anisotropy = g_ActiveConfig.iMaxAnisotropy; int old_aspect_ratio = g_ActiveConfig.iAspectRatio; int old_efb_scale = g_ActiveConfig.iEFBScale; @@ -1140,7 +1139,6 @@ void Renderer::CheckForConfigChanges() UpdateActiveConfig(); // Determine which (if any) settings have changed. - bool host_bits_changed = old_host_bits != g_ActiveConfig.GetHostConfigBits(); bool anisotropy_changed = old_anisotropy != g_ActiveConfig.iMaxAnisotropy; bool force_texture_filtering_changed = old_force_filtering != g_ActiveConfig.bForceFiltering; bool efb_scale_changed = old_efb_scale != g_ActiveConfig.iEFBScale; @@ -1162,9 +1160,8 @@ void Renderer::CheckForConfigChanges() // If the stereoscopy mode changed, we need to recreate the buffers as well. // SSAA changed on/off, we have to recompile shaders. // Changing stereoscopy from off<->on also requires shaders to be recompiled. - if (host_bits_changed) + if (CheckForHostConfigChanges()) { - OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL); g_command_buffer_mgr->WaitForGPUIdle(); FramebufferManager::GetInstance()->RecreateRenderPass(); FramebufferManager::GetInstance()->ResizeEFBTextures(); diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp index 32ab5b8c86..0b7833be5c 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp @@ -147,8 +147,7 @@ void StateTracker::ReloadPipelineUIDCache() m_uid_cache.Close(); // UID caches don't contain any host state, so use a single uid cache per gameid. - std::string filename = - g_ActiveConfig.GetDiskCacheFileName(APIType::Vulkan, "PipelineUID", true, false); + std::string filename = GetDiskShaderCacheFileName(APIType::Vulkan, "PipelineUID", true, false); if (g_ActiveConfig.bShaderCache) { PipelineInserter inserter(this); diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt index 9eeb9f93bb..0724212bdc 100644 --- a/Source/Core/VideoCommon/CMakeLists.txt +++ b/Source/Core/VideoCommon/CMakeLists.txt @@ -29,6 +29,7 @@ set(SRCS PostProcessing.cpp RenderBase.cpp RenderState.cpp + ShaderGenCommon.cpp Statistics.cpp TextureCacheBase.cpp TextureConfig.cpp diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp index 0e7a23b979..bb201ddb0f 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.cpp +++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp @@ -37,22 +37,25 @@ GeometryShaderUid GetGeometryShaderUid(u32 primitive_type) return out; } -static void EmitVertex(ShaderCode& out, const geometry_shader_uid_data* uid_data, - const char* vertex, APIType ApiType, bool wireframe, bool pixel_lighting, +static void EmitVertex(ShaderCode& out, const ShaderHostConfig& host_config, + const geometry_shader_uid_data* uid_data, const char* vertex, + APIType ApiType, bool wireframe, bool pixel_lighting, bool first_vertex = false); -static void EndPrimitive(ShaderCode& out, const geometry_shader_uid_data* uid_data, APIType ApiType, - bool wireframe, bool pixel_lighting); +static void EndPrimitive(ShaderCode& out, const ShaderHostConfig& host_config, + const geometry_shader_uid_data* uid_data, APIType ApiType, bool wireframe, + bool pixel_lighting); -ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid_data* uid_data) +ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& host_config, + const geometry_shader_uid_data* uid_data) { ShaderCode out; // Non-uid template parameters will write to the dummy data (=> gets optimized out) - const bool wireframe = g_ActiveConfig.bWireFrame; + const bool wireframe = host_config.wireframe; const bool pixel_lighting = g_ActiveConfig.bEnablePixelLighting; - const bool msaa = g_ActiveConfig.IsMSAAEnabled(); - const bool ssaa = g_ActiveConfig.IsSSAAEnabled(); - const bool stereo = g_ActiveConfig.IsStereoEnabled(); + const bool msaa = host_config.msaa; + const bool ssaa = host_config.ssaa; + const bool stereo = host_config.stereo; const unsigned int vertex_in = uid_data->primitive_type + 1; unsigned int vertex_out = uid_data->primitive_type == PRIMITIVE_TRIANGLES ? 3 : 4; @@ -62,7 +65,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) { // Insert layout parameters - if (g_ActiveConfig.backend_info.bSupportsGSInstancing) + if (host_config.backend_gs_instancing) { out.Write("layout(%s, invocations = %d) in;\n", primitives_ogl[uid_data->primitive_type], stereo ? 2 : 1); @@ -96,7 +99,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) { - if (g_ActiveConfig.backend_info.bSupportsGSInstancing) + if (host_config.backend_gs_instancing) out.Write("#define InstanceID gl_InvocationID\n"); out.Write("VARYING_LOCATION(0) in VertexData {\n"); @@ -125,7 +128,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid out.Write("};\n"); - if (g_ActiveConfig.backend_info.bSupportsGSInstancing) + if (host_config.backend_gs_instancing) { out.Write("[maxvertexcount(%d)]\n[instance(%d)]\n", vertex_out, stereo ? 2 : 1); out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream output, in uint " @@ -197,7 +200,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid { // If the GPU supports invocation we don't need a for loop and can simply use the // invocation identifier to determine which layer we're rendering. - if (g_ActiveConfig.backend_info.bSupportsGSInstancing) + if (host_config.backend_gs_instancing) out.Write("\tint eye = InstanceID;\n"); else out.Write("\tfor (int eye = 0; eye < 2; ++eye) {\n"); @@ -213,7 +216,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid out.Write("\tVS_OUTPUT f;\n"); AssignVSOutputMembers(out, "f", "vs[i]", uid_data->numTexGens, pixel_lighting); - if (g_ActiveConfig.backend_info.bSupportsDepthClamp && + if (host_config.backend_depth_clamp && DriverDetails::HasBug(DriverDetails::BUG_BROKEN_CLIP_DISTANCE)) { // On certain GPUs we have to consume the clip distance from the vertex shader @@ -263,8 +266,8 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid } out.Write("\t}\n"); - EmitVertex(out, uid_data, "l", ApiType, wireframe, pixel_lighting, true); - EmitVertex(out, uid_data, "r", ApiType, wireframe, pixel_lighting); + EmitVertex(out, host_config, uid_data, "l", ApiType, wireframe, pixel_lighting, true); + EmitVertex(out, host_config, uid_data, "r", ApiType, wireframe, pixel_lighting); } else if (uid_data->primitive_type == PRIMITIVE_POINTS) { @@ -292,21 +295,21 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid } out.Write("\t}\n"); - EmitVertex(out, uid_data, "ll", ApiType, wireframe, pixel_lighting, true); - EmitVertex(out, uid_data, "lr", ApiType, wireframe, pixel_lighting); - EmitVertex(out, uid_data, "ul", ApiType, wireframe, pixel_lighting); - EmitVertex(out, uid_data, "ur", ApiType, wireframe, pixel_lighting); + EmitVertex(out, host_config, uid_data, "ll", ApiType, wireframe, pixel_lighting, true); + EmitVertex(out, host_config, uid_data, "lr", ApiType, wireframe, pixel_lighting); + EmitVertex(out, host_config, uid_data, "ul", ApiType, wireframe, pixel_lighting); + EmitVertex(out, host_config, uid_data, "ur", ApiType, wireframe, pixel_lighting); } else { - EmitVertex(out, uid_data, "f", ApiType, wireframe, pixel_lighting, true); + EmitVertex(out, host_config, uid_data, "f", ApiType, wireframe, pixel_lighting, true); } out.Write("\t}\n"); - EndPrimitive(out, uid_data, ApiType, wireframe, pixel_lighting); + EndPrimitive(out, host_config, uid_data, ApiType, wireframe, pixel_lighting); - if (stereo && !g_ActiveConfig.backend_info.bSupportsGSInstancing) + if (stereo && !host_config.backend_gs_instancing) out.Write("\t}\n"); out.Write("}\n"); @@ -314,9 +317,9 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid return out; } -static void EmitVertex(ShaderCode& out, const geometry_shader_uid_data* uid_data, - const char* vertex, APIType ApiType, bool wireframe, bool pixel_lighting, - bool first_vertex) +static void EmitVertex(ShaderCode& out, const ShaderHostConfig& host_config, + const geometry_shader_uid_data* uid_data, const char* vertex, + APIType ApiType, bool wireframe, bool pixel_lighting, bool first_vertex) { if (wireframe && first_vertex) out.Write("\tif (i == 0) first = %s;\n", vertex); @@ -324,7 +327,7 @@ 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) + if (host_config.backend_depth_clamp) { out.Write("\tgl_ClipDistance[0] = %s.clipDist0;\n", vertex); out.Write("\tgl_ClipDistance[1] = %s.clipDist1;\n", vertex); @@ -349,11 +352,12 @@ static void EmitVertex(ShaderCode& out, const geometry_shader_uid_data* uid_data out.Write("\toutput.Append(ps);\n"); } -static void EndPrimitive(ShaderCode& out, const geometry_shader_uid_data* uid_data, APIType ApiType, - bool wireframe, bool pixel_lighting) +static void EndPrimitive(ShaderCode& out, const ShaderHostConfig& host_config, + const geometry_shader_uid_data* uid_data, APIType ApiType, bool wireframe, + bool pixel_lighting) { if (wireframe) - EmitVertex(out, uid_data, "first", ApiType, wireframe, pixel_lighting); + EmitVertex(out, host_config, uid_data, "first", ApiType, wireframe, pixel_lighting); if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) out.Write("\tEndPrimitive();\n"); diff --git a/Source/Core/VideoCommon/GeometryShaderGen.h b/Source/Core/VideoCommon/GeometryShaderGen.h index 8c00886bc6..58ab01f757 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.h +++ b/Source/Core/VideoCommon/GeometryShaderGen.h @@ -25,5 +25,6 @@ struct geometry_shader_uid_data typedef ShaderUid GeometryShaderUid; -ShaderCode GenerateGeometryShaderCode(APIType ApiType, const geometry_shader_uid_data* uid_data); +ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& host_config, + const geometry_shader_uid_data* uid_data); GeometryShaderUid GetGeometryShaderUid(u32 primitive_type); diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index 0dd4e868c6..fe4ef11bb0 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -345,14 +345,15 @@ static void WriteFog(ShaderCode& out, const pixel_shader_uid_data* uid_data); static void WriteColor(ShaderCode& out, const pixel_shader_uid_data* uid_data, bool use_dual_source); -ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* uid_data) +ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host_config, + const pixel_shader_uid_data* uid_data) { ShaderCode out; const bool per_pixel_lighting = g_ActiveConfig.bEnablePixelLighting; - const bool msaa = g_ActiveConfig.IsMSAAEnabled(); - const bool ssaa = g_ActiveConfig.IsSSAAEnabled(); - const bool stereo = g_ActiveConfig.IsStereoEnabled(); + const bool msaa = host_config.msaa; + const bool ssaa = host_config.ssaa; + const bool stereo = host_config.stereo; const u32 numStages = uid_data->genMode_numtevstages + 1; out.Write("//Pixel Shader for TEV stages\n"); @@ -501,7 +502,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* // Only use dual-source blending when required on drivers that don't support it very well. const bool use_dual_source = - g_ActiveConfig.backend_info.bSupportsDualSourceBlend && + host_config.backend_dual_source_blend && (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_DUAL_SOURCE_BLENDING) || uid_data->useDstAlpha); @@ -529,7 +530,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* out.Write("#define depth gl_FragDepth\n"); // We need to always use output blocks for Vulkan, but geometry shaders are also optional. - if (g_ActiveConfig.backend_info.bSupportsGeometryShaders || ApiType == APIType::Vulkan) + if (host_config.backend_geometry_shaders || ApiType == APIType::Vulkan) { out.Write("VARYING_LOCATION(0) in VertexData {\n"); GenerateVSOutputMembers(out, ApiType, uid_data->genMode_numtexgens, per_pixel_lighting, @@ -560,7 +561,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* out.Write("void main()\n{\n"); - if (g_ActiveConfig.backend_info.bSupportsGeometryShaders || ApiType == APIType::Vulkan) + if (host_config.backend_geometry_shaders || ApiType == APIType::Vulkan) { for (unsigned int i = 0; i < uid_data->genMode_numtexgens; ++i) out.Write("\tfloat3 uv%d = tex%d;\n", i, i); @@ -713,7 +714,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* out.Write("\tint zCoord = int(" I_ZSLOPE ".z + " I_ZSLOPE ".x * screenpos.x + " I_ZSLOPE ".y * screenpos.y);\n"); } - else if (!g_ActiveConfig.bFastDepthCalc) + else if (!host_config.fast_depth_calc) { // FastDepth means to trust the depth generated in perspective division. // It should be correct, but it seems not to be as accurate as required. TODO: Find out why! diff --git a/Source/Core/VideoCommon/PixelShaderGen.h b/Source/Core/VideoCommon/PixelShaderGen.h index 4ba7405cd7..23de4635e1 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.h +++ b/Source/Core/VideoCommon/PixelShaderGen.h @@ -157,5 +157,6 @@ struct pixel_shader_uid_data typedef ShaderUid PixelShaderUid; -ShaderCode GeneratePixelShaderCode(APIType ApiType, const pixel_shader_uid_data* uid_data); +ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host_config, + const pixel_shader_uid_data* uid_data); PixelShaderUid GetPixelShaderUid(); diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 62f86534c9..45e2006cb6 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -52,6 +52,7 @@ #include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/PixelShaderManager.h" #include "VideoCommon/PostProcessing.h" +#include "VideoCommon/ShaderGenCommon.h" #include "VideoCommon/Statistics.h" #include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/TextureDecoder.h" @@ -96,6 +97,8 @@ Renderer::Renderer(int backbuffer_width, int backbuffer_height) { m_aspect_wide = SConfig::GetInstance().m_wii_aspect_ratio != 0; } + + m_last_host_config_bits = ShaderHostConfig::GetCurrent().bits; } Renderer::~Renderer() @@ -315,6 +318,17 @@ void Renderer::SaveScreenshot(const std::string& filename, bool wait_for_complet } } +bool Renderer::CheckForHostConfigChanges() +{ + ShaderHostConfig new_host_config = ShaderHostConfig::GetCurrent(); + if (new_host_config.bits == m_last_host_config_bits) + return false; + + OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL); + m_last_host_config_bits = new_host_config.bits; + return true; +} + // Create On-Screen-Messages void Renderer::DrawDebugText() { diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 55ec03ee7b..4045b223aa 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -147,6 +147,8 @@ protected: std::tuple CalculateTargetScale(int x, int y) const; bool CalculateTargetSize(); + bool CheckForHostConfigChanges(); + void CheckFifoRecording(); void RecordVideoMemory(); @@ -182,6 +184,8 @@ protected: Common::Event m_surface_changed; void* m_new_surface_handle = nullptr; + u32 m_last_host_config_bits = 0; + private: void RunFrameDumps(); void ShutdownFrameDumping(); diff --git a/Source/Core/VideoCommon/ShaderGenCommon.cpp b/Source/Core/VideoCommon/ShaderGenCommon.cpp new file mode 100644 index 0000000000..58085fdafa --- /dev/null +++ b/Source/Core/VideoCommon/ShaderGenCommon.cpp @@ -0,0 +1,75 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "VideoCommon/ShaderGenCommon.h" +#include "Common/CommonPaths.h" +#include "Common/FileUtil.h" +#include "Core/ConfigManager.h" + +ShaderHostConfig ShaderHostConfig::GetCurrent() +{ + ShaderHostConfig bits = {}; + bits.msaa = g_ActiveConfig.iMultisamples > 1; + bits.ssaa = g_ActiveConfig.iMultisamples > 1 && g_ActiveConfig.bSSAA && + g_ActiveConfig.backend_info.bSupportsSSAA; + bits.stereo = g_ActiveConfig.iStereoMode > 0; + bits.wireframe = g_ActiveConfig.bWireFrame; + bits.per_pixel_lighting = g_ActiveConfig.bEnablePixelLighting; + bits.vertex_rounding = g_ActiveConfig.UseVertexRounding(); + bits.fast_depth_calc = g_ActiveConfig.bFastDepthCalc; + bits.bounding_box = g_ActiveConfig.bBBoxEnable; + bits.backend_dual_source_blend = g_ActiveConfig.backend_info.bSupportsDualSourceBlend; + bits.backend_geometry_shaders = g_ActiveConfig.backend_info.bSupportsGeometryShaders; + bits.backend_early_z = g_ActiveConfig.backend_info.bSupportsEarlyZ; + bits.backend_bbox = g_ActiveConfig.backend_info.bSupportsBBox; + bits.backend_gs_instancing = g_ActiveConfig.backend_info.bSupportsGSInstancing; + bits.backend_clip_control = g_ActiveConfig.backend_info.bSupportsClipControl; + bits.backend_ssaa = g_ActiveConfig.backend_info.bSupportsSSAA; + bits.backend_atomics = g_ActiveConfig.backend_info.bSupportsFragmentStoresAndAtomics; + bits.backend_depth_clamp = g_ActiveConfig.backend_info.bSupportsDepthClamp; + bits.backend_reversed_depth_range = g_ActiveConfig.backend_info.bSupportsReversedDepthRange; + return bits; +} + +std::string GetDiskShaderCacheFileName(APIType api_type, const char* type, bool include_gameid, + bool include_host_config) +{ + if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) + File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); + + std::string filename = File::GetUserPath(D_SHADERCACHE_IDX); + switch (api_type) + { + case APIType::D3D: + filename += "D3D"; + break; + case APIType::OpenGL: + filename += "OpenGL"; + break; + case APIType::Vulkan: + filename += "Vulkan"; + break; + default: + break; + } + + filename += '-'; + filename += type; + + if (include_gameid) + { + filename += '-'; + filename += SConfig::GetInstance().GetGameID(); + } + + if (include_host_config) + { + // We're using 18 bits, so 5 hex characters. + ShaderHostConfig host_config = ShaderHostConfig::GetCurrent(); + filename += StringFromFormat("-%05X", host_config.bits); + } + + filename += ".cache"; + return filename; +} diff --git a/Source/Core/VideoCommon/ShaderGenCommon.h b/Source/Core/VideoCommon/ShaderGenCommon.h index f70d6288e6..5750e58c3e 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/ShaderGenCommon.h @@ -151,6 +151,41 @@ private: std::vector constant_usage; // TODO: Is vector appropriate here? }; +// Host config contains the settings which can influence generated shaders. +union ShaderHostConfig +{ + u32 bits; + + struct + { + u32 msaa : 1; + u32 ssaa : 1; + u32 stereo : 1; + u32 wireframe : 1; + u32 per_pixel_lighting : 1; + u32 vertex_rounding : 1; + u32 fast_depth_calc : 1; + u32 bounding_box : 1; + u32 backend_dual_source_blend : 1; + u32 backend_geometry_shaders : 1; + u32 backend_early_z : 1; + u32 backend_bbox : 1; + u32 backend_gs_instancing : 1; + u32 backend_clip_control : 1; + u32 backend_ssaa : 1; + u32 backend_atomics : 1; + u32 backend_depth_clamp : 1; + u32 backend_reversed_depth_range : 1; + u32 pad : 14; + }; + + static ShaderHostConfig GetCurrent(); +}; + +// Gets the filename of the specified type of cache object (e.g. vertex shader, pipeline). +std::string GetDiskShaderCacheFileName(APIType api_type, const char* type, bool include_gameid, + bool include_host_config); + template inline void DefineOutputMember(T& object, APIType api_type, const char* qualifier, const char* type, const char* name, int var_index, const char* semantic = "", diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index a69245bda7..2ee9532254 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -76,14 +76,15 @@ VertexShaderUid GetVertexShaderUid() return out; } -ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_data* uid_data) +ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& host_config, + const vertex_shader_uid_data* uid_data) { ShaderCode out; const bool per_pixel_lighting = g_ActiveConfig.bEnablePixelLighting; - const bool msaa = g_ActiveConfig.IsMSAAEnabled(); - const bool ssaa = g_ActiveConfig.IsSSAAEnabled(); - const bool vertex_rounding = g_ActiveConfig.UseVertexRounding(); + const bool msaa = host_config.msaa; + const bool ssaa = host_config.ssaa; + const bool vertex_rounding = host_config.vertex_rounding; out.Write("%s", s_lighting_struct); @@ -128,7 +129,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da } // We need to always use output blocks for Vulkan, but geometry shaders are also optional. - if (g_ActiveConfig.backend_info.bSupportsGeometryShaders || api_type == APIType::Vulkan) + if (host_config.backend_geometry_shaders || api_type == APIType::Vulkan) { out.Write("VARYING_LOCATION(0) out VertexData {\n"); GenerateVSOutputMembers(out, api_type, uid_data->numTexGens, per_pixel_lighting, @@ -415,7 +416,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da // 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 if // necessary. - if (g_ActiveConfig.backend_info.bSupportsDepthClamp) + if (host_config.backend_depth_clamp) { // 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, which matches the console -1..0 range. @@ -440,7 +441,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da out.Write("o.pos.z = o.pos.w * " I_PIXELCENTERCORRECTION ".w - " "o.pos.z * " I_PIXELCENTERCORRECTION ".z;\n"); - if (!g_ActiveConfig.backend_info.bSupportsClipControl) + if (!host_config.backend_clip_control) { // 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 @@ -485,7 +486,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da if (api_type == APIType::OpenGL || api_type == APIType::Vulkan) { - if (g_ActiveConfig.backend_info.bSupportsGeometryShaders || api_type == APIType::Vulkan) + if (host_config.backend_geometry_shaders || api_type == APIType::Vulkan) { AssignVSOutputMembers(out, "vs", "o", uid_data->numTexGens, per_pixel_lighting); } @@ -505,7 +506,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_da out.Write("colors_1 = o.colors_1;\n"); } - if (g_ActiveConfig.backend_info.bSupportsDepthClamp) + if (host_config.backend_depth_clamp) { out.Write("gl_ClipDistance[0] = o.clipDist0;\n"); out.Write("gl_ClipDistance[1] = o.clipDist1;\n"); diff --git a/Source/Core/VideoCommon/VertexShaderGen.h b/Source/Core/VideoCommon/VertexShaderGen.h index 8c6f14f0e6..a93358d923 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.h +++ b/Source/Core/VideoCommon/VertexShaderGen.h @@ -65,4 +65,5 @@ struct vertex_shader_uid_data typedef ShaderUid VertexShaderUid; VertexShaderUid GetVertexShaderUid(); -ShaderCode GenerateVertexShaderCode(APIType api_type, const vertex_shader_uid_data* uid_data); +ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& host_config, + const vertex_shader_uid_data* uid_data); diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj b/Source/Core/VideoCommon/VideoCommon.vcxproj index 97adb25ac6..e33ccd9d7f 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj @@ -65,6 +65,7 @@ + diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters index a9f632493e..f4ec59eb1d 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters @@ -173,6 +173,9 @@ Base + + Shader Generators + diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp index 86cd38bfd8..355d2486b4 100644 --- a/Source/Core/VideoCommon/VideoConfig.cpp +++ b/Source/Core/VideoCommon/VideoConfig.cpp @@ -4,12 +4,9 @@ #include -#include "Common/CommonPaths.h" #include "Common/CommonTypes.h" -#include "Common/FileUtil.h" #include "Common/StringUtil.h" #include "Core/Config/GraphicsSettings.h" -#include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/Movie.h" #include "VideoCommon/OnScreenDisplay.h" @@ -191,109 +188,3 @@ bool VideoConfig::IsVSync() { return bVSync && !Core::GetIsThrottlerTempDisabled(); } - -bool VideoConfig::IsStereoEnabled() const -{ - return iStereoMode > 0; -} - -bool VideoConfig::IsMSAAEnabled() const -{ - return iMultisamples > 1; -} - -bool VideoConfig::IsSSAAEnabled() const -{ - return iMultisamples > 1 && bSSAA && backend_info.bSupportsSSAA; -} - -union HostConfigBits -{ - u32 bits; - - struct - { - u32 msaa : 1; - u32 ssaa : 1; - u32 stereo : 1; - u32 wireframe : 1; - u32 per_pixel_lighting : 1; - u32 vertex_rounding : 1; - u32 fast_depth_calc : 1; - u32 bounding_box : 1; - u32 backend_dual_source_blend : 1; - u32 backend_geometry_shaders : 1; - u32 backend_early_z : 1; - u32 backend_bbox : 1; - u32 backend_gs_instancing : 1; - u32 backend_clip_control : 1; - u32 backend_ssaa : 1; - u32 backend_atomics : 1; - u32 backend_depth_clamp : 1; - u32 backend_reversed_depth_range : 1; - u32 pad : 14; - }; -}; - -u32 VideoConfig::GetHostConfigBits() const -{ - HostConfigBits bits = {}; - bits.msaa = IsMSAAEnabled(); - bits.ssaa = IsSSAAEnabled(); - bits.stereo = IsStereoEnabled(); - bits.wireframe = bWireFrame; - bits.per_pixel_lighting = bEnablePixelLighting; - bits.vertex_rounding = UseVertexRounding(); - bits.fast_depth_calc = bFastDepthCalc; - bits.bounding_box = bBBoxEnable; - bits.backend_dual_source_blend = backend_info.bSupportsDualSourceBlend; - bits.backend_geometry_shaders = backend_info.bSupportsGeometryShaders; - bits.backend_early_z = backend_info.bSupportsEarlyZ; - bits.backend_bbox = backend_info.bSupportsBBox; - bits.backend_gs_instancing = backend_info.bSupportsGSInstancing; - bits.backend_clip_control = backend_info.bSupportsClipControl; - bits.backend_ssaa = backend_info.bSupportsSSAA; - bits.backend_atomics = backend_info.bSupportsFragmentStoresAndAtomics; - bits.backend_depth_clamp = backend_info.bSupportsDepthClamp; - bits.backend_reversed_depth_range = backend_info.bSupportsReversedDepthRange; - return bits.bits; -} - -std::string VideoConfig::GetDiskCacheFileName(APIType api_type, const char* type, - bool include_gameid, bool include_host_config) const -{ - if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX))) - File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX)); - - std::string filename = File::GetUserPath(D_SHADERCACHE_IDX); - switch (api_type) - { - case APIType::D3D: - filename += "D3D"; - break; - case APIType::OpenGL: - filename += "OpenGL"; - break; - case APIType::Vulkan: - filename += "Vulkan"; - break; - } - - filename += '-'; - filename += type; - - if (include_gameid) - { - filename += '-'; - filename += SConfig::GetInstance().GetGameID(); - } - - if (include_host_config) - { - // We're using 18 bits, so 5 hex characters. - filename += StringFromFormat("-%05X", GetHostConfigBits()); - } - - filename += ".cache"; - return filename; -} diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index 46415463d1..1216bcc431 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -224,14 +224,6 @@ struct VideoConfig final return backend_info.bSupportsGPUTextureDecoding && bEnableGPUTextureDecoding; } bool UseVertexRounding() const { return bVertexRounding && iEFBScale != SCALE_1X; } - bool IsStereoEnabled() const; - bool IsMSAAEnabled() const; - bool IsSSAAEnabled() const; - // Host config contains the settings which can influence generated shaders. - u32 GetHostConfigBits() const; - // Gets the filename of the specified type of cache object (e.g. vertex shader, pipeline). - std::string GetDiskCacheFileName(APIType api_type, const char* type, bool include_gameid, - bool include_host_config) const; }; extern VideoConfig g_Config;