diff options
| author | Stenzek <stenzek@gmail.com> | 2019-07-14 15:24:12 +1000 |
|---|---|---|
| committer | Stenzek <stenzek@gmail.com> | 2019-07-14 19:16:27 +1000 |
| commit | 946571b7595b6b24e02cf8622f2bd5935b5aa360 (patch) | |
| tree | eef0c948d64df352f6b37e0625e4dbd917d8f7e4 /Source/Core/VideoCommon/FramebufferShaderGen.cpp | |
| parent | 77f406c8a8dc638bd6404dd71b7537eed9498b69 (diff) | |
TextureCache: Support reinterpreting formats for VRAM textures
Diffstat (limited to 'Source/Core/VideoCommon/FramebufferShaderGen.cpp')
| -rw-r--r-- | Source/Core/VideoCommon/FramebufferShaderGen.cpp | 149 |
1 files changed, 148 insertions, 1 deletions
diff --git a/Source/Core/VideoCommon/FramebufferShaderGen.cpp b/Source/Core/VideoCommon/FramebufferShaderGen.cpp index dfb86d2be2..f944562d9c 100644 --- a/Source/Core/VideoCommon/FramebufferShaderGen.cpp +++ b/Source/Core/VideoCommon/FramebufferShaderGen.cpp @@ -1,6 +1,7 @@ #include "VideoCommon/FramebufferShaderGen.h" #include <sstream> #include "VideoCommon/FramebufferManager.h" +#include "VideoCommon/TextureDecoder.h" #include "VideoCommon/VertexShaderGen.h" namespace FramebufferShaderGen @@ -68,6 +69,26 @@ static void EmitSampleTexture(std::stringstream& ss, u32 n, const char* coords) } } +// Emits a texel fetch/load instruction. Assumes that "coords" is a 4-element vector, with z +// containing the layer, and w containing the mipmap level. +static void EmitTextureLoad(std::stringstream& ss, u32 n, const char* coords) +{ + switch (GetAPIType()) + { + case APIType::D3D: + ss << "tex" << n << ".Load(" << coords << ")"; + break; + + case APIType::OpenGL: + case APIType::Vulkan: + ss << "texelFetch(samp" << n << ", (" << coords << ").xyz, (" << coords << ").w)"; + break; + + default: + break; + } +} + static void EmitVertexMainDeclaration(std::stringstream& ss, u32 num_tex_inputs, u32 num_color_inputs, bool position_input, u32 num_tex_outputs, u32 num_color_outputs, @@ -133,7 +154,7 @@ static void EmitVertexMainDeclaration(std::stringstream& ss, u32 num_tex_inputs, static void EmitPixelMainDeclaration(std::stringstream& ss, u32 num_tex_inputs, u32 num_color_inputs, const char* output_type = "float4", - const char* extra_vars = "") + const char* extra_vars = "", bool emit_frag_coord = false) { switch (GetAPIType()) { @@ -144,6 +165,8 @@ static void EmitPixelMainDeclaration(std::stringstream& ss, u32 num_tex_inputs, ss << "in float3 v_tex" << i << " : TEXCOORD" << i << ", "; for (u32 i = 0; i < num_color_inputs; i++) ss << "in float4 v_col" << i << " : COLOR" << i << ", "; + if (emit_frag_coord) + ss << "in float4 frag_coord : SV_Position, "; ss << extra_vars << "out " << output_type << " ocol0 : SV_Target)\n"; } break; @@ -170,6 +193,8 @@ static void EmitPixelMainDeclaration(std::stringstream& ss, u32 num_tex_inputs, ss << "FRAGMENT_OUTPUT_LOCATION(0) out " << output_type << " ocol0;\n"; ss << extra_vars << "\n"; + if (emit_frag_coord) + ss << "#define frag_coord gl_FragCoord\n"; ss << "void main()\n"; } break; @@ -496,4 +521,126 @@ std::string GenerateFormatConversionShader(EFBReinterpretType convtype, u32 samp return ss.str(); } +std::string GenerateTextureReinterpretShader(TextureFormat from_format, TextureFormat to_format) +{ + std::stringstream ss; + EmitSamplerDeclarations(ss, 0, 1, false); + EmitPixelMainDeclaration(ss, 1, 0, "float4", "", true); + ss << "{\n"; + ss << " int layer = int(v_tex0.z);\n"; + ss << " int4 coords = int4(int2(frag_coord.xy), layer, 0);\n"; + + // Convert to a 32-bit value encompassing all channels, filling the most significant bits with + // zeroes. + ss << " uint raw_value;\n"; + switch (from_format) + { + case TextureFormat::I8: + case TextureFormat::C8: + { + ss << " float4 temp_value = "; + EmitTextureLoad(ss, 0, "coords"); + ss << ";\n"; + ss << " raw_value = uint(temp_value.r * 255.0);\n"; + } + break; + + case TextureFormat::IA8: + { + ss << " float4 temp_value = "; + EmitTextureLoad(ss, 0, "coords"); + ss << ";\n"; + ss << " raw_value = uint(temp_value.r * 255.0) | (uint(temp_value.a * 255.0) << 8);\n"; + } + break; + + case TextureFormat::IA4: + { + ss << " float4 temp_value = "; + EmitTextureLoad(ss, 0, "coords"); + ss << ";\n"; + ss << " raw_value = uint(temp_value.r * 15.0) | (uint(temp_value.a * 15.0) << 4);\n"; + } + break; + + case TextureFormat::RGB565: + { + ss << " float4 temp_value = "; + EmitTextureLoad(ss, 0, "coords"); + ss << ";\n"; + ss << " raw_value = uint(temp_value.b * 31.0) | (uint(temp_value.g * 63.0) << 5) |\n"; + ss << " (uint(temp_value.r * 31.0) << 11);\n"; + } + break; + + case TextureFormat::RGB5A3: + { + ss << " float4 temp_value = "; + EmitTextureLoad(ss, 0, "coords"); + ss << ";\n"; + + // 0.8784 = 224 / 255 which is the maximum alpha value that can be represented in 3 bits + ss << " if (temp_value.a > 0.878f) {\n"; + ss << " raw_value = (uint(temp_value.b * 31.0)) | (uint(temp_value.g * 31.0) << 5) |\n"; + ss << " (uint(temp_value.r * 31.0) << 10) | 0x8000u;\n"; + ss << " } else {\n"; + ss << " raw_value = (uint(temp_value.b * 15.0)) | (uint(temp_value.g * 15.0) << 4) |\n"; + ss << " (uint(temp_value.r * 15.0) << 8) | (uint(temp_value.a * 7.0) << 12);\n"; + ss << " }\n"; + } + break; + } + + // Now convert it to its new representation. + switch (to_format) + { + case TextureFormat::I8: + case TextureFormat::C8: + { + ss << " ocol0.rgba = (float(raw_value & 0xFFu) / 255.0).rrrr;\n"; + } + break; + + case TextureFormat::IA8: + { + ss << " ocol0.rgb = (float(raw_value & 0xFFu) / 255.0).rrr;\n"; + ss << " ocol0.a = float((raw_value >> 8) & 0xFFu) / 255.0;\n"; + } + break; + + case TextureFormat::IA4: + { + ss << " ocol0.rgb = (float(raw_value & 0xFu) / 15.0).rrr;\n"; + ss << " ocol0.a = float((raw_value >> 4) & 0xFu) / 15.0;\n"; + } + break; + + case TextureFormat::RGB565: + { + ss << " ocol0 = float4(float((raw_value >> 10) & 0x1Fu) / 31.0\n"; + ss << " float((raw_value >> 5) & 0x1Fu) / 31.0,\n"; + ss << " float(raw_value & 0x1Fu) / 31.0,, 1.0);\n"; + } + break; + + case TextureFormat::RGB5A3: + { + ss << " if ((raw_value & 0x8000u) != 0u) {\n"; + ss << " ocol0 = float4(float((raw_value >> 10) & 0x1Fu) / 31.0,\n"; + ss << " float((raw_value >> 5) & 0x1Fu) / 31.0,\n"; + ss << " float(raw_value & 0x1Fu) / 31.0, 1.0);\n"; + ss << " } else {\n"; + ss << " ocol0 = float4(float((raw_value >> 8) & 0x0Fu) / 15.0,\n"; + ss << " float((raw_value >> 4) & 0x0Fu) / 15.0,\n"; + ss << " float(raw_value & 0x0Fu) / 15.0,\n"; + ss << " float((raw_value >> 12) & 0x07u) / 7.0);\n"; + ss << " }\n"; + } + break; + } + + ss << "}\n"; + return ss.str(); +} + } // namespace FramebufferShaderGen |
