From 3847e226abd7e69d42796d47a61cfd539a430438 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 4 Apr 2017 23:53:03 +1000 Subject: [PATCH 1/3] TextureConversionShader: Consider source format of EFB for EFB2RAM Currently, we use the alpha channel from the EFB even if the current format does not include an alpha channel. Now, the alpha channel is set to 1 if the format does not have an alpha channel, as well as truncating to 5/6 bits per channel. This matches the EFB-to-texture behavior. --- .../VideoCommon/TextureConversionShader.cpp | 226 ++++++++++-------- .../VideoCommon/TextureConversionShader.h | 8 +- Source/Core/VideoCommon/TextureDecoder.h | 17 ++ 3 files changed, 150 insertions(+), 101 deletions(-) diff --git a/Source/Core/VideoCommon/TextureConversionShader.cpp b/Source/Core/VideoCommon/TextureConversionShader.cpp index 833d2a7840..d22ade97c7 100644 --- a/Source/Core/VideoCommon/TextureConversionShader.cpp +++ b/Source/Core/VideoCommon/TextureConversionShader.cpp @@ -14,7 +14,6 @@ #include "Common/MsgHandler.h" #include "VideoCommon/RenderBase.h" #include "VideoCommon/TextureConversionShader.h" -#include "VideoCommon/TextureDecoder.h" #include "VideoCommon/VideoCommon.h" #define WRITE p += sprintf @@ -79,6 +78,11 @@ u16 GetEncodedSampleCount(u32 format) } } +static bool EFBFormatHasAlpha(u32 format) +{ + return format == PEControl::RGBA6_Z24; +} + // block dimensions : widthStride, heightStride // texture dims : width, height, x offset, y offset static void WriteSwizzler(char*& p, u32 format, APIType ApiType) @@ -162,7 +166,7 @@ static void WriteSwizzler(char*& p, u32 format, APIType ApiType) } static void WriteSampleColor(char*& p, const char* colorComp, const char* dest, int xoffset, - APIType ApiType, bool depth = false) + APIType ApiType, const EFBCopyFormat& format, bool depth) { if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) { @@ -181,6 +185,25 @@ static void WriteSampleColor(char*& p, const char* colorComp, const char* dest, if (depth) WRITE(p, " %s = 1.0 - %s;\n", dest, dest); } + + // Truncate 8-bits to 5/6-bits per channel. + switch (format.efb_format) + { + case PEControl::RGBA6_Z24: + WRITE(p, " %s = floor(%s * 63.0) / 63.0;\n", dest, dest); + break; + + case PEControl::RGB565_Z16: + WRITE( + p, + " %s = floor(%s * float4(31.0, 63.0, 31.0, 1.0).%s) / float4(31.0, 63.0, 31.0, 1.0).%s;\n", + dest, dest, colorComp, colorComp); + break; + } + + // Alpha channel is set to 1 in the copy if the EFB does not have an alpha channel. + if (std::strchr(colorComp, 'a') && !EFBFormatHasAlpha(format.efb_format)) + WRITE(p, " %s.a = 1.0;\n", dest); } static void WriteColorToIntensity(char*& p, const char* src, const char* dest) @@ -206,21 +229,21 @@ static void WriteEncoderEnd(char*& p) IntensityConstantAdded = false; } -static void WriteI8Encoder(char*& p, APIType ApiType) +static void WriteI8Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format) { WriteSwizzler(p, GX_TF_I8, ApiType); WRITE(p, " float3 texSample;\n"); - WriteSampleColor(p, "rgb", "texSample", 0, ApiType); + WriteSampleColor(p, "rgb", "texSample", 0, ApiType, format, false); WriteColorToIntensity(p, "texSample", "ocol0.b"); - WriteSampleColor(p, "rgb", "texSample", 1, ApiType); + WriteSampleColor(p, "rgb", "texSample", 1, ApiType, format, false); WriteColorToIntensity(p, "texSample", "ocol0.g"); - WriteSampleColor(p, "rgb", "texSample", 2, ApiType); + WriteSampleColor(p, "rgb", "texSample", 2, ApiType, format, false); WriteColorToIntensity(p, "texSample", "ocol0.r"); - WriteSampleColor(p, "rgb", "texSample", 3, ApiType); + WriteSampleColor(p, "rgb", "texSample", 3, ApiType, format, false); WriteColorToIntensity(p, "texSample", "ocol0.a"); WRITE(p, " ocol0.rgba += IntensityConst.aaaa;\n"); // see WriteColorToIntensity @@ -228,35 +251,35 @@ static void WriteI8Encoder(char*& p, APIType ApiType) WriteEncoderEnd(p); } -static void WriteI4Encoder(char*& p, APIType ApiType) +static void WriteI4Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format) { WriteSwizzler(p, GX_TF_I4, ApiType); WRITE(p, " float3 texSample;\n"); WRITE(p, " float4 color0;\n"); WRITE(p, " float4 color1;\n"); - WriteSampleColor(p, "rgb", "texSample", 0, ApiType); + WriteSampleColor(p, "rgb", "texSample", 0, ApiType, format, false); WriteColorToIntensity(p, "texSample", "color0.b"); - WriteSampleColor(p, "rgb", "texSample", 1, ApiType); + WriteSampleColor(p, "rgb", "texSample", 1, ApiType, format, false); WriteColorToIntensity(p, "texSample", "color1.b"); - WriteSampleColor(p, "rgb", "texSample", 2, ApiType); + WriteSampleColor(p, "rgb", "texSample", 2, ApiType, format, false); WriteColorToIntensity(p, "texSample", "color0.g"); - WriteSampleColor(p, "rgb", "texSample", 3, ApiType); + WriteSampleColor(p, "rgb", "texSample", 3, ApiType, format, false); WriteColorToIntensity(p, "texSample", "color1.g"); - WriteSampleColor(p, "rgb", "texSample", 4, ApiType); + WriteSampleColor(p, "rgb", "texSample", 4, ApiType, format, false); WriteColorToIntensity(p, "texSample", "color0.r"); - WriteSampleColor(p, "rgb", "texSample", 5, ApiType); + WriteSampleColor(p, "rgb", "texSample", 5, ApiType, format, false); WriteColorToIntensity(p, "texSample", "color1.r"); - WriteSampleColor(p, "rgb", "texSample", 6, ApiType); + WriteSampleColor(p, "rgb", "texSample", 6, ApiType, format, false); WriteColorToIntensity(p, "texSample", "color0.a"); - WriteSampleColor(p, "rgb", "texSample", 7, ApiType); + WriteSampleColor(p, "rgb", "texSample", 7, ApiType, format, false); WriteColorToIntensity(p, "texSample", "color1.a"); WRITE(p, " color0.rgba += IntensityConst.aaaa;\n"); @@ -269,16 +292,16 @@ static void WriteI4Encoder(char*& p, APIType ApiType) WriteEncoderEnd(p); } -static void WriteIA8Encoder(char*& p, APIType ApiType) +static void WriteIA8Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format) { WriteSwizzler(p, GX_TF_IA8, ApiType); WRITE(p, " float4 texSample;\n"); - WriteSampleColor(p, "rgba", "texSample", 0, ApiType); + WriteSampleColor(p, "rgba", "texSample", 0, ApiType, format, false); WRITE(p, " ocol0.b = texSample.a;\n"); WriteColorToIntensity(p, "texSample", "ocol0.g"); - WriteSampleColor(p, "rgba", "texSample", 1, ApiType); + WriteSampleColor(p, "rgba", "texSample", 1, ApiType, format, false); WRITE(p, " ocol0.r = texSample.a;\n"); WriteColorToIntensity(p, "texSample", "ocol0.a"); @@ -287,26 +310,26 @@ static void WriteIA8Encoder(char*& p, APIType ApiType) WriteEncoderEnd(p); } -static void WriteIA4Encoder(char*& p, APIType ApiType) +static void WriteIA4Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format) { WriteSwizzler(p, GX_TF_IA4, ApiType); WRITE(p, " float4 texSample;\n"); WRITE(p, " float4 color0;\n"); WRITE(p, " float4 color1;\n"); - WriteSampleColor(p, "rgba", "texSample", 0, ApiType); + WriteSampleColor(p, "rgba", "texSample", 0, ApiType, format, false); WRITE(p, " color0.b = texSample.a;\n"); WriteColorToIntensity(p, "texSample", "color1.b"); - WriteSampleColor(p, "rgba", "texSample", 1, ApiType); + WriteSampleColor(p, "rgba", "texSample", 1, ApiType, format, false); WRITE(p, " color0.g = texSample.a;\n"); WriteColorToIntensity(p, "texSample", "color1.g"); - WriteSampleColor(p, "rgba", "texSample", 2, ApiType); + WriteSampleColor(p, "rgba", "texSample", 2, ApiType, format, false); WRITE(p, " color0.r = texSample.a;\n"); WriteColorToIntensity(p, "texSample", "color1.r"); - WriteSampleColor(p, "rgba", "texSample", 3, ApiType); + WriteSampleColor(p, "rgba", "texSample", 3, ApiType, format, false); WRITE(p, " color0.a = texSample.a;\n"); WriteColorToIntensity(p, "texSample", "color1.a"); @@ -319,12 +342,12 @@ static void WriteIA4Encoder(char*& p, APIType ApiType) WriteEncoderEnd(p); } -static void WriteRGB565Encoder(char*& p, APIType ApiType) +static void WriteRGB565Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format) { WriteSwizzler(p, GX_TF_RGB565, ApiType); - WriteSampleColor(p, "rgb", "float3 texSample0", 0, ApiType); - WriteSampleColor(p, "rgb", "float3 texSample1", 1, ApiType); + WriteSampleColor(p, "rgb", "float3 texSample0", 0, ApiType, format, false); + WriteSampleColor(p, "rgb", "float3 texSample1", 1, ApiType, format, false); WRITE(p, " float2 texRs = float2(texSample0.r, texSample1.r);\n"); WRITE(p, " float2 texGs = float2(texSample0.g, texSample1.g);\n"); WRITE(p, " float2 texBs = float2(texSample0.b, texSample1.b);\n"); @@ -342,7 +365,7 @@ static void WriteRGB565Encoder(char*& p, APIType ApiType) WriteEncoderEnd(p); } -static void WriteRGB5A3Encoder(char*& p, APIType ApiType) +static void WriteRGB5A3Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format) { WriteSwizzler(p, GX_TF_RGB5A3, ApiType); @@ -351,7 +374,7 @@ static void WriteRGB5A3Encoder(char*& p, APIType ApiType) WRITE(p, " float gUpper;\n"); WRITE(p, " float gLower;\n"); - WriteSampleColor(p, "rgba", "texSample", 0, ApiType); + WriteSampleColor(p, "rgba", "texSample", 0, ApiType, format, false); // 0.8784 = 224 / 255 which is the maximum alpha value that can be represented in 3 bits WRITE(p, "if(texSample.a > 0.878f) {\n"); @@ -377,7 +400,8 @@ static void WriteRGB5A3Encoder(char*& p, APIType ApiType) WRITE(p, "}\n"); - WriteSampleColor(p, "rgba", "texSample", 1, ApiType); + WriteSampleColor(p, "rgba", "texSample", 1, ApiType, format, false); + WRITE(p, " texSample.a = 1.0;\n"); WRITE(p, "if(texSample.a > 0.878f) {\n"); @@ -406,7 +430,7 @@ static void WriteRGB5A3Encoder(char*& p, APIType ApiType) WriteEncoderEnd(p); } -static void WriteRGBA8Encoder(char*& p, APIType ApiType) +static void WriteRGBA8Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format) { WriteSwizzler(p, GX_TF_RGBA8, ApiType); @@ -414,13 +438,13 @@ static void WriteRGBA8Encoder(char*& p, APIType ApiType) WRITE(p, " float4 color0;\n"); WRITE(p, " float4 color1;\n"); - WriteSampleColor(p, "rgba", "texSample", 0, ApiType); + WriteSampleColor(p, "rgba", "texSample", 0, ApiType, format, false); WRITE(p, " color0.b = texSample.a;\n"); WRITE(p, " color0.g = texSample.r;\n"); WRITE(p, " color1.b = texSample.g;\n"); WRITE(p, " color1.g = texSample.b;\n"); - WriteSampleColor(p, "rgba", "texSample", 1, ApiType); + WriteSampleColor(p, "rgba", "texSample", 1, ApiType, format, false); WRITE(p, " color0.r = texSample.a;\n"); WRITE(p, " color0.a = texSample.r;\n"); WRITE(p, " color1.r = texSample.g;\n"); @@ -431,20 +455,21 @@ static void WriteRGBA8Encoder(char*& p, APIType ApiType) WriteEncoderEnd(p); } -static void WriteC4Encoder(char*& p, const char* comp, APIType ApiType, bool depth = false) +static void WriteC4Encoder(char*& p, const char* comp, APIType ApiType, const EFBCopyFormat& format, + bool depth) { WriteSwizzler(p, GX_CTF_R4, ApiType); WRITE(p, " float4 color0;\n"); WRITE(p, " float4 color1;\n"); - WriteSampleColor(p, comp, "color0.b", 0, ApiType, depth); - WriteSampleColor(p, comp, "color1.b", 1, ApiType, depth); - WriteSampleColor(p, comp, "color0.g", 2, ApiType, depth); - WriteSampleColor(p, comp, "color1.g", 3, ApiType, depth); - WriteSampleColor(p, comp, "color0.r", 4, ApiType, depth); - WriteSampleColor(p, comp, "color1.r", 5, ApiType, depth); - WriteSampleColor(p, comp, "color0.a", 6, ApiType, depth); - WriteSampleColor(p, comp, "color1.a", 7, ApiType, depth); + WriteSampleColor(p, comp, "color0.b", 0, ApiType, format, depth); + WriteSampleColor(p, comp, "color1.b", 1, ApiType, format, depth); + WriteSampleColor(p, comp, "color0.g", 2, ApiType, format, depth); + WriteSampleColor(p, comp, "color1.g", 3, ApiType, format, depth); + WriteSampleColor(p, comp, "color0.r", 4, ApiType, format, depth); + WriteSampleColor(p, comp, "color1.r", 5, ApiType, format, depth); + WriteSampleColor(p, comp, "color0.a", 6, ApiType, format, depth); + WriteSampleColor(p, comp, "color1.a", 7, ApiType, format, depth); WriteToBitDepth(p, 4, "color0", "color0"); WriteToBitDepth(p, 4, "color1", "color1"); @@ -453,38 +478,40 @@ static void WriteC4Encoder(char*& p, const char* comp, APIType ApiType, bool dep WriteEncoderEnd(p); } -static void WriteC8Encoder(char*& p, const char* comp, APIType ApiType, bool depth = false) +static void WriteC8Encoder(char*& p, const char* comp, APIType ApiType, const EFBCopyFormat& format, + bool depth) { WriteSwizzler(p, GX_CTF_R8, ApiType); - WriteSampleColor(p, comp, "ocol0.b", 0, ApiType, depth); - WriteSampleColor(p, comp, "ocol0.g", 1, ApiType, depth); - WriteSampleColor(p, comp, "ocol0.r", 2, ApiType, depth); - WriteSampleColor(p, comp, "ocol0.a", 3, ApiType, depth); + WriteSampleColor(p, comp, "ocol0.b", 0, ApiType, format, depth); + WriteSampleColor(p, comp, "ocol0.g", 1, ApiType, format, depth); + WriteSampleColor(p, comp, "ocol0.r", 2, ApiType, format, depth); + WriteSampleColor(p, comp, "ocol0.a", 3, ApiType, format, depth); WriteEncoderEnd(p); } -static void WriteCC4Encoder(char*& p, const char* comp, APIType ApiType) +static void WriteCC4Encoder(char*& p, const char* comp, APIType ApiType, + const EFBCopyFormat& format) { WriteSwizzler(p, GX_CTF_RA4, ApiType); WRITE(p, " float2 texSample;\n"); WRITE(p, " float4 color0;\n"); WRITE(p, " float4 color1;\n"); - WriteSampleColor(p, comp, "texSample", 0, ApiType); + WriteSampleColor(p, comp, "texSample", 0, ApiType, format, false); WRITE(p, " color0.b = texSample.x;\n"); WRITE(p, " color1.b = texSample.y;\n"); - WriteSampleColor(p, comp, "texSample", 1, ApiType); + WriteSampleColor(p, comp, "texSample", 1, ApiType, format, false); WRITE(p, " color0.g = texSample.x;\n"); WRITE(p, " color1.g = texSample.y;\n"); - WriteSampleColor(p, comp, "texSample", 2, ApiType); + WriteSampleColor(p, comp, "texSample", 2, ApiType, format, false); WRITE(p, " color0.r = texSample.x;\n"); WRITE(p, " color1.r = texSample.y;\n"); - WriteSampleColor(p, comp, "texSample", 3, ApiType); + WriteSampleColor(p, comp, "texSample", 3, ApiType, format, false); WRITE(p, " color0.a = texSample.x;\n"); WRITE(p, " color1.a = texSample.y;\n"); @@ -495,38 +522,40 @@ static void WriteCC4Encoder(char*& p, const char* comp, APIType ApiType) WriteEncoderEnd(p); } -static void WriteCC8Encoder(char*& p, const char* comp, APIType ApiType) +static void WriteCC8Encoder(char*& p, const char* comp, APIType ApiType, + const EFBCopyFormat& format) { WriteSwizzler(p, GX_CTF_RA8, ApiType); - WriteSampleColor(p, comp, "ocol0.bg", 0, ApiType); - WriteSampleColor(p, comp, "ocol0.ra", 1, ApiType); + WriteSampleColor(p, comp, "ocol0.bg", 0, ApiType, format, false); + WriteSampleColor(p, comp, "ocol0.ra", 1, ApiType, format, false); WriteEncoderEnd(p); } -static void WriteZ8Encoder(char*& p, const char* multiplier, APIType ApiType) +static void WriteZ8Encoder(char*& p, const char* multiplier, APIType ApiType, + const EFBCopyFormat& format) { WriteSwizzler(p, GX_CTF_Z8M, ApiType); WRITE(p, " float depth;\n"); - WriteSampleColor(p, "r", "depth", 0, ApiType, true); + WriteSampleColor(p, "r", "depth", 0, ApiType, format, true); WRITE(p, "ocol0.b = frac(depth * %s);\n", multiplier); - WriteSampleColor(p, "r", "depth", 1, ApiType, true); + WriteSampleColor(p, "r", "depth", 1, ApiType, format, true); WRITE(p, "ocol0.g = frac(depth * %s);\n", multiplier); - WriteSampleColor(p, "r", "depth", 2, ApiType, true); + WriteSampleColor(p, "r", "depth", 2, ApiType, format, true); WRITE(p, "ocol0.r = frac(depth * %s);\n", multiplier); - WriteSampleColor(p, "r", "depth", 3, ApiType, true); + WriteSampleColor(p, "r", "depth", 3, ApiType, format, true); WRITE(p, "ocol0.a = frac(depth * %s);\n", multiplier); WriteEncoderEnd(p); } -static void WriteZ16Encoder(char*& p, APIType ApiType) +static void WriteZ16Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format) { WriteSwizzler(p, GX_TF_Z16, ApiType); @@ -535,7 +564,7 @@ static void WriteZ16Encoder(char*& p, APIType ApiType) // byte order is reversed - WriteSampleColor(p, "r", "depth", 0, ApiType, true); + WriteSampleColor(p, "r", "depth", 0, ApiType, format, true); WRITE(p, " depth *= 16777216.0;\n"); WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n"); @@ -545,7 +574,7 @@ static void WriteZ16Encoder(char*& p, APIType ApiType) WRITE(p, " ocol0.b = expanded.g / 255.0;\n"); WRITE(p, " ocol0.g = expanded.r / 255.0;\n"); - WriteSampleColor(p, "r", "depth", 1, ApiType, true); + WriteSampleColor(p, "r", "depth", 1, ApiType, format, true); WRITE(p, " depth *= 16777216.0;\n"); WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n"); @@ -558,7 +587,7 @@ static void WriteZ16Encoder(char*& p, APIType ApiType) WriteEncoderEnd(p); } -static void WriteZ16LEncoder(char*& p, APIType ApiType) +static void WriteZ16LEncoder(char*& p, APIType ApiType, const EFBCopyFormat& format) { WriteSwizzler(p, GX_CTF_Z16L, ApiType); @@ -567,7 +596,7 @@ static void WriteZ16LEncoder(char*& p, APIType ApiType) // byte order is reversed - WriteSampleColor(p, "r", "depth", 0, ApiType, true); + WriteSampleColor(p, "r", "depth", 0, ApiType, format, true); WRITE(p, " depth *= 16777216.0;\n"); WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n"); @@ -579,7 +608,7 @@ static void WriteZ16LEncoder(char*& p, APIType ApiType) WRITE(p, " ocol0.b = expanded.b / 255.0;\n"); WRITE(p, " ocol0.g = expanded.g / 255.0;\n"); - WriteSampleColor(p, "r", "depth", 1, ApiType, true); + WriteSampleColor(p, "r", "depth", 1, ApiType, format, true); WRITE(p, " depth *= 16777216.0;\n"); WRITE(p, " expanded.r = floor(depth / (256.0 * 256.0));\n"); @@ -594,7 +623,7 @@ static void WriteZ16LEncoder(char*& p, APIType ApiType) WriteEncoderEnd(p); } -static void WriteZ24Encoder(char*& p, APIType ApiType) +static void WriteZ24Encoder(char*& p, APIType ApiType, const EFBCopyFormat& format) { WriteSwizzler(p, GX_TF_Z24X8, ApiType); @@ -603,8 +632,8 @@ static void WriteZ24Encoder(char*& p, APIType ApiType) WRITE(p, " float3 expanded0;\n"); WRITE(p, " float3 expanded1;\n"); - WriteSampleColor(p, "r", "depth0", 0, ApiType, true); - WriteSampleColor(p, "r", "depth1", 1, ApiType, true); + WriteSampleColor(p, "r", "depth0", 0, ApiType, format, true); + WriteSampleColor(p, "r", "depth1", 1, ApiType, format, true); for (int i = 0; i < 2; i++) { @@ -634,87 +663,87 @@ static void WriteZ24Encoder(char*& p, APIType ApiType) WriteEncoderEnd(p); } -const char* GenerateEncodingShader(u32 format, APIType ApiType) +const char* GenerateEncodingShader(const EFBCopyFormat& format, APIType api_type) { text[sizeof(text) - 1] = 0x7C; // canary char* p = text; - switch (format) + switch (format.copy_format) { case GX_TF_I4: - WriteI4Encoder(p, ApiType); + WriteI4Encoder(p, api_type, format); break; case GX_TF_I8: - WriteI8Encoder(p, ApiType); + WriteI8Encoder(p, api_type, format); break; case GX_TF_IA4: - WriteIA4Encoder(p, ApiType); + WriteIA4Encoder(p, api_type, format); break; case GX_TF_IA8: - WriteIA8Encoder(p, ApiType); + WriteIA8Encoder(p, api_type, format); break; case GX_TF_RGB565: - WriteRGB565Encoder(p, ApiType); + WriteRGB565Encoder(p, api_type, format); break; case GX_TF_RGB5A3: - WriteRGB5A3Encoder(p, ApiType); + WriteRGB5A3Encoder(p, api_type, format); break; case GX_TF_RGBA8: - WriteRGBA8Encoder(p, ApiType); + WriteRGBA8Encoder(p, api_type, format); break; case GX_CTF_R4: - WriteC4Encoder(p, "r", ApiType); + WriteC4Encoder(p, "r", api_type, format, false); break; case GX_CTF_RA4: - WriteCC4Encoder(p, "ar", ApiType); + WriteCC4Encoder(p, "ar", api_type, format); break; case GX_CTF_RA8: - WriteCC8Encoder(p, "ar", ApiType); + WriteCC8Encoder(p, "ar", api_type, format); break; case GX_CTF_A8: - WriteC8Encoder(p, "a", ApiType); + WriteC8Encoder(p, "a", api_type, format, false); break; case GX_CTF_R8: - WriteC8Encoder(p, "r", ApiType); + WriteC8Encoder(p, "r", api_type, format, false); break; case GX_CTF_G8: - WriteC8Encoder(p, "g", ApiType); + WriteC8Encoder(p, "g", api_type, format, false); break; case GX_CTF_B8: - WriteC8Encoder(p, "b", ApiType); + WriteC8Encoder(p, "b", api_type, format, false); break; case GX_CTF_RG8: - WriteCC8Encoder(p, "rg", ApiType); + WriteCC8Encoder(p, "rg", api_type, format); break; case GX_CTF_GB8: - WriteCC8Encoder(p, "gb", ApiType); + WriteCC8Encoder(p, "gb", api_type, format); break; case GX_CTF_Z8H: case GX_TF_Z8: - WriteC8Encoder(p, "r", ApiType, true); + WriteC8Encoder(p, "r", api_type, format, true); break; case GX_CTF_Z16R: case GX_TF_Z16: - WriteZ16Encoder(p, ApiType); + WriteZ16Encoder(p, api_type, format); break; case GX_TF_Z24X8: - WriteZ24Encoder(p, ApiType); + WriteZ24Encoder(p, api_type, format); break; case GX_CTF_Z4: - WriteC4Encoder(p, "r", ApiType, true); + WriteC4Encoder(p, "r", api_type, format, true); break; case GX_CTF_Z8M: - WriteZ8Encoder(p, "256.0", ApiType); + WriteZ8Encoder(p, "256.0", api_type, format); break; case GX_CTF_Z8L: - WriteZ8Encoder(p, "65536.0", ApiType); + WriteZ8Encoder(p, "65536.0", api_type, format); break; case GX_CTF_Z16L: - WriteZ16LEncoder(p, ApiType); + WriteZ16LEncoder(p, api_type, format); break; default: - PanicAlert("Unknown texture copy format: 0x%x\n", format); + PanicAlert("Unknown texture copy format: 0x%x\n", static_cast(format.copy_format)); break; } @@ -1219,9 +1248,9 @@ static const std::array s_buffer_bytes_per_texel = {{ 8, // BUFFER_FORMAT_R32G32_UINT }}; -const DecodingShaderInfo* GetDecodingShaderInfo(u32 format) +const DecodingShaderInfo* GetDecodingShaderInfo(TextureFormat format) { - auto iter = s_decoding_shader_info.find(static_cast(format)); + auto iter = s_decoding_shader_info.find(format); return iter != s_decoding_shader_info.end() ? &iter->second : nullptr; } @@ -1240,7 +1269,8 @@ std::pair GetDispatchCount(const DecodingShaderInfo* info, u32 width, (height + (info->group_size_y - 1)) / info->group_size_y}; } -std::string GenerateDecodingShader(u32 format, u32 palette_format, APIType api_type) +std::string GenerateDecodingShader(TextureFormat format, TlutFormat palette_format, + APIType api_type) { const DecodingShaderInfo* info = GetDecodingShaderInfo(format); if (!info) diff --git a/Source/Core/VideoCommon/TextureConversionShader.h b/Source/Core/VideoCommon/TextureConversionShader.h index cc65a2d201..abcd765245 100644 --- a/Source/Core/VideoCommon/TextureConversionShader.h +++ b/Source/Core/VideoCommon/TextureConversionShader.h @@ -8,6 +8,7 @@ #include #include "Common/CommonTypes.h" +#include "VideoCommon/TextureDecoder.h" enum class APIType; @@ -15,7 +16,7 @@ namespace TextureConversionShader { u16 GetEncodedSampleCount(u32 format); -const char* GenerateEncodingShader(u32 format, APIType ApiType); +const char* GenerateEncodingShader(const EFBCopyFormat& format, APIType ApiType); // View format of the input data to the texture decoding shader. enum BufferFormat @@ -39,7 +40,7 @@ struct DecodingShaderInfo // Obtain shader information for the specified texture format. // If this format does not have a shader written for it, returns nullptr. -const DecodingShaderInfo* GetDecodingShaderInfo(u32 format); +const DecodingShaderInfo* GetDecodingShaderInfo(TextureFormat format); // Determine how many bytes there are in each element of the texel buffer. // Needed for alignment and stride calculations. @@ -50,6 +51,7 @@ u32 GetBytesPerBufferElement(BufferFormat buffer_format); std::pair GetDispatchCount(const DecodingShaderInfo* info, u32 width, u32 height); // Returns the GLSL string containing the texture decoding shader for the specified format. -std::string GenerateDecodingShader(u32 format, u32 palette_format, APIType api_type); +std::string GenerateDecodingShader(TextureFormat format, TlutFormat palette_format, + APIType api_type); } // namespace TextureConversionShader diff --git a/Source/Core/VideoCommon/TextureDecoder.h b/Source/Core/VideoCommon/TextureDecoder.h index 44834c0623..b424dd324f 100644 --- a/Source/Core/VideoCommon/TextureDecoder.h +++ b/Source/Core/VideoCommon/TextureDecoder.h @@ -4,6 +4,7 @@ #pragma once +#include #include "Common/CommonTypes.h" enum @@ -67,6 +68,22 @@ enum TlutFormat GX_TL_RGB5A3 = 0x2, }; +struct EFBCopyFormat +{ + EFBCopyFormat(u32 efb_format_, TextureFormat copy_format_) + : efb_format(efb_format_), copy_format(copy_format_) + { + } + + bool operator<(const EFBCopyFormat& rhs) const + { + return std::tie(efb_format, copy_format) < std::tie(rhs.efb_format, rhs.copy_format); + } + + u32 efb_format; + TextureFormat copy_format; +}; + int TexDecoder_GetTexelSizeInNibbles(int format); int TexDecoder_GetTextureSizeInBytes(int width, int height, int format); int TexDecoder_GetBlockWidthInTexels(u32 format); From e9850aa0f270a1f735562db72d84860611ad7226 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 4 Apr 2017 23:55:36 +1000 Subject: [PATCH 2/3] VideoBackends: Support updated texture encoding shader generators --- .../VideoBackends/D3D/PSTextureEncoder.cpp | 94 ++++++------------- .../Core/VideoBackends/D3D/PSTextureEncoder.h | 26 ++--- .../Core/VideoBackends/D3D/TextureCache.cpp | 8 +- Source/Core/VideoBackends/D3D/TextureCache.h | 6 +- .../VideoBackends/D3D12/PSTextureEncoder.cpp | 75 +++++---------- .../VideoBackends/D3D12/PSTextureEncoder.h | 25 ++--- .../Core/VideoBackends/D3D12/TextureCache.cpp | 8 +- .../Core/VideoBackends/D3D12/TextureCache.h | 6 +- Source/Core/VideoBackends/Null/TextureCache.h | 6 +- .../Core/VideoBackends/OGL/TextureCache.cpp | 9 +- Source/Core/VideoBackends/OGL/TextureCache.h | 6 +- .../VideoBackends/OGL/TextureConverter.cpp | 84 ++++++++--------- .../Core/VideoBackends/OGL/TextureConverter.h | 7 +- Source/Core/VideoBackends/Software/SWmain.cpp | 6 +- .../VideoBackends/Vulkan/TextureCache.cpp | 8 +- .../Core/VideoBackends/Vulkan/TextureCache.h | 6 +- .../VideoBackends/Vulkan/TextureConverter.cpp | 64 ++++++------- .../VideoBackends/Vulkan/TextureConverter.h | 15 +-- Source/Core/VideoCommon/TextureCacheBase.cpp | 8 +- Source/Core/VideoCommon/TextureCacheBase.h | 6 +- 20 files changed, 194 insertions(+), 279 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp index 7b9bfaeaa3..403e768599 100644 --- a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp +++ b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp @@ -75,11 +75,11 @@ void PSTextureEncoder::Shutdown() { m_ready = false; - for (auto& it : m_staticShaders) + for (auto& it : m_encoding_shaders) { SAFE_RELEASE(it.second); } - m_staticShaders.clear(); + m_encoding_shaders.clear(); SAFE_RELEASE(m_encodeParams); SAFE_RELEASE(m_outStage); @@ -87,9 +87,9 @@ void PSTextureEncoder::Shutdown() SAFE_RELEASE(m_out); } -void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, - u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, - const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) +void PSTextureEncoder::Encode(u8* dst, const EFBCopyFormat& format, u32 native_width, + u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, + bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half) { if (!m_ready) // Make sure we initialized OK return; @@ -120,10 +120,10 @@ void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_p D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr); EFBEncodeParams params; - params.SrcLeft = srcRect.left; - params.SrcTop = srcRect.top; + params.SrcLeft = src_rect.left; + params.SrcTop = src_rect.top; params.DestWidth = native_width; - params.ScaleFactor = scaleByHalf ? 2 : 1; + params.ScaleFactor = scale_by_half ? 2 : 1; D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, ¶ms, 0, 0); D3D::stateman->SetPixelConstants(m_encodeParams); @@ -131,15 +131,15 @@ void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_p // TODO: This only produces perfect downsampling for 1.5x and 2x IR, other resolution will // need more complex down filtering to average all pixels and produce the correct result. // Also, box filtering won't be correct for anything other than 1x IR - if (scaleByHalf || g_ActiveConfig.iEFBScale != SCALE_1X) + if (scale_by_half || g_ActiveConfig.iEFBScale != SCALE_1X) D3D::SetLinearCopySampler(); else D3D::SetPointCopySampler(); - D3D::drawShadedTexQuad( - pEFB, targetRect.AsRECT(), g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight(), - SetStaticShader(format, is_depth_copy, isIntensity, scaleByHalf), - VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout()); + D3D::drawShadedTexQuad(pEFB, targetRect.AsRECT(), g_renderer->GetTargetWidth(), + g_renderer->GetTargetHeight(), GetEncodingPixelShader(format), + VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout()); // Copy to staging buffer D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, words_per_row, num_blocks_y, 1); @@ -168,61 +168,27 @@ void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_p FramebufferManager::GetEFBDepthTexture()->GetDSV()); } -ID3D11PixelShader* PSTextureEncoder::SetStaticShader(unsigned int dstFormat, bool is_depth_copy, - bool isIntensity, bool scaleByHalf) +ID3D11PixelShader* PSTextureEncoder::GetEncodingPixelShader(const EFBCopyFormat& format) { - ComboKey key = MakeComboKey(dstFormat, is_depth_copy, isIntensity, scaleByHalf); + auto iter = m_encoding_shaders.find(format); + if (iter != m_encoding_shaders.end()) + return iter->second; - ComboMap::iterator it = m_staticShaders.find(key); - if (it == m_staticShaders.end()) + D3DBlob* bytecode = nullptr; + const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::D3D); + if (!D3D::CompilePixelShader(shader, &bytecode)) { - INFO_LOG(VIDEO, - "Compiling efb encoding shader for dstFormat 0x%X, is_depth_copy %d, isIntensity " - "%d, scaleByHalf %d", - dstFormat, is_depth_copy, isIntensity ? 1 : 0, scaleByHalf ? 1 : 0); - - u32 format = dstFormat; - - if (is_depth_copy) - { - format |= _GX_TF_ZTF; - if (dstFormat == 11) - format = GX_TF_Z16; - else if (format < GX_TF_Z8 || format > GX_TF_Z24X8) - format |= _GX_TF_CTF; - } - else - { - if (dstFormat > GX_TF_RGBA8 || (dstFormat < GX_TF_RGB565 && !isIntensity)) - format |= _GX_TF_CTF; - } - - D3DBlob* bytecode = nullptr; - const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::D3D); - if (!D3D::CompilePixelShader(shader, &bytecode)) - { - WARN_LOG(VIDEO, "EFB encoder shader for dstFormat 0x%X, is_depth_copy %d, isIntensity %d, " - "scaleByHalf %d failed to compile", - dstFormat, is_depth_copy, isIntensity ? 1 : 0, scaleByHalf ? 1 : 0); - m_staticShaders[key] = nullptr; - return nullptr; - } - - ID3D11PixelShader* newShader; - HRESULT hr = - D3D::device->CreatePixelShader(bytecode->Data(), bytecode->Size(), nullptr, &newShader); - CHECK(SUCCEEDED(hr), "create efb encoder pixel shader"); - - char debugName[255] = {}; - sprintf_s(debugName, - "efb encoder pixel shader (dst:%d, is_depth_copy:%d, intensity:%d, scale:%d)", - dstFormat, is_depth_copy, isIntensity, scaleByHalf); - D3D::SetDebugObjectName(newShader, debugName); - - it = m_staticShaders.emplace(key, newShader).first; - bytecode->Release(); + PanicAlert("Failed to compile texture encoding shader."); + m_encoding_shaders[format] = nullptr; + return nullptr; } - return it->second; + ID3D11PixelShader* newShader; + HRESULT hr = + D3D::device->CreatePixelShader(bytecode->Data(), bytecode->Size(), nullptr, &newShader); + CHECK(SUCCEEDED(hr), "create efb encoder pixel shader"); + + m_encoding_shaders.emplace(format, newShader); + return newShader; } } diff --git a/Source/Core/VideoBackends/D3D/PSTextureEncoder.h b/Source/Core/VideoBackends/D3D/PSTextureEncoder.h index eee3f63cc5..c000777591 100644 --- a/Source/Core/VideoBackends/D3D/PSTextureEncoder.h +++ b/Source/Core/VideoBackends/D3D/PSTextureEncoder.h @@ -7,6 +7,7 @@ #include #include "Common/CommonTypes.h" +#include "VideoCommon/TextureConversionShader.h" #include "VideoCommon/VideoCommon.h" struct ID3D11Texture2D; @@ -31,32 +32,19 @@ public: void Init(); void Shutdown(); - void Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, - u32 memory_stride, bool is_depth_copy, const EFBRectangle& srcRect, bool isIntensity, - bool scaleByHalf); + void Encode(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, const EFBRectangle& src_rect, + bool scale_by_half); private: + ID3D11PixelShader* GetEncodingPixelShader(const EFBCopyFormat& format); + bool m_ready; ID3D11Texture2D* m_out; ID3D11RenderTargetView* m_outRTV; ID3D11Texture2D* m_outStage; ID3D11Buffer* m_encodeParams; - - ID3D11PixelShader* SetStaticShader(unsigned int dstFormat, bool is_depth_copy, bool isIntensity, - bool scaleByHalf); - - typedef unsigned int ComboKey; // Key for a shader combination - - ComboKey MakeComboKey(unsigned int dstFormat, bool is_depth_copy, bool isIntensity, - bool scaleByHalf) - { - return (dstFormat << 4) | (static_cast(is_depth_copy) << 2) | - (isIntensity ? (1 << 1) : 0) | (scaleByHalf ? (1 << 0) : 0); - } - - typedef std::map ComboMap; - - ComboMap m_staticShaders; + std::map m_encoding_shaders; }; } diff --git a/Source/Core/VideoBackends/D3D/TextureCache.cpp b/Source/Core/VideoBackends/D3D/TextureCache.cpp index e3edf79695..d6369f290f 100644 --- a/Source/Core/VideoBackends/D3D/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D/TextureCache.cpp @@ -241,12 +241,12 @@ void TextureCache::TCacheEntry::FromRenderTarget(bool is_depth_copy, const EFBRe g_renderer->RestoreAPIState(); } -void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, - u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, - const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) +void TextureCache::CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, + u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, + bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half) { g_encoder->Encode(dst, format, native_width, bytes_per_row, num_blocks_y, memory_stride, - is_depth_copy, srcRect, isIntensity, scaleByHalf); + is_depth_copy, src_rect, scale_by_half); } const char palette_shader[] = diff --git a/Source/Core/VideoBackends/D3D/TextureCache.h b/Source/Core/VideoBackends/D3D/TextureCache.h index bf82418208..01b229cf72 100644 --- a/Source/Core/VideoBackends/D3D/TextureCache.h +++ b/Source/Core/VideoBackends/D3D/TextureCache.h @@ -51,9 +51,9 @@ private: void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format) override; - void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, - u32 memory_stride, bool is_depth_copy, const EFBRectangle& srcRect, bool isIntensity, - bool scaleByHalf) override; + void CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, + const EFBRectangle& src_rect, bool scale_by_half) override; bool CompileShaders() override { return true; } void DeleteShaders() override {} diff --git a/Source/Core/VideoBackends/D3D12/PSTextureEncoder.cpp b/Source/Core/VideoBackends/D3D12/PSTextureEncoder.cpp index 8e70540d94..ce56588669 100644 --- a/Source/Core/VideoBackends/D3D12/PSTextureEncoder.cpp +++ b/Source/Core/VideoBackends/D3D12/PSTextureEncoder.cpp @@ -101,18 +101,18 @@ void PSTextureEncoder::Shutdown() D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_out_readback_buffer); D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_encode_params_buffer); - for (auto& it : m_static_shaders_blobs) + for (auto& it : m_shader_blobs) { SAFE_RELEASE(it); } - m_static_shaders_blobs.clear(); - m_static_shaders_map.clear(); + m_shader_blobs.clear(); + m_encoding_shaders.clear(); } -void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, - u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, - const EFBRectangle& src_rect, bool is_intensity, bool scale_by_half) +void PSTextureEncoder::Encode(u8* dst, const EFBCopyFormat& format, u32 native_width, + u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, + bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half) { if (!m_ready) // Make sure we initialized OK return; @@ -167,8 +167,7 @@ void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_p D3D::DrawShadedTexQuad( efb_source, target_rect.AsRECT(), g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight(), - SetStaticShader(format, is_depth_copy, is_intensity, scale_by_half), - StaticShaderCache::GetSimpleVertexShader(), + GetEncodingPixelShader(format), StaticShaderCache::GetSimpleVertexShader(), StaticShaderCache::GetSimpleVertexShaderInputLayout(), D3D12_SHADER_BYTECODE(), 1.0f, 0, DXGI_FORMAT_B8G8R8A8_UNORM, false, false /* Render target is not multisampled */ ); @@ -223,53 +222,27 @@ void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_p m_out_readback_buffer->Unmap(0, &write_range); } -D3D12_SHADER_BYTECODE PSTextureEncoder::SetStaticShader(unsigned int dst_format, bool is_depth_copy, - bool is_intensity, bool scale_by_half) +D3D12_SHADER_BYTECODE PSTextureEncoder::GetEncodingPixelShader(const EFBCopyFormat& format) { - ComboKey key = MakeComboKey(dst_format, is_depth_copy, is_intensity, scale_by_half); + auto iter = m_encoding_shaders.find(format); + if (iter != m_encoding_shaders.end()) + return iter->second; - ComboMap::iterator it = m_static_shaders_map.find(key); - if (it == m_static_shaders_map.end()) + ID3DBlob* bytecode = nullptr; + const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::D3D); + if (!D3D::CompilePixelShader(shader, &bytecode)) { - INFO_LOG(VIDEO, "Compiling efb encoding shader for dst_format 0x%X, is_depth_copy %d, " - "is_intensity %d, scale_by_half %d", - dst_format, is_depth_copy, is_intensity ? 1 : 0, scale_by_half ? 1 : 0); - - u32 format = dst_format; - - if (is_depth_copy) - { - format |= _GX_TF_ZTF; - if (dst_format == 11) - format = GX_TF_Z16; - else if (format < GX_TF_Z8 || format > GX_TF_Z24X8) - format |= _GX_TF_CTF; - } - else - { - if (dst_format > GX_TF_RGBA8 || (dst_format < GX_TF_RGB565 && !is_intensity)) - format |= _GX_TF_CTF; - } - - ID3DBlob* bytecode = nullptr; - const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::D3D); - if (!D3D::CompilePixelShader(shader, &bytecode)) - { - WARN_LOG(VIDEO, "EFB encoder shader for dst_format 0x%X, is_depth_copy %d, is_intensity %d, " - "scale_by_half %d failed to compile", - dst_format, is_depth_copy, is_intensity ? 1 : 0, scale_by_half ? 1 : 0); - m_static_shaders_blobs[key] = {}; - return {}; - } - - D3D12_SHADER_BYTECODE new_shader = {bytecode->GetBufferPointer(), bytecode->GetBufferSize()}; - - it = m_static_shaders_map.emplace(key, new_shader).first; - - // Keep track of the ID3DBlobs, so we can free them upon shutdown. - m_static_shaders_blobs.push_back(bytecode); + PanicAlert("Failed to compile texture encoding shader."); + m_encoding_shaders[format] = {}; + return {}; } - return it->second; + D3D12_SHADER_BYTECODE new_shader = {bytecode->GetBufferPointer(), bytecode->GetBufferSize()}; + m_encoding_shaders.emplace(format, new_shader); + + // Keep track of the ID3DBlobs, so we can free them upon shutdown. + m_shader_blobs.push_back(bytecode); + + return new_shader; } } diff --git a/Source/Core/VideoBackends/D3D12/PSTextureEncoder.h b/Source/Core/VideoBackends/D3D12/PSTextureEncoder.h index 8f7f11b229..b3f984277c 100644 --- a/Source/Core/VideoBackends/D3D12/PSTextureEncoder.h +++ b/Source/Core/VideoBackends/D3D12/PSTextureEncoder.h @@ -9,6 +9,7 @@ #include "Common/CommonTypes.h" #include "VideoBackends/D3D12/D3DBase.h" +#include "VideoCommon/TextureConversionShader.h" #include "VideoCommon/VideoCommon.h" namespace DX12 @@ -20,11 +21,13 @@ public: void Init(); void Shutdown(); - void Encode(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, - u32 memory_stride, bool is_depth_copy, const EFBRectangle& src_rect, - bool is_intensity, bool scale_by_half); + void Encode(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, const EFBRectangle& src_rect, + bool scale_by_half); private: + D3D12_SHADER_BYTECODE GetEncodingPixelShader(const EFBCopyFormat& format); + bool m_ready = false; ID3D12Resource* m_out = nullptr; @@ -35,19 +38,7 @@ private: ID3D12Resource* m_encode_params_buffer = nullptr; void* m_encode_params_buffer_data = nullptr; - D3D12_SHADER_BYTECODE SetStaticShader(unsigned int dst_format, bool is_depth_copy, - bool is_intensity, bool scale_by_half); - - using ComboKey = unsigned int; // Key for a shader combination - static ComboKey MakeComboKey(unsigned int dst_format, bool is_depth_copy, bool is_intensity, - bool scale_by_half) - { - return (dst_format << 4) | (is_depth_copy << 2) | (is_intensity ? (1 << 1) : 0) | - (scale_by_half ? (1 << 0) : 0); - } - - using ComboMap = std::map; - ComboMap m_static_shaders_map; - std::vector m_static_shaders_blobs; + std::map m_encoding_shaders; + std::vector m_shader_blobs; }; } diff --git a/Source/Core/VideoBackends/D3D12/TextureCache.cpp b/Source/Core/VideoBackends/D3D12/TextureCache.cpp index 8ae4d54d74..d626cb7732 100644 --- a/Source/Core/VideoBackends/D3D12/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D12/TextureCache.cpp @@ -306,12 +306,12 @@ void TextureCache::TCacheEntry::FromRenderTarget(bool is_depth_copy, const EFBRe g_renderer->RestoreAPIState(); } -void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, - u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, - const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) +void TextureCache::CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, + u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, + bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half) { s_encoder->Encode(dst, format, native_width, bytes_per_row, num_blocks_y, memory_stride, - is_depth_copy, srcRect, isIntensity, scaleByHalf); + is_depth_copy, src_rect, scale_by_half); } static const constexpr char s_palette_shader_hlsl[] = diff --git a/Source/Core/VideoBackends/D3D12/TextureCache.h b/Source/Core/VideoBackends/D3D12/TextureCache.h index 87c3107960..f6921afe5b 100644 --- a/Source/Core/VideoBackends/D3D12/TextureCache.h +++ b/Source/Core/VideoBackends/D3D12/TextureCache.h @@ -60,9 +60,9 @@ private: void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format) override; - void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, - u32 memory_stride, bool is_depth_copy, const EFBRectangle& src_rect, - bool is_intensity, bool scale_by_half) override; + void CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, + const EFBRectangle& src_rect, bool scale_by_half) override; bool CompileShaders() override { return true; } void DeleteShaders() override {} diff --git a/Source/Core/VideoBackends/Null/TextureCache.h b/Source/Core/VideoBackends/Null/TextureCache.h index ff21422e69..48d111dce6 100644 --- a/Source/Core/VideoBackends/Null/TextureCache.h +++ b/Source/Core/VideoBackends/Null/TextureCache.h @@ -20,9 +20,9 @@ public: { } - void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, - u32 memory_stride, bool is_depth_copy, const EFBRectangle& src_rect, - bool is_intensity, bool scale_by_half) override + void CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, + const EFBRectangle& src_rect, bool scale_by_half) override { } diff --git a/Source/Core/VideoBackends/OGL/TextureCache.cpp b/Source/Core/VideoBackends/OGL/TextureCache.cpp index 33130da5c8..3bf1342809 100644 --- a/Source/Core/VideoBackends/OGL/TextureCache.cpp +++ b/Source/Core/VideoBackends/OGL/TextureCache.cpp @@ -288,13 +288,12 @@ void TextureCache::TCacheEntry::FromRenderTarget(bool is_depth_copy, const EFBRe g_renderer->RestoreAPIState(); } -void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, - u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, - const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) +void TextureCache::CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, + u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, + bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half) { TextureConverter::EncodeToRamFromTexture(dst, format, native_width, bytes_per_row, num_blocks_y, - memory_stride, is_depth_copy, isIntensity, scaleByHalf, - srcRect); + memory_stride, is_depth_copy, src_rect, scale_by_half); } TextureCache::TextureCache() diff --git a/Source/Core/VideoBackends/OGL/TextureCache.h b/Source/Core/VideoBackends/OGL/TextureCache.h index cfd267caae..aece35cd6c 100644 --- a/Source/Core/VideoBackends/OGL/TextureCache.h +++ b/Source/Core/VideoBackends/OGL/TextureCache.h @@ -58,9 +58,9 @@ private: void ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format) override; - void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, - u32 memory_stride, bool is_depth_copy, const EFBRectangle& srcRect, bool isIntensity, - bool scaleByHalf) override; + void CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, + const EFBRectangle& src_rect, bool scale_by_half) override; bool CompileShaders() override; void DeleteShaders() override; diff --git a/Source/Core/VideoBackends/OGL/TextureConverter.cpp b/Source/Core/VideoBackends/OGL/TextureConverter.cpp index b54234710b..1a51d8fb09 100644 --- a/Source/Core/VideoBackends/OGL/TextureConverter.cpp +++ b/Source/Core/VideoBackends/OGL/TextureConverter.cpp @@ -45,10 +45,12 @@ static int s_rgbToYuyvUniform_loc; static SHADER s_yuyvToRgbProgram; -// Not all slots are taken - but who cares. -const u32 NUM_ENCODING_PROGRAMS = 64; -static SHADER s_encodingPrograms[NUM_ENCODING_PROGRAMS]; -static int s_encodingUniforms[NUM_ENCODING_PROGRAMS]; +struct EncodingProgram +{ + SHADER program; + GLint copy_position_uniform; +}; +static std::map s_encoding_programs; static GLuint s_PBO = 0; // for readback with different strides @@ -133,41 +135,37 @@ static void CreatePrograms() ProgramShaderCache::CompileShader(s_yuyvToRgbProgram, VProgramYuyvToRgb, FProgramYuyvToRgb); } -static SHADER& GetOrCreateEncodingShader(u32 format) +static EncodingProgram& GetOrCreateEncodingShader(const EFBCopyFormat& format) { - if (format >= NUM_ENCODING_PROGRAMS) - { - PanicAlert("Unknown texture copy format: 0x%x\n", format); - return s_encodingPrograms[0]; - } + auto iter = s_encoding_programs.find(format); + if (iter != s_encoding_programs.end()) + return iter->second; - if (s_encodingPrograms[format].glprogid == 0) - { - const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::OpenGL); + const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::OpenGL); #if defined(_DEBUG) || defined(DEBUGFAST) - if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader) - { - static int counter = 0; - std::string filename = - StringFromFormat("%senc_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); + if (g_ActiveConfig.iLog & CONF_SAVESHADERS && shader) + { + static int counter = 0; + std::string filename = + StringFromFormat("%senc_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), counter++); - SaveData(filename, shader); - } + SaveData(filename, shader); + } #endif - const char* VProgram = "void main()\n" - "{\n" - " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" - " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" - "}\n"; + const char* VProgram = "void main()\n" + "{\n" + " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" + " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" + "}\n"; - ProgramShaderCache::CompileShader(s_encodingPrograms[format], VProgram, shader); + EncodingProgram program; + if (!ProgramShaderCache::CompileShader(program.program, VProgram, shader)) + PanicAlert("Failed to compile texture encoding shader."); - s_encodingUniforms[format] = - glGetUniformLocation(s_encodingPrograms[format].glprogid, "position"); - } - return s_encodingPrograms[format]; + program.copy_position_uniform = glGetUniformLocation(program.program.glprogid, "position"); + return s_encoding_programs.emplace(format, program).first->second; } void Init() @@ -204,8 +202,9 @@ void Shutdown() s_rgbToYuyvProgram.Destroy(); s_yuyvToRgbProgram.Destroy(); - for (auto& program : s_encodingPrograms) - program.Destroy(); + for (auto& program : s_encoding_programs) + program.second.program.Destroy(); + s_encoding_programs.clear(); s_srcTexture = 0; s_dstTexture = 0; @@ -271,23 +270,24 @@ static void EncodeToRamUsingShader(GLuint srcTexture, u8* destAddr, u32 dst_line glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); } -void EncodeToRamFromTexture(u8* dest_ptr, u32 format, u32 native_width, u32 bytes_per_row, - u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, - bool bIsIntensityFmt, int bScaleByHalf, const EFBRectangle& source) +void EncodeToRamFromTexture(u8* dest_ptr, const EFBCopyFormat& format, u32 native_width, + u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, + bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half) { g_renderer->ResetAPIState(); - SHADER& texconv_shader = GetOrCreateEncodingShader(format); + EncodingProgram& texconv_shader = GetOrCreateEncodingShader(format); - texconv_shader.Bind(); - glUniform4i(s_encodingUniforms[format], source.left, source.top, native_width, - bScaleByHalf ? 2 : 1); + texconv_shader.program.Bind(); + glUniform4i(texconv_shader.copy_position_uniform, src_rect.left, src_rect.top, native_width, + scale_by_half ? 2 : 1); - const GLuint read_texture = is_depth_copy ? FramebufferManager::ResolveAndGetDepthTarget(source) : - FramebufferManager::ResolveAndGetRenderTarget(source); + const GLuint read_texture = is_depth_copy ? + FramebufferManager::ResolveAndGetDepthTarget(src_rect) : + FramebufferManager::ResolveAndGetRenderTarget(src_rect); EncodeToRamUsingShader(read_texture, dest_ptr, bytes_per_row, num_blocks_y, memory_stride, - bScaleByHalf > 0 && !is_depth_copy); + scale_by_half && !is_depth_copy); FramebufferManager::SetFramebuffer(0); g_renderer->RestoreAPIState(); diff --git a/Source/Core/VideoBackends/OGL/TextureConverter.h b/Source/Core/VideoBackends/OGL/TextureConverter.h index 8893ef1e52..11576f9aa1 100644 --- a/Source/Core/VideoBackends/OGL/TextureConverter.h +++ b/Source/Core/VideoBackends/OGL/TextureConverter.h @@ -7,6 +7,7 @@ #include "Common/CommonTypes.h" #include "Common/GL/GLUtil.h" +#include "VideoCommon/TextureDecoder.h" #include "VideoCommon/VideoCommon.h" namespace OGL @@ -24,9 +25,9 @@ void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* des void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture); // returns size of the encoded data (in bytes) -void EncodeToRamFromTexture(u8* dest_ptr, u32 format, u32 native_width, u32 bytes_per_row, - u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, - bool bIsIntensityFmt, int bScaleByHalf, const EFBRectangle& source); +void EncodeToRamFromTexture(u8* dest_ptr, const EFBCopyFormat& format, u32 native_width, + u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, + bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half); } } // namespace OGL diff --git a/Source/Core/VideoBackends/Software/SWmain.cpp b/Source/Core/VideoBackends/Software/SWmain.cpp index eb70f4059f..0f67c0e6fd 100644 --- a/Source/Core/VideoBackends/Software/SWmain.cpp +++ b/Source/Core/VideoBackends/Software/SWmain.cpp @@ -53,9 +53,9 @@ public: TlutFormat format) override { } - void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, - u32 memory_stride, bool is_depth_copy, const EFBRectangle& srcRect, bool isIntensity, - bool scaleByHalf) override + void CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, + const EFBRectangle& src_rect, bool scale_by_half) override { EfbCopy::CopyEfb(); } diff --git a/Source/Core/VideoBackends/Vulkan/TextureCache.cpp b/Source/Core/VideoBackends/Vulkan/TextureCache.cpp index b951b78aa2..23cc06abff 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/TextureCache.cpp @@ -88,9 +88,9 @@ void TextureCache::ConvertTexture(TCacheEntryBase* base_entry, TCacheEntryBase* m_texture_converter->ConvertTexture(entry, unconverted, m_render_pass, palette, format); } -void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, - u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, - const EFBRectangle& src_rect, bool is_intensity, bool scale_by_half) +void TextureCache::CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, + u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, + bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half) { // Flush EFB pokes first, as they're expected to be included. FramebufferManager::GetInstance()->FlushEFBPokes(); @@ -120,7 +120,7 @@ void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_ m_texture_converter->EncodeTextureToMemory(src_texture->GetView(), dst, format, native_width, bytes_per_row, num_blocks_y, memory_stride, - is_depth_copy, is_intensity, scale_by_half, src_rect); + is_depth_copy, src_rect, scale_by_half); // Transition back to original state src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), original_layout); diff --git a/Source/Core/VideoBackends/Vulkan/TextureCache.h b/Source/Core/VideoBackends/Vulkan/TextureCache.h index b433d7d9e0..5fd25c23d8 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureCache.h +++ b/Source/Core/VideoBackends/Vulkan/TextureCache.h @@ -59,9 +59,9 @@ public: void ConvertTexture(TCacheEntryBase* base_entry, TCacheEntryBase* base_unconverted, void* palette, TlutFormat format) override; - void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, - u32 memory_stride, bool is_depth_copy, const EFBRectangle& src_rect, - bool is_intensity, bool scale_by_half) override; + void CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, + const EFBRectangle& src_rect, bool scale_by_half) override; void CopyRectangleFromTexture(TCacheEntry* dst_texture, const MathUtil::Rectangle& dst_rect, Texture2D* src_texture, const MathUtil::Rectangle& src_rect); diff --git a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp index 7765647b1f..ca5ebe94bc 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp +++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp @@ -57,11 +57,8 @@ TextureConverter::~TextureConverter() if (m_encoding_render_framebuffer != VK_NULL_HANDLE) vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_encoding_render_framebuffer, nullptr); - for (VkShaderModule shader : m_encoding_shaders) - { - if (shader != VK_NULL_HANDLE) - vkDestroyShaderModule(g_vulkan_context->GetDevice(), shader, nullptr); - } + for (auto& it : m_encoding_shaders) + vkDestroyShaderModule(g_vulkan_context->GetDevice(), it.second, nullptr); for (const auto& it : m_decoding_pipelines) { @@ -89,12 +86,6 @@ bool TextureConverter::Initialize() return false; } - if (!CompileEncodingShaders()) - { - PanicAlert("Failed to compile texture encoding shaders"); - return false; - } - if (!CreateEncodingRenderPass()) { PanicAlert("Failed to create encode render pass"); @@ -221,15 +212,17 @@ void TextureConverter::ConvertTexture(TextureCache::TCacheEntry* dst_entry, draw.EndRenderPass(); } -void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_ptr, u32 format, - u32 native_width, u32 bytes_per_row, u32 num_blocks_y, - u32 memory_stride, bool is_depth_copy, - bool is_intensity, int scale_by_half, - const EFBRectangle& src_rect) +void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_ptr, + const EFBCopyFormat& format, u32 native_width, + u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, + bool is_depth_copy, const EFBRectangle& src_rect, + bool scale_by_half) { - if (m_encoding_shaders[format] == VK_NULL_HANDLE) + VkShaderModule shader = GetEncodingShader(format); + if (shader == VK_NULL_HANDLE) { - ERROR_LOG(VIDEO, "Missing encoding fragment shader for format %u", format); + ERROR_LOG(VIDEO, "Missing encoding fragment shader for format %u->%u", format.efb_format, + static_cast(format.copy_format)); return; } @@ -242,7 +235,7 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT), m_encoding_render_pass, g_object_cache->GetScreenQuadVertexShader(), - VK_NULL_HANDLE, m_encoding_shaders[format]); + VK_NULL_HANDLE, shader); // Uniform - int4 of left,top,native_width,scale s32 position_uniform[4] = {src_rect.left, src_rect.top, static_cast(native_width), @@ -681,24 +674,25 @@ bool TextureConverter::CompilePaletteConversionShaders() m_palette_conversion_shaders[GX_TL_RGB5A3] != VK_NULL_HANDLE; } -bool TextureConverter::CompileEncodingShaders() +VkShaderModule TextureConverter::CompileEncodingShader(const EFBCopyFormat& format) { - // Texture encoding shaders - static const u32 texture_encoding_shader_formats[] = { - GX_TF_I4, GX_TF_I8, GX_TF_IA4, GX_TF_IA8, GX_TF_RGB565, GX_TF_RGB5A3, GX_TF_RGBA8, - GX_CTF_R4, GX_CTF_RA4, GX_CTF_RA8, GX_CTF_A8, GX_CTF_R8, GX_CTF_G8, GX_CTF_B8, - GX_CTF_RG8, GX_CTF_GB8, GX_CTF_Z8H, GX_TF_Z8, GX_CTF_Z16R, GX_TF_Z16, GX_TF_Z24X8, - GX_CTF_Z4, GX_CTF_Z8M, GX_CTF_Z8L, GX_CTF_Z16L}; - for (u32 format : texture_encoding_shader_formats) - { - const char* shader_source = - TextureConversionShader::GenerateEncodingShader(format, APIType::Vulkan); - m_encoding_shaders[format] = Util::CompileAndCreateFragmentShader(shader_source); - if (m_encoding_shaders[format] == VK_NULL_HANDLE) - return false; - } + const char* shader = TextureConversionShader::GenerateEncodingShader(format, APIType::Vulkan); + VkShaderModule module = Util::CompileAndCreateFragmentShader(shader); + if (module == VK_NULL_HANDLE) + PanicAlert("Failed to compile texture encoding shader."); - return true; + return module; +} + +VkShaderModule TextureConverter::GetEncodingShader(const EFBCopyFormat& format) +{ + auto iter = m_encoding_shaders.find(format); + if (iter != m_encoding_shaders.end()) + return iter->second; + + VkShaderModule shader = CompileEncodingShader(format); + m_encoding_shaders.emplace(format, shader); + return shader; } bool TextureConverter::CreateEncodingRenderPass() diff --git a/Source/Core/VideoBackends/Vulkan/TextureConverter.h b/Source/Core/VideoBackends/Vulkan/TextureConverter.h index 39543e0f17..a139f1eab9 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureConverter.h +++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.h @@ -35,10 +35,10 @@ public: // Uses an encoding shader to copy src_texture to dest_ptr. // NOTE: Executes the current command buffer. - void EncodeTextureToMemory(VkImageView src_texture, u8* dest_ptr, u32 format, u32 native_width, - u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - bool is_depth_copy, bool is_intensity, int scale_by_half, - const EFBRectangle& source); + void EncodeTextureToMemory(VkImageView src_texture, u8* dest_ptr, const EFBCopyFormat& format, + u32 native_width, u32 bytes_per_row, u32 num_blocks_y, + u32 memory_stride, bool is_depth_copy, const EFBRectangle& src_rect, + bool scale_by_half); // Encodes texture to guest memory in XFB (YUYV) format. void EncodeTextureToMemoryYUYV(void* dst_ptr, u32 dst_width, u32 dst_stride, u32 dst_height, @@ -55,7 +55,6 @@ public: TlutFormat palette_format); private: - static const u32 NUM_TEXTURE_ENCODING_SHADERS = 64; static const u32 ENCODING_TEXTURE_WIDTH = EFB_WIDTH * 4; static const u32 ENCODING_TEXTURE_HEIGHT = 1024; static const VkFormat ENCODING_TEXTURE_FORMAT = VK_FORMAT_B8G8R8A8_UNORM; @@ -70,7 +69,9 @@ private: bool CompilePaletteConversionShaders(); - bool CompileEncodingShaders(); + VkShaderModule CompileEncodingShader(const EFBCopyFormat& format); + VkShaderModule GetEncodingShader(const EFBCopyFormat& format); + bool CreateEncodingRenderPass(); bool CreateEncodingTexture(); bool CreateEncodingDownloadTexture(); @@ -102,7 +103,7 @@ private: std::array m_palette_conversion_shaders = {}; // Texture encoding - RGBA8->GX format in memory - std::array m_encoding_shaders = {}; + std::map m_encoding_shaders; VkRenderPass m_encoding_render_pass = VK_NULL_HANDLE; std::unique_ptr m_encoding_render_texture; VkFramebuffer m_encoding_render_framebuffer = VK_NULL_HANDLE; diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index c12c53be27..89d473cfec 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -969,7 +969,8 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFo ColorMask[0] = ColorMask[1] = ColorMask[2] = ColorMask[3] = 255.0f; ColorMask[4] = ColorMask[5] = ColorMask[6] = ColorMask[7] = 1.0f / 255.0f; unsigned int cbufid = -1; - bool efbHasAlpha = bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; + u32 srcFormat = bpmem.zcontrol.pixel_format; + bool efbHasAlpha = srcFormat == PEControl::RGBA6_Z24; if (is_depth_copy) { @@ -1278,8 +1279,9 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFo if (copy_to_ram) { - CopyEFB(dst, dstFormat, tex_w, bytes_per_row, num_blocks_y, dstStride, is_depth_copy, srcRect, - isIntensity, scaleByHalf); + EFBCopyFormat format(srcFormat, static_cast(dstFormat)); + CopyEFB(dst, format, tex_w, bytes_per_row, num_blocks_y, dstStride, is_depth_copy, srcRect, + scaleByHalf); } else { diff --git a/Source/Core/VideoCommon/TextureCacheBase.h b/Source/Core/VideoCommon/TextureCacheBase.h index 3000491924..4c9582079b 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.h +++ b/Source/Core/VideoCommon/TextureCacheBase.h @@ -154,9 +154,9 @@ public: virtual TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) = 0; - virtual void CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, - u32 memory_stride, bool is_depth_copy, const EFBRectangle& srcRect, - bool isIntensity, bool scaleByHalf) = 0; + virtual void CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row, + u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, + const EFBRectangle& src_rect, bool scale_by_half) = 0; virtual bool CompileShaders() = 0; virtual void DeleteShaders() = 0; From 5e7bd03d0b8aaf16b4baa716d73c4804760a84c0 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 5 Apr 2017 00:06:47 +1000 Subject: [PATCH 3/3] Vulkan: Linear filter >1xIR EFB copies, matching the other backends --- Source/Core/VideoBackends/Vulkan/TextureConverter.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp index ca5ebe94bc..1bc173d4ee 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp +++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp @@ -27,6 +27,7 @@ #include "VideoCommon/TextureConversionShader.h" #include "VideoCommon/TextureDecoder.h" +#include "VideoCommon/VideoConfig.h" namespace Vulkan { @@ -242,10 +243,12 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p scale_by_half ? 2 : 1}; draw.SetPushConstants(position_uniform, sizeof(position_uniform)); - // Doesn't make sense to linear filter depth values - draw.SetPSSampler(0, src_texture, (scale_by_half && !is_depth_copy) ? - g_object_cache->GetLinearSampler() : - g_object_cache->GetPointSampler()); + // We also linear filtering for both box filtering and downsampling higher resolutions to 1x + // TODO: This only produces perfect downsampling for 1.5x and 2x IR, other resolution will + // need more complex down filtering to average all pixels and produce the correct result. + bool linear_filter = (scale_by_half && !is_depth_copy) || g_ActiveConfig.iEFBScale != SCALE_1X; + draw.SetPSSampler(0, src_texture, linear_filter ? g_object_cache->GetLinearSampler() : + g_object_cache->GetPointSampler()); u32 render_width = bytes_per_row / sizeof(u32); u32 render_height = num_blocks_y;