2020-11-04 08:18:35 +00:00
|
|
|
#include <cstdarg>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cstring>
|
|
|
|
|
|
|
|
#include "Common/GPU/Shader.h"
|
|
|
|
#include "Common/GPU/ShaderWriter.h"
|
2022-01-30 23:49:02 +00:00
|
|
|
#include "Common/Log.h"
|
2020-11-02 07:59:30 +00:00
|
|
|
|
2022-08-03 10:32:42 +00:00
|
|
|
const char * const vulkan_glsl_preamble_fs =
|
2020-11-02 07:59:30 +00:00
|
|
|
"#version 450\n"
|
|
|
|
"#extension GL_ARB_separate_shader_objects : enable\n"
|
|
|
|
"#extension GL_ARB_shading_language_420pack : enable\n"
|
|
|
|
"#extension GL_ARB_conservative_depth : enable\n"
|
|
|
|
"#extension GL_ARB_shader_image_load_store : enable\n"
|
|
|
|
"#define splat3(x) vec3(x)\n"
|
|
|
|
"#define DISCARD discard\n"
|
2020-11-10 21:26:34 +00:00
|
|
|
"precision lowp float;\n"
|
|
|
|
"precision highp int;\n"
|
2020-11-02 07:59:30 +00:00
|
|
|
"\n";
|
|
|
|
|
2022-08-03 10:32:42 +00:00
|
|
|
const char * const hlsl_preamble_fs =
|
2020-11-02 07:59:30 +00:00
|
|
|
"#define vec2 float2\n"
|
|
|
|
"#define vec3 float3\n"
|
|
|
|
"#define vec4 float4\n"
|
|
|
|
"#define uvec3 uint3\n"
|
2020-11-08 22:17:06 +00:00
|
|
|
"#define uvec4 uint4\n"
|
2020-11-02 07:59:30 +00:00
|
|
|
"#define ivec3 int3\n"
|
|
|
|
"#define ivec4 int4\n"
|
|
|
|
"#define mat4 float4x4\n"
|
|
|
|
"#define mat3x4 float4x3\n" // note how the conventions are backwards
|
|
|
|
"#define splat3(x) float3(x, x, x)\n"
|
|
|
|
"#define mix lerp\n"
|
2020-11-09 08:10:44 +00:00
|
|
|
"#define lowp\n"
|
|
|
|
"#define mediump\n"
|
|
|
|
"#define highp\n"
|
2020-11-02 07:59:30 +00:00
|
|
|
"#define mod(x, y) fmod(x, y)\n";
|
|
|
|
|
2022-08-03 10:32:42 +00:00
|
|
|
static const char * const hlsl_d3d11_preamble_fs =
|
2020-11-02 07:59:30 +00:00
|
|
|
"#define DISCARD discard\n"
|
|
|
|
"#define DISCARD_BELOW(x) clip(x);\n";
|
2022-08-03 10:32:42 +00:00
|
|
|
static const char * const hlsl_d3d9_preamble_fs =
|
2020-11-02 07:59:30 +00:00
|
|
|
"#define DISCARD clip(-1)\n"
|
|
|
|
"#define DISCARD_BELOW(x) clip(x)\n";
|
|
|
|
|
2022-08-03 10:32:42 +00:00
|
|
|
static const char * const vulkan_glsl_preamble_vs =
|
2020-11-02 07:59:30 +00:00
|
|
|
"#version 450\n"
|
|
|
|
"#extension GL_ARB_separate_shader_objects : enable\n"
|
|
|
|
"#extension GL_ARB_shading_language_420pack : enable\n"
|
|
|
|
"#define mul(x, y) ((x) * (y))\n"
|
|
|
|
"#define splat3(x) vec3(x)\n"
|
2020-11-10 21:26:34 +00:00
|
|
|
"precision highp float;\n"
|
2020-11-02 07:59:30 +00:00
|
|
|
"\n";
|
|
|
|
|
2022-08-03 10:32:42 +00:00
|
|
|
static const char * const hlsl_preamble_vs =
|
2020-11-02 07:59:30 +00:00
|
|
|
"#define vec2 float2\n"
|
|
|
|
"#define vec3 float3\n"
|
|
|
|
"#define vec4 float4\n"
|
|
|
|
"#define ivec2 int2\n"
|
|
|
|
"#define ivec4 int4\n"
|
2021-10-31 12:44:54 +00:00
|
|
|
"#define mat2 float2x2\n"
|
2020-11-02 07:59:30 +00:00
|
|
|
"#define mat4 float4x4\n"
|
|
|
|
"#define mat3x4 float4x3\n" // note how the conventions are backwards
|
|
|
|
"#define splat3(x) vec3(x, x, x)\n"
|
|
|
|
"#define lowp\n"
|
|
|
|
"#define mediump\n"
|
|
|
|
"#define highp\n"
|
|
|
|
"\n";
|
|
|
|
|
2022-08-03 10:32:42 +00:00
|
|
|
static const char * const semanticNames[8] = {
|
|
|
|
"POSITION",
|
|
|
|
"COLOR0",
|
|
|
|
"TEXCOORD0",
|
|
|
|
"TEXCOORD1",
|
|
|
|
"NORMAL",
|
|
|
|
"TANGENT",
|
|
|
|
"BINORMAL",
|
|
|
|
};
|
|
|
|
|
2020-11-02 07:59:30 +00:00
|
|
|
// Unsafe. But doesn't matter, we'll use big buffers for shader gen.
|
2020-11-02 15:12:45 +00:00
|
|
|
ShaderWriter & ShaderWriter::F(const char *format, ...) {
|
2020-11-02 07:59:30 +00:00
|
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
|
|
p_ += vsprintf(p_, format, args);
|
|
|
|
va_end(args);
|
2020-11-02 15:12:45 +00:00
|
|
|
return *this;
|
2020-11-02 07:59:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ShaderWriter::Preamble(const char **gl_extensions, size_t num_gl_extensions) {
|
|
|
|
switch (lang_.shaderLanguage) {
|
|
|
|
case GLSL_VULKAN:
|
|
|
|
switch (stage_) {
|
|
|
|
case ShaderStage::Vertex:
|
|
|
|
W(vulkan_glsl_preamble_vs);
|
|
|
|
break;
|
|
|
|
case ShaderStage::Fragment:
|
|
|
|
W(vulkan_glsl_preamble_fs);
|
|
|
|
break;
|
2020-12-13 15:04:16 +00:00
|
|
|
default:
|
|
|
|
break;
|
2020-11-02 07:59:30 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case HLSL_D3D11:
|
|
|
|
case HLSL_D3D9:
|
|
|
|
switch (stage_) {
|
|
|
|
case ShaderStage::Vertex:
|
|
|
|
W(hlsl_preamble_vs);
|
|
|
|
break;
|
|
|
|
case ShaderStage::Fragment:
|
|
|
|
W(hlsl_preamble_fs);
|
|
|
|
if (lang_.shaderLanguage == HLSL_D3D9) {
|
|
|
|
W(hlsl_d3d9_preamble_fs);
|
|
|
|
} else {
|
|
|
|
W(hlsl_d3d11_preamble_fs);
|
|
|
|
}
|
|
|
|
break;
|
2020-12-13 15:04:16 +00:00
|
|
|
default:
|
|
|
|
break;
|
2020-11-02 07:59:30 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default: // OpenGL
|
2020-11-02 10:45:47 +00:00
|
|
|
F("#version %d%s\n", lang_.glslVersionNumber, lang_.gles && lang_.glslES30 ? " es" : "");
|
2020-11-03 18:53:02 +00:00
|
|
|
// IMPORTANT! Extensions must be the first thing after #version.
|
|
|
|
for (size_t i = 0; i < num_gl_extensions; i++) {
|
|
|
|
F("%s\n", gl_extensions[i]);
|
|
|
|
}
|
2020-11-16 22:26:37 +00:00
|
|
|
// Print some system info - useful to gather information directly from screenshots.
|
|
|
|
F("// %s\n", lang_.driverInfo);
|
2020-11-02 07:59:30 +00:00
|
|
|
switch (stage_) {
|
|
|
|
case ShaderStage::Fragment:
|
2020-11-02 10:45:47 +00:00
|
|
|
C("#define DISCARD discard\n");
|
2020-11-02 07:59:30 +00:00
|
|
|
if (lang_.gles) {
|
2020-11-02 10:45:47 +00:00
|
|
|
C("precision lowp float;\n");
|
2020-11-02 15:12:45 +00:00
|
|
|
if (lang_.glslES30) {
|
|
|
|
C("precision highp int;\n");
|
|
|
|
}
|
2020-11-02 07:59:30 +00:00
|
|
|
}
|
|
|
|
break;
|
2020-11-02 08:21:29 +00:00
|
|
|
case ShaderStage::Vertex:
|
|
|
|
if (lang_.gles) {
|
2020-11-02 10:45:47 +00:00
|
|
|
C("precision highp float;\n");
|
2020-11-02 08:21:29 +00:00
|
|
|
}
|
2020-11-03 14:44:57 +00:00
|
|
|
C("#define gl_VertexIndex gl_VertexID\n");
|
2020-11-02 08:21:29 +00:00
|
|
|
break;
|
2020-12-13 15:04:16 +00:00
|
|
|
default:
|
|
|
|
break;
|
2020-11-02 07:59:30 +00:00
|
|
|
}
|
|
|
|
if (!lang_.gles) {
|
2020-11-02 10:45:47 +00:00
|
|
|
C("#define lowp\n");
|
|
|
|
C("#define mediump\n");
|
|
|
|
C("#define highp\n");
|
2020-11-02 07:59:30 +00:00
|
|
|
}
|
2020-11-02 10:45:47 +00:00
|
|
|
C("#define splat3(x) vec3(x)\n");
|
|
|
|
C("#define mul(x, y) ((x) * (y))\n");
|
2020-11-02 07:59:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-11-02 15:12:45 +00:00
|
|
|
|
|
|
|
void ShaderWriter::BeginVSMain(Slice<InputDef> inputs, Slice<UniformDef> uniforms, Slice<VaryingDef> varyings) {
|
2020-11-03 14:44:57 +00:00
|
|
|
_assert_(this->stage_ == ShaderStage::Vertex);
|
2020-11-02 15:12:45 +00:00
|
|
|
switch (lang_.shaderLanguage) {
|
|
|
|
case HLSL_D3D11:
|
|
|
|
case HLSL_D3D9:
|
2020-11-03 14:44:57 +00:00
|
|
|
{
|
|
|
|
C("struct VS_OUTPUT {\n");
|
|
|
|
for (auto &varying : varyings) {
|
2022-08-03 10:32:42 +00:00
|
|
|
F(" %s %s : %s;\n", varying.type, varying.name, semanticNames[varying.semantic]);
|
2020-11-03 14:44:57 +00:00
|
|
|
}
|
2020-11-06 19:08:57 +00:00
|
|
|
F(" vec4 pos : %s;\n", lang_.shaderLanguage == HLSL_D3D11 ? "SV_Position" : "POSITION");
|
2020-11-03 14:44:57 +00:00
|
|
|
C("};\n");
|
|
|
|
|
|
|
|
C("VS_OUTPUT main( "); // 2 spaces for the D3D9 rewind
|
|
|
|
if (lang_.shaderLanguage == HLSL_D3D11) {
|
|
|
|
C("uint gl_VertexIndex : SV_VertexID, ");
|
|
|
|
}
|
2022-07-24 16:43:27 +00:00
|
|
|
// List the inputs.
|
|
|
|
for (auto &input : inputs) {
|
2022-08-03 10:32:42 +00:00
|
|
|
F("in %s %s : %s, ", input.type, input.name, semanticNames[input.semantic]);
|
2022-07-24 16:43:27 +00:00
|
|
|
}
|
|
|
|
|
2020-11-03 14:44:57 +00:00
|
|
|
Rewind(2); // Get rid of the last comma.
|
|
|
|
C(") {\n");
|
|
|
|
C(" vec4 gl_Position;\n");
|
|
|
|
for (auto &varying : varyings) {
|
2022-08-03 10:32:42 +00:00
|
|
|
F(" %s %s; // %s\n", varying.type, varying.name, semanticNames[varying.semantic]);
|
2020-11-03 14:44:57 +00:00
|
|
|
}
|
2020-11-02 15:12:45 +00:00
|
|
|
break;
|
2020-11-03 14:44:57 +00:00
|
|
|
}
|
2020-11-02 15:12:45 +00:00
|
|
|
case GLSL_VULKAN:
|
2022-07-24 16:29:11 +00:00
|
|
|
{
|
|
|
|
for (auto &input : inputs) {
|
2022-08-03 10:32:42 +00:00
|
|
|
F("layout(location = %d) in %s %s;\n", input.semantic /*index*/, input.type, input.name);
|
2022-07-24 16:29:11 +00:00
|
|
|
}
|
2020-11-03 14:44:57 +00:00
|
|
|
for (auto &varying : varyings) {
|
2020-11-10 21:26:34 +00:00
|
|
|
F("layout(location = %d) %s out %s %s; // %s\n",
|
2022-08-03 10:32:42 +00:00
|
|
|
varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic]);
|
2020-11-03 14:44:57 +00:00
|
|
|
}
|
|
|
|
C("void main() {\n");
|
|
|
|
break;
|
2022-07-24 16:29:11 +00:00
|
|
|
}
|
2020-11-03 14:44:57 +00:00
|
|
|
default: // OpenGL
|
2022-07-24 16:29:11 +00:00
|
|
|
for (auto &input : inputs) {
|
2022-08-06 16:18:57 +00:00
|
|
|
F("%s %s %s;\n", lang_.attribute, input.type, input.name);
|
2022-07-24 16:29:11 +00:00
|
|
|
}
|
2020-11-03 14:44:57 +00:00
|
|
|
for (auto &varying : varyings) {
|
2022-08-03 10:32:42 +00:00
|
|
|
F("%s %s %s %s; // %s (%d)\n", lang_.varying_vs, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic], varying.index);
|
2020-11-03 14:44:57 +00:00
|
|
|
}
|
2020-11-02 15:12:45 +00:00
|
|
|
C("void main() {\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShaderWriter::BeginFSMain(Slice<UniformDef> uniforms, Slice<VaryingDef> varyings) {
|
2020-11-03 14:44:57 +00:00
|
|
|
_assert_(this->stage_ == ShaderStage::Fragment);
|
2020-11-02 15:12:45 +00:00
|
|
|
switch (lang_.shaderLanguage) {
|
|
|
|
case HLSL_D3D11:
|
|
|
|
if (!uniforms.is_empty()) {
|
2022-07-24 18:07:29 +00:00
|
|
|
C("cbuffer base : register(b0) {\n");
|
|
|
|
|
2020-11-02 15:12:45 +00:00
|
|
|
for (auto &uniform : uniforms) {
|
2022-07-24 18:07:29 +00:00
|
|
|
F(" %s %s;\n", uniform.type, uniform.name);
|
2020-11-02 15:12:45 +00:00
|
|
|
}
|
2022-07-24 18:07:29 +00:00
|
|
|
|
|
|
|
C("};\n");
|
2020-11-02 15:12:45 +00:00
|
|
|
}
|
2022-07-24 18:07:29 +00:00
|
|
|
|
2020-11-02 15:12:45 +00:00
|
|
|
// Let's do the varyings as parameters to main, no struct.
|
|
|
|
C("vec4 main(");
|
|
|
|
for (auto &varying : varyings) {
|
2022-08-03 10:32:42 +00:00
|
|
|
F(" %s %s : %s, ", varying.type, varying.name, semanticNames[varying.semantic]);
|
2020-11-02 15:12:45 +00:00
|
|
|
}
|
|
|
|
// Erase the last comma
|
|
|
|
Rewind(2);
|
|
|
|
|
|
|
|
F(") : SV_Target0 {\n");
|
|
|
|
break;
|
|
|
|
case HLSL_D3D9:
|
|
|
|
for (auto &uniform : uniforms) {
|
2021-01-01 23:29:22 +00:00
|
|
|
F(" %s %s : register(c%d);\n", uniform.type, uniform.name, uniform.index);
|
2020-11-02 15:12:45 +00:00
|
|
|
}
|
|
|
|
// Let's do the varyings as parameters to main, no struct.
|
|
|
|
C("vec4 main(");
|
|
|
|
for (auto &varying : varyings) {
|
2022-08-03 10:32:42 +00:00
|
|
|
F(" %s %s : %s, ", varying.type, varying.name, semanticNames[varying.semantic]);
|
2020-11-02 15:12:45 +00:00
|
|
|
}
|
|
|
|
// Erase the last comma
|
|
|
|
Rewind(2);
|
|
|
|
|
|
|
|
F(") : COLOR {\n");
|
|
|
|
break;
|
|
|
|
case GLSL_VULKAN:
|
|
|
|
for (auto &varying : varyings) {
|
2022-08-03 10:32:42 +00:00
|
|
|
F("layout(location = %d) %s in %s %s; // %s\n", varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic]);
|
2020-11-02 15:12:45 +00:00
|
|
|
}
|
2020-11-10 21:26:34 +00:00
|
|
|
C("layout(location = 0, index = 0) out vec4 fragColor0;\n");
|
2022-07-24 16:29:11 +00:00
|
|
|
if (!uniforms.is_empty()) {
|
|
|
|
C("layout(std140, set = 0, binding = 0) uniform bufferVals {\n");
|
|
|
|
for (auto &uniform : uniforms) {
|
|
|
|
F("%s %s;\n", uniform.type, uniform.name);
|
|
|
|
}
|
|
|
|
C("};\n");
|
|
|
|
}
|
2020-11-02 15:12:45 +00:00
|
|
|
C("\nvoid main() {\n");
|
|
|
|
break;
|
2022-07-24 16:29:11 +00:00
|
|
|
|
|
|
|
default: // GLSL OpenGL
|
2020-11-02 15:12:45 +00:00
|
|
|
for (auto &varying : varyings) {
|
2022-08-03 10:32:42 +00:00
|
|
|
F("%s %s %s %s; // %s\n", lang_.varying_fs, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic]);
|
2020-11-02 15:12:45 +00:00
|
|
|
}
|
2022-07-24 16:29:11 +00:00
|
|
|
for (auto &uniform : uniforms) {
|
|
|
|
F("uniform %s %s;\n", uniform.type, uniform.name);
|
|
|
|
}
|
2020-11-02 15:12:45 +00:00
|
|
|
if (!strcmp(lang_.fragColor0, "fragColor0")) {
|
|
|
|
C("out vec4 fragColor0;\n");
|
|
|
|
}
|
|
|
|
C("\nvoid main() {\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-03 14:44:57 +00:00
|
|
|
void ShaderWriter::EndVSMain(Slice<VaryingDef> varyings) {
|
|
|
|
_assert_(this->stage_ == ShaderStage::Vertex);
|
|
|
|
switch (lang_.shaderLanguage) {
|
|
|
|
case HLSL_D3D11:
|
|
|
|
case HLSL_D3D9:
|
|
|
|
C(" VS_OUTPUT vs_out;\n");
|
|
|
|
C(" vs_out.pos = gl_Position;\n");
|
|
|
|
for (auto &varying : varyings) {
|
|
|
|
F(" vs_out.%s = %s;\n", varying.name, varying.name);
|
|
|
|
}
|
|
|
|
C(" return vs_out;\n");
|
|
|
|
break;
|
|
|
|
case GLSL_VULKAN:
|
|
|
|
default: // OpenGL
|
|
|
|
break;
|
|
|
|
}
|
2020-11-02 15:12:45 +00:00
|
|
|
C("}\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShaderWriter::EndFSMain(const char *vec4_color_variable) {
|
2020-11-03 14:44:57 +00:00
|
|
|
_assert_(this->stage_ == ShaderStage::Fragment);
|
2020-11-02 15:12:45 +00:00
|
|
|
switch (lang_.shaderLanguage) {
|
|
|
|
case HLSL_D3D11:
|
|
|
|
case HLSL_D3D9:
|
|
|
|
F(" return %s;\n", vec4_color_variable);
|
|
|
|
break;
|
|
|
|
case GLSL_VULKAN:
|
|
|
|
default: // OpenGL
|
|
|
|
F(" %s = %s;\n", lang_.fragColor0, vec4_color_variable);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
C("}\n");
|
|
|
|
}
|
|
|
|
|
2020-11-10 21:26:34 +00:00
|
|
|
void ShaderWriter::HighPrecisionFloat() {
|
|
|
|
if ((ShaderLanguageIsOpenGL(lang_.shaderLanguage) && lang_.gles) || lang_.shaderLanguage == GLSL_VULKAN) {
|
|
|
|
C("precision highp float;\n");
|
2020-11-10 21:01:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-05 08:00:27 +00:00
|
|
|
void ShaderWriter::DeclareSamplers(Slice<SamplerDef> samplers) {
|
|
|
|
for (int i = 0; i < (int)samplers.size(); i++) {
|
|
|
|
DeclareTexture2D(samplers[i].name,i);
|
|
|
|
DeclareSampler2D(samplers[i].name, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-02 15:12:45 +00:00
|
|
|
void ShaderWriter::DeclareTexture2D(const char *name, int binding) {
|
|
|
|
switch (lang_.shaderLanguage) {
|
|
|
|
case HLSL_D3D11:
|
|
|
|
F("Texture2D<float4> %s : register(t%d);\n", name, binding);
|
|
|
|
break;
|
|
|
|
case HLSL_D3D9:
|
2022-07-24 16:43:27 +00:00
|
|
|
F("sampler %s: register(s%d);\n", name, binding);
|
2020-11-02 15:12:45 +00:00
|
|
|
break;
|
|
|
|
case GLSL_VULKAN:
|
2020-11-06 19:08:57 +00:00
|
|
|
// In the thin3d descriptor set layout, textures start at 1 in set 0. Hence the +1.
|
|
|
|
F("layout(set = 0, binding = %d) uniform sampler2D %s;\n", binding + 1, name);
|
2020-11-02 15:12:45 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
F("uniform sampler2D %s;\n", name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShaderWriter::DeclareSampler2D(const char *name, int binding) {
|
|
|
|
// We only use separate samplers in HLSL D3D11, where we have no choice.
|
|
|
|
switch (lang_.shaderLanguage) {
|
|
|
|
case HLSL_D3D11:
|
|
|
|
F("SamplerState %s : register(s%d);\n", name, binding);
|
|
|
|
break;
|
2020-12-13 15:04:16 +00:00
|
|
|
default:
|
|
|
|
break;
|
2020-11-02 15:12:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ShaderWriter &ShaderWriter::SampleTexture2D(const char *texName, const char *samplerName, const char *uv) {
|
|
|
|
switch (lang_.shaderLanguage) {
|
|
|
|
case HLSL_D3D11:
|
|
|
|
F("%s.Sample(%s, %s)", texName, samplerName, uv);
|
|
|
|
break;
|
|
|
|
case HLSL_D3D9:
|
|
|
|
F("tex2D(%s, %s)", texName, uv);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.
|
|
|
|
F("%s(%s, %s)", lang_.texture, texName, uv);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|