Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/GPU/ShaderWriter.cpp
3187 views
1
#include <cstdarg>
2
#include <cstdio>
3
#include <cstring>
4
5
#include "Common/GPU/Shader.h"
6
#include "Common/GPU/ShaderWriter.h"
7
#include "Common/Log.h"
8
9
const char * const vulkan_glsl_preamble_fs =
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 * const 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 ivec2 int2\n"
27
"#define ivec3 int3\n"
28
"#define ivec4 int4\n"
29
"#define mat4 float4x4\n"
30
"#define mat3x4 float4x3\n" // note how the conventions are backwards
31
"#define splat3(x) float3(x, x, x)\n"
32
"#define mix lerp\n"
33
"#define lowp\n"
34
"#define mediump\n"
35
"#define highp\n"
36
"#define fract frac\n"
37
"#define mod(x, y) fmod(x, y)\n";
38
39
static const char * const hlsl_d3d11_preamble_fs =
40
"#define DISCARD discard\n"
41
"#define DISCARD_BELOW(x) clip(x);\n";
42
43
static const char * const vulkan_glsl_preamble_vs =
44
"#extension GL_ARB_separate_shader_objects : enable\n"
45
"#extension GL_ARB_shading_language_420pack : enable\n"
46
"#define mul(x, y) ((x) * (y))\n"
47
"#define splat3(x) vec3(x)\n"
48
"precision highp float;\n"
49
"\n";
50
51
static const char * const hlsl_preamble_gs =
52
"#define vec2 float2\n"
53
"#define vec3 float3\n"
54
"#define vec4 float4\n"
55
"#define ivec2 int2\n"
56
"#define ivec4 int4\n"
57
"#define mat2 float2x2\n"
58
"#define mat4 float4x4\n"
59
"#define mat3x4 float4x3\n" // note how the conventions are backwards
60
"#define splat3(x) vec3(x, x, x)\n"
61
"#define lowp\n"
62
"#define mediump\n"
63
"#define highp\n"
64
"\n";
65
66
static const char * const vulkan_glsl_preamble_gs =
67
"#extension GL_ARB_separate_shader_objects : enable\n"
68
"#extension GL_ARB_shading_language_420pack : enable\n"
69
"#define mul(x, y) ((x) * (y))\n"
70
"#define splat3(x) vec3(x)\n"
71
"precision highp float;\n"
72
"\n";
73
74
static const char * const hlsl_preamble_vs =
75
"#define vec2 float2\n"
76
"#define vec3 float3\n"
77
"#define vec4 float4\n"
78
"#define ivec2 int2\n"
79
"#define ivec4 int4\n"
80
"#define mat2 float2x2\n"
81
"#define mat4 float4x4\n"
82
"#define mat3x4 float4x3\n" // note how the conventions are backwards
83
"#define splat3(x) vec3(x, x, x)\n"
84
"#define lowp\n"
85
"#define mediump\n"
86
"#define highp\n"
87
"\n";
88
89
static const char * const semanticNames[] = {
90
"POSITION",
91
"COLOR0",
92
"COLOR1",
93
"TEXCOORD0",
94
"TEXCOORD1",
95
"NORMAL",
96
"TANGENT",
97
"BINORMAL",
98
};
99
static_assert(ARRAY_SIZE(semanticNames) == Draw::SEM_MAX, "Missing semantic in semanticNames");
100
101
// Unsafe. But doesn't matter, we'll use big buffers for shader gen.
102
ShaderWriter & ShaderWriter::F(const char *format, ...) {
103
va_list args;
104
va_start(args, format);
105
p_ += vsprintf(p_, format, args);
106
va_end(args);
107
return *this;
108
}
109
110
void ShaderWriter::Preamble(Slice<const char *> extensions) {
111
switch (lang_.shaderLanguage) {
112
case GLSL_VULKAN:
113
C("#version 450\n");
114
if (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) {
115
C("#extension GL_EXT_multiview : enable\n");
116
}
117
// IMPORTANT! Extensions must be the first thing after #version.
118
for (size_t i = 0; i < extensions.size(); i++) {
119
F("%s\n", extensions[i]);
120
}
121
switch (stage_) {
122
case ShaderStage::Vertex:
123
W(vulkan_glsl_preamble_vs);
124
break;
125
case ShaderStage::Fragment:
126
W(vulkan_glsl_preamble_fs);
127
break;
128
case ShaderStage::Geometry:
129
W(vulkan_glsl_preamble_gs);
130
break;
131
default:
132
break;
133
}
134
break;
135
case HLSL_D3D11:
136
switch (stage_) {
137
case ShaderStage::Vertex:
138
W(hlsl_preamble_vs);
139
break;
140
case ShaderStage::Fragment:
141
W(hlsl_preamble_fs);
142
W(hlsl_d3d11_preamble_fs);
143
break;
144
case ShaderStage::Geometry:
145
W(hlsl_preamble_gs);
146
break;
147
default:
148
break;
149
}
150
break;
151
default: // OpenGL
152
F("#version %d%s\n", lang_.glslVersionNumber, lang_.gles && lang_.glslES30 ? " es" : "");
153
// IMPORTANT! Extensions must be the first thing after #version.
154
for (size_t i = 0; i < extensions.size(); i++) {
155
F("%s\n", extensions[i]);
156
}
157
// Print some system info - useful to gather information directly from screenshots.
158
if (strlen(lang_.driverInfo) != 0) {
159
F("// Driver: %s\n", lang_.driverInfo);
160
}
161
switch (stage_) {
162
case ShaderStage::Fragment:
163
C("#define DISCARD discard\n");
164
if (lang_.gles) {
165
C("precision lowp float;\n");
166
if (lang_.glslES30) {
167
C("precision highp int;\n");
168
}
169
}
170
break;
171
case ShaderStage::Vertex:
172
if (lang_.gles) {
173
C("precision highp float;\n");
174
}
175
C("#define gl_VertexIndex gl_VertexID\n");
176
break;
177
case ShaderStage::Geometry:
178
if (lang_.gles) {
179
C("precision highp float;\n");
180
}
181
break;
182
default:
183
break;
184
}
185
if (!lang_.gles) {
186
C("#define lowp\n");
187
C("#define mediump\n");
188
C("#define highp\n");
189
}
190
C("#define splat3(x) vec3(x)\n");
191
C("#define mul(x, y) ((x) * (y))\n");
192
break;
193
}
194
}
195
196
void ShaderWriter::BeginVSMain(Slice<InputDef> inputs, Slice<UniformDef> uniforms, Slice<VaryingDef> varyings) {
197
_assert_(this->stage_ == ShaderStage::Vertex);
198
switch (lang_.shaderLanguage) {
199
case HLSL_D3D11:
200
{
201
C("struct VS_OUTPUT {\n");
202
for (auto &varying : varyings) {
203
F(" %s %s : %s;\n", varying.type, varying.name, semanticNames[varying.semantic]);
204
}
205
F(" vec4 pos : %s;\n", lang_.shaderLanguage == HLSL_D3D11 ? "SV_Position" : "POSITION");
206
C("};\n");
207
208
C("VS_OUTPUT main( "); // 2 spaces for the rewind
209
C("uint gl_VertexIndex : SV_VertexID, ");
210
// List the inputs.
211
for (auto &input : inputs) {
212
F("in %s %s : %s, ", input.type, input.name, semanticNames[input.semantic]);
213
}
214
215
Rewind(2); // Get rid of the last comma.
216
C(") {\n");
217
C(" vec4 gl_Position;\n");
218
for (auto &varying : varyings) {
219
F(" %s %s; // %s\n", varying.type, varying.name, semanticNames[varying.semantic]);
220
}
221
break;
222
}
223
case GLSL_VULKAN:
224
{
225
for (auto &input : inputs) {
226
F("layout(location = %d) in %s %s;\n", input.semantic /*index*/, input.type, input.name);
227
}
228
for (auto &varying : varyings) {
229
F("layout(location = %d) %s out %s %s; // %s\n",
230
varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic]);
231
}
232
C("void main() {\n");
233
break;
234
}
235
default: // OpenGL
236
for (auto &input : inputs) {
237
F("%s %s %s;\n", lang_.attribute, input.type, input.name);
238
}
239
for (auto &varying : varyings) {
240
F("%s %s %s %s; // %s (%d)\n", lang_.varying_vs, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic], varying.index);
241
}
242
C("void main() {\n");
243
break;
244
}
245
}
246
247
void ShaderWriter::BeginFSMain(Slice<UniformDef> uniforms, Slice<VaryingDef> varyings) {
248
_assert_(this->stage_ == ShaderStage::Fragment);
249
switch (lang_.shaderLanguage) {
250
case HLSL_D3D11:
251
if (!uniforms.is_empty()) {
252
C("cbuffer base : register(b0) {\n");
253
254
for (auto &uniform : uniforms) {
255
F(" %s %s;\n", uniform.type, uniform.name);
256
}
257
258
C("};\n");
259
}
260
261
if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) {
262
C("float gl_FragDepth;\n");
263
}
264
265
C("struct PS_OUT {\n");
266
C(" vec4 target : SV_Target0;\n");
267
if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) {
268
C(" float depth : SV_Depth;\n");
269
}
270
C("};\n");
271
272
// Let's do the varyings as parameters to main, no struct.
273
C("PS_OUT main(");
274
for (auto &varying : varyings) {
275
F(" %s %s : %s, ", varying.type, varying.name, semanticNames[varying.semantic]);
276
}
277
// Erase the last comma
278
Rewind(2);
279
280
F(") {\n");
281
C(" PS_OUT ps_out;\n");
282
if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) {
283
C(" float gl_FragDepth;\n");
284
}
285
break;
286
case GLSL_VULKAN:
287
for (auto &varying : varyings) {
288
F("layout(location = %d) %s in %s %s; // %s\n", varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic]);
289
}
290
C("layout(location = 0, index = 0) out vec4 fragColor0;\n");
291
if (!uniforms.is_empty()) {
292
C("layout(std140, set = 0, binding = 0) uniform bufferVals {\n");
293
for (auto &uniform : uniforms) {
294
F("%s %s;\n", uniform.type, uniform.name);
295
}
296
C("};\n");
297
}
298
C("\nvoid main() {\n");
299
break;
300
301
default: // GLSL OpenGL
302
for (auto &varying : varyings) {
303
F("%s %s %s %s; // %s\n", lang_.varying_fs, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic]);
304
}
305
for (auto &uniform : uniforms) {
306
F("uniform %s %s;\n", uniform.type, uniform.name);
307
}
308
if (!strcmp(lang_.fragColor0, "fragColor0")) {
309
C("out vec4 fragColor0;\n");
310
}
311
C("\nvoid main() {\n");
312
break;
313
}
314
}
315
316
void ShaderWriter::BeginGSMain(Slice<VaryingDef> varyings, Slice<VaryingDef> outVaryings) {
317
_assert_(this->stage_ == ShaderStage::Geometry);
318
switch (lang_.shaderLanguage) {
319
case HLSL_D3D11:
320
// Untested, but should work.
321
C("\nstruct GS_OUTPUT {\n");
322
for (auto &varying : outVaryings) {
323
F(" %s %s : %s;\n", varying.type, varying.name, semanticNames[varying.semantic]);
324
}
325
F(" vec4 pos : %s;\n", lang_.shaderLanguage == HLSL_D3D11 ? "SV_Position" : "POSITION");
326
C("};\n");
327
C("#define EmitVertex() emit.Append(gsout)\n");
328
329
C("void main(");
330
for (auto &varying : varyings) {
331
F(" in %s %s : %s, ", varying.type, varying.name, semanticNames[varying.semantic]);
332
}
333
C("inout TriangleStream<GS_OUTPUT> emit) {\n");
334
C(" GS_OUTPUT gsout;\n");
335
break;
336
case GLSL_VULKAN:
337
for (auto &varying : varyings) {
338
F("layout(location = %d) %s in %s %s[]; // %s\n", varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic]);
339
}
340
for (auto &varying : outVaryings) {
341
F("layout(location = %d) %s out %s %s; // %s\n", varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic]);
342
}
343
C("\nvoid main() {\n");
344
break;
345
case GLSL_3xx:
346
C("\nvoid main() {\n");
347
break;
348
default:
349
break;
350
}
351
}
352
353
void ShaderWriter::EndVSMain(Slice<VaryingDef> varyings) {
354
_assert_(this->stage_ == ShaderStage::Vertex);
355
switch (lang_.shaderLanguage) {
356
case HLSL_D3D11:
357
C(" VS_OUTPUT vs_out;\n");
358
if (strlen(lang_.viewportYSign)) {
359
F(" gl_Position.y *= %s1.0;\n", lang_.viewportYSign);
360
}
361
C(" vs_out.pos = gl_Position;\n");
362
for (auto &varying : varyings) {
363
F(" vs_out.%s = %s;\n", varying.name, varying.name);
364
}
365
C(" return vs_out;\n");
366
break;
367
case GLSL_VULKAN:
368
default: // OpenGL
369
break;
370
}
371
C("}\n");
372
}
373
374
void ShaderWriter::EndFSMain(const char *vec4_color_variable) {
375
_assert_(this->stage_ == ShaderStage::Fragment);
376
switch (lang_.shaderLanguage) {
377
case HLSL_D3D11:
378
F(" ps_out.target = %s;\n", vec4_color_variable);
379
if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) {
380
C(" ps_out.depth = gl_FragDepth;\n");
381
}
382
C(" return ps_out;\n");
383
break;
384
case GLSL_VULKAN:
385
default: // OpenGL
386
F(" %s = %s;\n", lang_.fragColor0, vec4_color_variable);
387
break;
388
}
389
C("}\n");
390
}
391
392
void ShaderWriter::EndGSMain() {
393
_assert_(this->stage_ == ShaderStage::Geometry);
394
C("}\n");
395
}
396
397
void ShaderWriter::HighPrecisionFloat() {
398
if ((ShaderLanguageIsOpenGL(lang_.shaderLanguage) && lang_.gles) || lang_.shaderLanguage == GLSL_VULKAN) {
399
C("precision highp float;\n");
400
}
401
}
402
403
void ShaderWriter::LowPrecisionFloat() {
404
if ((ShaderLanguageIsOpenGL(lang_.shaderLanguage) && lang_.gles) || lang_.shaderLanguage == GLSL_VULKAN) {
405
C("precision lowp float;\n");
406
}
407
}
408
409
void ShaderWriter::ConstFloat(const char *name, float value) {
410
switch (lang_.shaderLanguage) {
411
case HLSL_D3D11:
412
F("static const float %s = %f;\n", name, value);
413
break;
414
default:
415
F("#define %s %f\n", name, value);
416
break;
417
}
418
}
419
420
void ShaderWriter::DeclareSamplers(Slice<SamplerDef> samplers) {
421
for (int i = 0; i < (int)samplers.size(); i++) {
422
DeclareTexture2D(samplers[i]);
423
DeclareSampler2D(samplers[i]);
424
}
425
samplerDefs_ = samplers;
426
}
427
428
void ShaderWriter::ApplySamplerMetadata(Slice<SamplerDef> samplers) {
429
samplerDefs_ = samplers;
430
}
431
432
void ShaderWriter::DeclareTexture2D(const SamplerDef &def) {
433
switch (lang_.shaderLanguage) {
434
case HLSL_D3D11:
435
F("Texture2D<float4> %s : register(t%d);\n", def.name, def.binding);
436
break;
437
case GLSL_VULKAN:
438
// texBindingBase_ is used for the thin3d descriptor set layout, where they start at 1.
439
if (def.flags & SamplerFlags::ARRAY_ON_VULKAN) {
440
F("layout(set = 0, binding = %d) uniform sampler2DArray %s;\n", def.binding + texBindingBase_, def.name);
441
} else {
442
F("layout(set = 0, binding = %d) uniform sampler2D %s;\n", def.binding + texBindingBase_, def.name);
443
}
444
break;
445
default:
446
F("uniform sampler2D %s;\n", def.name);
447
break;
448
}
449
}
450
451
void ShaderWriter::DeclareSampler2D(const SamplerDef &def) {
452
// We only use separate samplers in HLSL D3D11, where we have no choice.
453
switch (lang_.shaderLanguage) {
454
case HLSL_D3D11:
455
F("SamplerState %sSamp : register(s%d);\n", def.name, def.binding);
456
break;
457
default:
458
break;
459
}
460
}
461
462
ShaderWriter &ShaderWriter::SampleTexture2D(const char *sampName, const char *uv) {
463
const SamplerDef *samp = GetSamplerDef(sampName);
464
switch (lang_.shaderLanguage) {
465
case HLSL_D3D11:
466
F("%s.Sample(%sSamp, %s)", sampName, sampName, uv);
467
break;
468
default:
469
// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.
470
if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) {
471
const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "float(gl_ViewIndex)" : "0.0";
472
F("%s(%s, vec3(%s, %s))", lang_.texture, sampName, uv, index);
473
} else {
474
F("%s(%s, %s)", lang_.texture, sampName, uv);
475
}
476
break;
477
}
478
return *this;
479
}
480
481
ShaderWriter &ShaderWriter::SampleTexture2DOffset(const char *sampName, const char *uv, int offX, int offY) {
482
const SamplerDef *samp = GetSamplerDef(sampName);
483
484
switch (lang_.shaderLanguage) {
485
case HLSL_D3D11:
486
F("%s.Sample(%sSamp, %s, int2(%d, %d))", sampName, sampName, uv, offX, offY);
487
break;
488
default:
489
// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.
490
if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) {
491
const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "float(gl_ViewIndex)" : "0.0";
492
F("%sOffset(%s, vec3(%s, %s), ivec2(%d, %d))", lang_.texture, sampName, uv, index, offX, offY);
493
} else {
494
F("%sOffset(%s, %s, ivec2(%d, %d))", lang_.texture, sampName, uv, offX, offY);
495
}
496
break;
497
}
498
return *this;
499
}
500
501
ShaderWriter &ShaderWriter::LoadTexture2D(const char *sampName, const char *uv, int level) {
502
const SamplerDef *samp = GetSamplerDef(sampName);
503
504
switch (lang_.shaderLanguage) {
505
case HLSL_D3D11:
506
F("%s.Load(ivec3(%s, %d))", sampName, uv, level);
507
break;
508
default:
509
// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.
510
if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) {
511
const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "gl_ViewIndex" : "0";
512
F("texelFetch(%s, vec3(%s, %s), %d)", sampName, uv, index, level);
513
} else {
514
F("texelFetch(%s, %s, %d)", sampName, uv, level);
515
}
516
break;
517
}
518
return *this;
519
}
520
521
ShaderWriter &ShaderWriter::GetTextureSize(const char *szVariable, const char *texName) {
522
switch (lang_.shaderLanguage) {
523
case HLSL_D3D11:
524
F(" float2 %s; %s.GetDimensions(%s.x, %s.y);", szVariable, texName, szVariable, szVariable);
525
break;
526
default:
527
// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.
528
F("vec2 %s = textureSize(%s, 0);", szVariable, texName);
529
break;
530
}
531
return *this;
532
}
533
534
const SamplerDef *ShaderWriter::GetSamplerDef(const char *name) const {
535
for (int i = 0; i < (int)samplerDefs_.size(); i++) {
536
if (!strcmp(samplerDefs_[i].name, name)) {
537
return &samplerDefs_[i];
538
}
539
}
540
return nullptr;
541
}
542
543