1 #include <cstdarg>
2 #include <cstdio>
3 #include <cstring>
4 
5 #include "Common/GPU/Shader.h"
6 #include "Common/GPU/ShaderWriter.h"
7 
8 const char *vulkan_glsl_preamble_fs =
9 "#version 450\n"
10 "#extension GL_ARB_separate_shader_objects : enable\n"
11 "#extension GL_ARB_shading_language_420pack : enable\n"
12 "#extension GL_ARB_conservative_depth : enable\n"
13 "#extension GL_ARB_shader_image_load_store : enable\n"
14 "#define splat3(x) vec3(x)\n"
15 "#define DISCARD discard\n"
16 "precision lowp float;\n"
17 "precision highp int;\n"
18 "\n";
19 
20 const char *hlsl_preamble_fs =
21 "#define vec2 float2\n"
22 "#define vec3 float3\n"
23 "#define vec4 float4\n"
24 "#define uvec3 uint3\n"
25 "#define uvec4 uint4\n"
26 "#define ivec3 int3\n"
27 "#define ivec4 int4\n"
28 "#define mat4 float4x4\n"
29 "#define mat3x4 float4x3\n"  // note how the conventions are backwards
30 "#define splat3(x) float3(x, x, x)\n"
31 "#define mix lerp\n"
32 "#define lowp\n"
33 "#define mediump\n"
34 "#define highp\n"
35 "#define mod(x, y) fmod(x, y)\n";
36 
37 const char *hlsl_d3d11_preamble_fs =
38 "#define DISCARD discard\n"
39 "#define DISCARD_BELOW(x) clip(x);\n";
40 const char *hlsl_d3d9_preamble_fs =
41 "#define DISCARD clip(-1)\n"
42 "#define DISCARD_BELOW(x) clip(x)\n";
43 
44 const char *vulkan_glsl_preamble_vs =
45 "#version 450\n"
46 "#extension GL_ARB_separate_shader_objects : enable\n"
47 "#extension GL_ARB_shading_language_420pack : enable\n"
48 "#define mul(x, y) ((x) * (y))\n"
49 "#define splat3(x) vec3(x)\n"
50 "precision highp float;\n"
51 "\n";
52 
53 const char *hlsl_preamble_vs =
54 "#define vec2 float2\n"
55 "#define vec3 float3\n"
56 "#define vec4 float4\n"
57 "#define ivec2 int2\n"
58 "#define ivec4 int4\n"
59 "#define mat4 float4x4\n"
60 "#define mat3x4 float4x3\n"  // note how the conventions are backwards
61 "#define splat3(x) vec3(x, x, x)\n"
62 "#define lowp\n"
63 "#define mediump\n"
64 "#define highp\n"
65 "\n";
66 
67 // Unsafe. But doesn't matter, we'll use big buffers for shader gen.
F(const char * format,...)68 ShaderWriter & ShaderWriter::F(const char *format, ...) {
69 	va_list args;
70 	va_start(args, format);
71 	p_ += vsprintf(p_, format, args);
72 	va_end(args);
73 	return *this;
74 }
75 
Preamble(const char ** gl_extensions,size_t num_gl_extensions)76 void ShaderWriter::Preamble(const char **gl_extensions, size_t num_gl_extensions) {
77 	switch (lang_.shaderLanguage) {
78 	case GLSL_VULKAN:
79 		switch (stage_) {
80 		case ShaderStage::Vertex:
81 			W(vulkan_glsl_preamble_vs);
82 			break;
83 		case ShaderStage::Fragment:
84 			W(vulkan_glsl_preamble_fs);
85 			break;
86 		default:
87 			break;
88 		}
89 		break;
90 	case HLSL_D3D11:
91 	case HLSL_D3D9:
92 		switch (stage_) {
93 		case ShaderStage::Vertex:
94 			W(hlsl_preamble_vs);
95 			break;
96 		case ShaderStage::Fragment:
97 			W(hlsl_preamble_fs);
98 			if (lang_.shaderLanguage == HLSL_D3D9) {
99 				W(hlsl_d3d9_preamble_fs);
100 			} else {
101 				W(hlsl_d3d11_preamble_fs);
102 			}
103 			break;
104 		default:
105 			break;
106 		}
107 		break;
108 	default:  // OpenGL
109 		F("#version %d%s\n", lang_.glslVersionNumber, lang_.gles && lang_.glslES30 ? " es" : "");
110 		// IMPORTANT! Extensions must be the first thing after #version.
111 		for (size_t i = 0; i < num_gl_extensions; i++) {
112 			F("%s\n", gl_extensions[i]);
113 		}
114 		// Print some system info - useful to gather information directly from screenshots.
115 		F("// %s\n", lang_.driverInfo);
116 		switch (stage_) {
117 		case ShaderStage::Fragment:
118 			C("#define DISCARD discard\n");
119 			if (lang_.gles) {
120 				C("precision lowp float;\n");
121 				if (lang_.glslES30) {
122 					C("precision highp int;\n");
123 				}
124 			}
125 			break;
126 		case ShaderStage::Vertex:
127 			if (lang_.gles) {
128 				C("precision highp float;\n");
129 			}
130 			C("#define gl_VertexIndex gl_VertexID\n");
131 			break;
132 		default:
133 			break;
134 		}
135 		if (!lang_.gles) {
136 			C("#define lowp\n");
137 			C("#define mediump\n");
138 			C("#define highp\n");
139 		}
140 		C("#define splat3(x) vec3(x)\n");
141 		C("#define mul(x, y) ((x) * (y))\n");
142 		break;
143 	}
144 }
145 
BeginVSMain(Slice<InputDef> inputs,Slice<UniformDef> uniforms,Slice<VaryingDef> varyings)146 void ShaderWriter::BeginVSMain(Slice<InputDef> inputs, Slice<UniformDef> uniforms, Slice<VaryingDef> varyings) {
147 	_assert_(this->stage_ == ShaderStage::Vertex);
148 	switch (lang_.shaderLanguage) {
149 	case HLSL_D3D11:
150 	case HLSL_D3D9:
151 	{
152 		C("struct VS_OUTPUT {\n");
153 		for (auto &varying : varyings) {
154 			F("  %s %s : %s;\n", varying.type, varying.name, varying.semantic);
155 		}
156 		F("  vec4 pos : %s;\n", lang_.shaderLanguage == HLSL_D3D11 ? "SV_Position" : "POSITION");
157 		C("};\n");
158 
159 		C("VS_OUTPUT main(  ");  // 2 spaces for the D3D9 rewind
160 		if (lang_.shaderLanguage == HLSL_D3D11) {
161 			C("uint gl_VertexIndex : SV_VertexID, ");
162 		}
163 		Rewind(2);  // Get rid of the last comma.
164 		C(") {\n");
165 		C("  vec4 gl_Position;\n");
166 		for (auto &varying : varyings) {
167 			F("  %s %s;\n", varying.type, varying.name);
168 		}
169 		break;
170 	}
171 	case GLSL_VULKAN:
172 		for (auto &varying : varyings) {
173 			F("layout(location = %d) %s out %s %s;  // %s\n",
174 				varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic);
175 		}
176 		C("void main() {\n");
177 		break;
178 	default:  // OpenGL
179 		for (auto &varying : varyings) {
180 			F("%s %s %s %s;  // %s (%d)\n", lang_.varying_vs, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic, varying.index);
181 		}
182 		C("void main() {\n");
183 		break;
184 	}
185 }
186 
BeginFSMain(Slice<UniformDef> uniforms,Slice<VaryingDef> varyings)187 void ShaderWriter::BeginFSMain(Slice<UniformDef> uniforms, Slice<VaryingDef> varyings) {
188 	_assert_(this->stage_ == ShaderStage::Fragment);
189 	switch (lang_.shaderLanguage) {
190 	case HLSL_D3D11:
191 		if (!uniforms.is_empty()) {
192 			for (auto &uniform : uniforms) {
193 				//F("  %s %s : %s;\n", uniform.type, uniform.name, uniform.index);
194 			}
195 		}
196 		// Let's do the varyings as parameters to main, no struct.
197 		C("vec4 main(");
198 		for (auto &varying : varyings) {
199 			F("  %s %s : %s, ", varying.type, varying.name, varying.semantic);
200 		}
201 		// Erase the last comma
202 		Rewind(2);
203 
204 		F(") : SV_Target0 {\n");
205 		break;
206 	case HLSL_D3D9:
207 		for (auto &uniform : uniforms) {
208 			F("  %s %s : register(c%d);\n", uniform.type, uniform.name, uniform.index);
209 		}
210 		// Let's do the varyings as parameters to main, no struct.
211 		C("vec4 main(");
212 		for (auto &varying : varyings) {
213 			F("  %s %s : %s, ", varying.type, varying.name, varying.semantic);
214 		}
215 		// Erase the last comma
216 		Rewind(2);
217 
218 		F(") : COLOR {\n");
219 		break;
220 	case GLSL_VULKAN:
221 		for (auto &varying : varyings) {
222 			F("layout(location = %d) %s in %s %s;  // %s\n", varying.index, varying.precision ? varying.precision : "", varying.type, varying.name,  varying.semantic);
223 		}
224 		C("layout(location = 0, index = 0) out vec4 fragColor0;\n");
225 		C("\nvoid main() {\n");
226 		break;
227 	default:
228 		for (auto &varying : varyings) {
229 			F("%s %s %s %s;  // %s\n", lang_.varying_fs, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic);
230 		}
231 		if (!strcmp(lang_.fragColor0, "fragColor0")) {
232 			C("out vec4 fragColor0;\n");
233 		}
234 		C("\nvoid main() {\n");
235 		break;
236 	}
237 }
238 
EndVSMain(Slice<VaryingDef> varyings)239 void ShaderWriter::EndVSMain(Slice<VaryingDef> varyings) {
240 	_assert_(this->stage_ == ShaderStage::Vertex);
241 	switch (lang_.shaderLanguage) {
242 	case HLSL_D3D11:
243 	case HLSL_D3D9:
244 		C("  VS_OUTPUT vs_out;\n");
245 		C("  vs_out.pos = gl_Position;\n");
246 		for (auto &varying : varyings) {
247 			F("  vs_out.%s = %s;\n", varying.name, varying.name);
248 		}
249 		C("  return vs_out;\n");
250 		break;
251 	case GLSL_VULKAN:
252 	default:  // OpenGL
253 		break;
254 	}
255 	C("}\n");
256 }
257 
EndFSMain(const char * vec4_color_variable)258 void ShaderWriter::EndFSMain(const char *vec4_color_variable) {
259 	_assert_(this->stage_ == ShaderStage::Fragment);
260 	switch (lang_.shaderLanguage) {
261 	case HLSL_D3D11:
262 	case HLSL_D3D9:
263 		F("  return %s;\n", vec4_color_variable);
264 		break;
265 	case GLSL_VULKAN:
266 	default:  // OpenGL
267 		F("  %s = %s;\n", lang_.fragColor0, vec4_color_variable);
268 		break;
269 	}
270 	C("}\n");
271 }
272 
HighPrecisionFloat()273 void ShaderWriter::HighPrecisionFloat() {
274 	if ((ShaderLanguageIsOpenGL(lang_.shaderLanguage) && lang_.gles) || lang_.shaderLanguage == GLSL_VULKAN) {
275 		C("precision highp float;\n");
276 	}
277 }
278 
DeclareTexture2D(const char * name,int binding)279 void ShaderWriter::DeclareTexture2D(const char *name, int binding) {
280 	switch (lang_.shaderLanguage) {
281 	case HLSL_D3D11:
282 		F("Texture2D<float4> %s : register(t%d);\n", name, binding);
283 		break;
284 	case HLSL_D3D9:
285 		break;
286 	case GLSL_VULKAN:
287 		// In the thin3d descriptor set layout, textures start at 1 in set 0. Hence the +1.
288 		F("layout(set = 0, binding = %d) uniform sampler2D %s;\n", binding + 1, name);
289 		break;
290 	default:
291 		F("uniform sampler2D %s;\n", name);
292 		break;
293 	}
294 }
295 
DeclareSampler2D(const char * name,int binding)296 void ShaderWriter::DeclareSampler2D(const char *name, int binding) {
297 	// We only use separate samplers in HLSL D3D11, where we have no choice.
298 	switch (lang_.shaderLanguage) {
299 	case HLSL_D3D11:
300 		F("SamplerState %s : register(s%d);\n", name, binding);
301 		break;
302 	default:
303 		break;
304 	}
305 }
306 
SampleTexture2D(const char * texName,const char * samplerName,const char * uv)307 ShaderWriter &ShaderWriter::SampleTexture2D(const char *texName, const char *samplerName, const char *uv) {
308 	switch (lang_.shaderLanguage) {
309 	case HLSL_D3D11:
310 		F("%s.Sample(%s, %s)", texName, samplerName, uv);
311 		break;
312 	case HLSL_D3D9:
313 		F("tex2D(%s, %s)", texName, uv);
314 		break;
315 	default:
316 		// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.
317 		F("%s(%s, %s)", lang_.texture, texName, uv);
318 		break;
319 	}
320 	return *this;
321 }
322