1 #include <cstdarg>
2 
3 #include "Common/GPU/Shader.h"
4 #include "Common/GPU/ShaderWriter.h"
5 #include "GPU/Common/ReinterpretFramebuffer.h"
6 
7 static const VaryingDef varyings[1] = {
8 	{ "vec2", "v_texcoord", "TEXCOORD0", 0, "highp" },
9 };
10 
11 // TODO: We could possibly have an option to preserve any extra color precision? But gonna start without it.
12 // Requires full size integer math. It would be possible to make a floating point-only version with lots of
13 // modulo and stuff, might do it one day.
GenerateReinterpretFragmentShader(char * buffer,GEBufferFormat from,GEBufferFormat to,const ShaderLanguageDesc & lang)14 bool GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBufferFormat to, const ShaderLanguageDesc &lang) {
15 	if (!lang.bitwiseOps) {
16 		return false;
17 	}
18 
19 	ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0);
20 
21 	writer.HighPrecisionFloat();
22 
23 	writer.DeclareSampler2D("samp", 0);
24 	writer.DeclareTexture2D("tex", 0);
25 
26 	writer.BeginFSMain(Slice<UniformDef>::empty(), varyings);
27 
28 	writer.C("  vec4 val = ").SampleTexture2D("tex", "samp", "v_texcoord.xy").C(";\n");
29 
30 	switch (from) {
31 	case GE_FORMAT_4444:
32 		writer.C("  uint color = uint(val.r * 15.99) | (uint(val.g * 15.99) << 4u) | (uint(val.b * 15.99) << 8u) | (uint(val.a * 15.99) << 12u);\n");
33 		break;
34 	case GE_FORMAT_5551:
35 		writer.C("  uint color = uint(val.r * 31.99) | (uint(val.g * 31.99) << 5u) | (uint(val.b * 31.99) << 10u);\n");
36 		writer.C("  if (val.a >= 0.5) color |= 0x8000U;\n");
37 		break;
38 	case GE_FORMAT_565:
39 		writer.C("  uint color = uint(val.r * 31.99) | (uint(val.g * 63.99) << 5u) | (uint(val.b * 31.99) << 11u);\n");
40 		break;
41 	default:
42 		_assert_(false);
43 		break;
44 	}
45 
46 	switch (to) {
47 	case GE_FORMAT_4444:
48 		writer.C("  vec4 outColor = vec4(float(color & 0xFU), float((color >> 4u) & 0xFU), float((color >> 8u) & 0xFU), float((color >> 12u) & 0xFU));\n");
49 		writer.C("  outColor *= 1.0 / 15.0;\n");
50 		break;
51 	case GE_FORMAT_5551:
52 		writer.C("  vec4 outColor = vec4(float(color & 0x1FU), float((color >> 5u) & 0x1FU), float((color >> 10u) & 0x1FU), 0.0);\n");
53 		writer.C("  outColor.rgb *= 1.0 / 31.0;\n");
54 		writer.C("  outColor.a = float(color >> 15);\n");
55 		break;
56 	case GE_FORMAT_565:
57 		writer.C("  vec4 outColor = vec4(float(color & 0x1FU), float((color >> 5u) & 0x3FU), float((color >> 11u) & 0x1FU), 1.0);\n");
58 		writer.C("  outColor.rb *= 1.0 / 31.0;\n");
59 		writer.C("  outColor.g *= 1.0 / 63.0;\n");
60 		break;
61 	default:
62 		_assert_(false);
63 		break;
64 	}
65 
66 	writer.EndFSMain("outColor");
67 	return true;
68 }
69 
GenerateReinterpretVertexShader(char * buffer,const ShaderLanguageDesc & lang)70 bool GenerateReinterpretVertexShader(char *buffer, const ShaderLanguageDesc &lang) {
71 	if (!lang.bitwiseOps) {
72 		return false;
73 	}
74 	ShaderWriter writer(buffer, lang, ShaderStage::Vertex, nullptr, 0);
75 
76 	writer.BeginVSMain(Slice<InputDef>::empty(), Slice<UniformDef>::empty(), varyings);
77 
78 	writer.C("  float x = -1.0 + float((gl_VertexIndex & 1) << 2);\n");
79 	writer.C("  float y = -1.0 + float((gl_VertexIndex & 2) << 1);\n");
80 	writer.C("  v_texcoord = (vec2(x, y) + vec2(1.0, 1.0)) * 0.5;\n");
81 	writer.F("  y *= %s1.0;\n", lang.viewportYSign);
82 	writer.C("  gl_Position = vec4(x, y, 0.0, 1.0);\n");
83 
84 	writer.EndVSMain(varyings);
85 	return true;
86 }
87