CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Common/GPU/ShaderWriter.cpp
Views: 1401
#include <cstdarg>1#include <cstdio>2#include <cstring>34#include "Common/GPU/Shader.h"5#include "Common/GPU/ShaderWriter.h"6#include "Common/Log.h"78const char * const vulkan_glsl_preamble_fs =9"#extension GL_ARB_separate_shader_objects : enable\n"10"#extension GL_ARB_shading_language_420pack : enable\n"11"#extension GL_ARB_conservative_depth : enable\n"12"#extension GL_ARB_shader_image_load_store : enable\n"13"#define splat3(x) vec3(x)\n"14"#define DISCARD discard\n"15"precision lowp float;\n"16"precision highp int;\n"17"\n";1819const char * const hlsl_preamble_fs =20"#define vec2 float2\n"21"#define vec3 float3\n"22"#define vec4 float4\n"23"#define uvec3 uint3\n"24"#define uvec4 uint4\n"25"#define ivec2 int2\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 backwards30"#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 fract frac\n"36"#define mod(x, y) fmod(x, y)\n";3738static const char * const hlsl_d3d11_preamble_fs =39"#define DISCARD discard\n"40"#define DISCARD_BELOW(x) clip(x);\n";41static const char * const hlsl_d3d9_preamble_fs =42"#define DISCARD clip(-1)\n"43"#define DISCARD_BELOW(x) clip(x)\n";4445static const char * const vulkan_glsl_preamble_vs =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";5253static const char * const hlsl_preamble_gs =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 mat2 float2x2\n"60"#define mat4 float4x4\n"61"#define mat3x4 float4x3\n" // note how the conventions are backwards62"#define splat3(x) vec3(x, x, x)\n"63"#define lowp\n"64"#define mediump\n"65"#define highp\n"66"\n";6768static const char * const vulkan_glsl_preamble_gs =69"#extension GL_ARB_separate_shader_objects : enable\n"70"#extension GL_ARB_shading_language_420pack : enable\n"71"#define mul(x, y) ((x) * (y))\n"72"#define splat3(x) vec3(x)\n"73"precision highp float;\n"74"\n";7576static const char * const hlsl_preamble_vs =77"#define vec2 float2\n"78"#define vec3 float3\n"79"#define vec4 float4\n"80"#define ivec2 int2\n"81"#define ivec4 int4\n"82"#define mat2 float2x2\n"83"#define mat4 float4x4\n"84"#define mat3x4 float4x3\n" // note how the conventions are backwards85"#define splat3(x) vec3(x, x, x)\n"86"#define lowp\n"87"#define mediump\n"88"#define highp\n"89"\n";9091static const char * const semanticNames[] = {92"POSITION",93"COLOR0",94"COLOR1",95"TEXCOORD0",96"TEXCOORD1",97"NORMAL",98"TANGENT",99"BINORMAL",100};101static_assert(ARRAY_SIZE(semanticNames) == Draw::SEM_MAX, "Missing semantic in semanticNames");102103// Unsafe. But doesn't matter, we'll use big buffers for shader gen.104ShaderWriter & ShaderWriter::F(const char *format, ...) {105va_list args;106va_start(args, format);107p_ += vsprintf(p_, format, args);108va_end(args);109return *this;110}111112void ShaderWriter::Preamble(Slice<const char *> extensions) {113switch (lang_.shaderLanguage) {114case GLSL_VULKAN:115C("#version 450\n");116if (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) {117C("#extension GL_EXT_multiview : enable\n");118}119// IMPORTANT! Extensions must be the first thing after #version.120for (size_t i = 0; i < extensions.size(); i++) {121F("%s\n", extensions[i]);122}123switch (stage_) {124case ShaderStage::Vertex:125W(vulkan_glsl_preamble_vs);126break;127case ShaderStage::Fragment:128W(vulkan_glsl_preamble_fs);129break;130case ShaderStage::Geometry:131W(vulkan_glsl_preamble_gs);132break;133default:134break;135}136break;137case HLSL_D3D11:138case HLSL_D3D9:139switch (stage_) {140case ShaderStage::Vertex:141W(hlsl_preamble_vs);142break;143case ShaderStage::Fragment:144W(hlsl_preamble_fs);145if (lang_.shaderLanguage == HLSL_D3D9) {146W(hlsl_d3d9_preamble_fs);147} else {148W(hlsl_d3d11_preamble_fs);149}150break;151case ShaderStage::Geometry:152W(hlsl_preamble_gs);153break;154default:155break;156}157break;158default: // OpenGL159F("#version %d%s\n", lang_.glslVersionNumber, lang_.gles && lang_.glslES30 ? " es" : "");160// IMPORTANT! Extensions must be the first thing after #version.161for (size_t i = 0; i < extensions.size(); i++) {162F("%s\n", extensions[i]);163}164// Print some system info - useful to gather information directly from screenshots.165if (strlen(lang_.driverInfo) != 0) {166F("// Driver: %s\n", lang_.driverInfo);167}168switch (stage_) {169case ShaderStage::Fragment:170C("#define DISCARD discard\n");171if (lang_.gles) {172C("precision lowp float;\n");173if (lang_.glslES30) {174C("precision highp int;\n");175}176}177break;178case ShaderStage::Vertex:179if (lang_.gles) {180C("precision highp float;\n");181}182C("#define gl_VertexIndex gl_VertexID\n");183break;184case ShaderStage::Geometry:185if (lang_.gles) {186C("precision highp float;\n");187}188break;189default:190break;191}192if (!lang_.gles) {193C("#define lowp\n");194C("#define mediump\n");195C("#define highp\n");196}197C("#define splat3(x) vec3(x)\n");198C("#define mul(x, y) ((x) * (y))\n");199break;200}201}202203void ShaderWriter::BeginVSMain(Slice<InputDef> inputs, Slice<UniformDef> uniforms, Slice<VaryingDef> varyings) {204_assert_(this->stage_ == ShaderStage::Vertex);205switch (lang_.shaderLanguage) {206case HLSL_D3D11:207case HLSL_D3D9:208{209C("struct VS_OUTPUT {\n");210for (auto &varying : varyings) {211F(" %s %s : %s;\n", varying.type, varying.name, semanticNames[varying.semantic]);212}213F(" vec4 pos : %s;\n", lang_.shaderLanguage == HLSL_D3D11 ? "SV_Position" : "POSITION");214C("};\n");215216C("VS_OUTPUT main( "); // 2 spaces for the rewind217if (lang_.shaderLanguage == HLSL_D3D11) {218C("uint gl_VertexIndex : SV_VertexID, ");219}220// List the inputs.221for (auto &input : inputs) {222F("in %s %s : %s, ", input.type, input.name, semanticNames[input.semantic]);223}224225Rewind(2); // Get rid of the last comma.226C(") {\n");227C(" vec4 gl_Position;\n");228for (auto &varying : varyings) {229F(" %s %s; // %s\n", varying.type, varying.name, semanticNames[varying.semantic]);230}231break;232}233case GLSL_VULKAN:234{235for (auto &input : inputs) {236F("layout(location = %d) in %s %s;\n", input.semantic /*index*/, input.type, input.name);237}238for (auto &varying : varyings) {239F("layout(location = %d) %s out %s %s; // %s\n",240varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic]);241}242C("void main() {\n");243break;244}245default: // OpenGL246for (auto &input : inputs) {247F("%s %s %s;\n", lang_.attribute, input.type, input.name);248}249for (auto &varying : varyings) {250F("%s %s %s %s; // %s (%d)\n", lang_.varying_vs, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic], varying.index);251}252C("void main() {\n");253break;254}255}256257void ShaderWriter::BeginFSMain(Slice<UniformDef> uniforms, Slice<VaryingDef> varyings) {258_assert_(this->stage_ == ShaderStage::Fragment);259switch (lang_.shaderLanguage) {260case HLSL_D3D11:261if (!uniforms.is_empty()) {262C("cbuffer base : register(b0) {\n");263264for (auto &uniform : uniforms) {265F(" %s %s;\n", uniform.type, uniform.name);266}267268C("};\n");269}270271if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) {272C("float gl_FragDepth;\n");273}274275C("struct PS_OUT {\n");276C(" vec4 target : SV_Target0;\n");277if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) {278C(" float depth : SV_Depth;\n");279}280C("};\n");281282// Let's do the varyings as parameters to main, no struct.283C("PS_OUT main(");284for (auto &varying : varyings) {285F(" %s %s : %s, ", varying.type, varying.name, semanticNames[varying.semantic]);286}287// Erase the last comma288Rewind(2);289290F(") {\n");291C(" PS_OUT ps_out;\n");292if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) {293C(" float gl_FragDepth;\n");294}295break;296case HLSL_D3D9:297C("struct PS_OUT {\n");298C(" vec4 target : SV_Target0;\n");299if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) {300C(" float depth : DEPTH;\n");301}302C("};\n");303304for (auto &uniform : uniforms) {305F(" %s %s : register(c%d);\n", uniform.type, uniform.name, uniform.index);306}307// Let's do the varyings as parameters to main, no struct.308C("PS_OUT main(");309for (auto &varying : varyings) {310F(" %s %s : %s, ", varying.type, varying.name, semanticNames[varying.semantic]);311}312// Erase the last comma313Rewind(2);314315F(") {\n");316C(" PS_OUT ps_out;\n");317if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) {318C(" float gl_FragDepth;\n");319}320321break;322case GLSL_VULKAN:323for (auto &varying : varyings) {324F("layout(location = %d) %s in %s %s; // %s\n", varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic]);325}326C("layout(location = 0, index = 0) out vec4 fragColor0;\n");327if (!uniforms.is_empty()) {328C("layout(std140, set = 0, binding = 0) uniform bufferVals {\n");329for (auto &uniform : uniforms) {330F("%s %s;\n", uniform.type, uniform.name);331}332C("};\n");333}334C("\nvoid main() {\n");335break;336337default: // GLSL OpenGL338for (auto &varying : varyings) {339F("%s %s %s %s; // %s\n", lang_.varying_fs, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic]);340}341for (auto &uniform : uniforms) {342F("uniform %s %s;\n", uniform.type, uniform.name);343}344if (!strcmp(lang_.fragColor0, "fragColor0")) {345C("out vec4 fragColor0;\n");346}347C("\nvoid main() {\n");348break;349}350}351352void ShaderWriter::BeginGSMain(Slice<VaryingDef> varyings, Slice<VaryingDef> outVaryings) {353_assert_(this->stage_ == ShaderStage::Geometry);354switch (lang_.shaderLanguage) {355case HLSL_D3D11:356// Untested, but should work.357C("\nstruct GS_OUTPUT {\n");358for (auto &varying : outVaryings) {359F(" %s %s : %s;\n", varying.type, varying.name, semanticNames[varying.semantic]);360}361F(" vec4 pos : %s;\n", lang_.shaderLanguage == HLSL_D3D11 ? "SV_Position" : "POSITION");362C("};\n");363C("#define EmitVertex() emit.Append(gsout)\n");364365C("void main(");366for (auto &varying : varyings) {367F(" in %s %s : %s, ", varying.type, varying.name, semanticNames[varying.semantic]);368}369C("inout TriangleStream<GS_OUTPUT> emit) {\n");370C(" GS_OUTPUT gsout;\n");371break;372case GLSL_VULKAN:373for (auto &varying : varyings) {374F("layout(location = %d) %s in %s %s[]; // %s\n", varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic]);375}376for (auto &varying : outVaryings) {377F("layout(location = %d) %s out %s %s; // %s\n", varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, semanticNames[varying.semantic]);378}379C("\nvoid main() {\n");380break;381case GLSL_3xx:382C("\nvoid main() {\n");383break;384default:385break;386}387}388389void ShaderWriter::EndVSMain(Slice<VaryingDef> varyings) {390_assert_(this->stage_ == ShaderStage::Vertex);391switch (lang_.shaderLanguage) {392case HLSL_D3D11:393case HLSL_D3D9:394C(" VS_OUTPUT vs_out;\n");395if (strlen(lang_.viewportYSign)) {396F(" gl_Position.y *= %s1.0;\n", lang_.viewportYSign);397}398C(" vs_out.pos = gl_Position;\n");399for (auto &varying : varyings) {400F(" vs_out.%s = %s;\n", varying.name, varying.name);401}402C(" return vs_out;\n");403break;404case GLSL_VULKAN:405default: // OpenGL406break;407}408C("}\n");409}410411void ShaderWriter::EndFSMain(const char *vec4_color_variable) {412_assert_(this->stage_ == ShaderStage::Fragment);413switch (lang_.shaderLanguage) {414case HLSL_D3D11:415case HLSL_D3D9:416F(" ps_out.target = %s;\n", vec4_color_variable);417if (flags_ & ShaderWriterFlags::FS_WRITE_DEPTH) {418C(" ps_out.depth = gl_FragDepth;\n");419}420C(" return ps_out;\n");421break;422case GLSL_VULKAN:423default: // OpenGL424F(" %s = %s;\n", lang_.fragColor0, vec4_color_variable);425break;426}427C("}\n");428}429430void ShaderWriter::EndGSMain() {431_assert_(this->stage_ == ShaderStage::Geometry);432C("}\n");433}434435void ShaderWriter::HighPrecisionFloat() {436if ((ShaderLanguageIsOpenGL(lang_.shaderLanguage) && lang_.gles) || lang_.shaderLanguage == GLSL_VULKAN) {437C("precision highp float;\n");438}439}440441void ShaderWriter::LowPrecisionFloat() {442if ((ShaderLanguageIsOpenGL(lang_.shaderLanguage) && lang_.gles) || lang_.shaderLanguage == GLSL_VULKAN) {443C("precision lowp float;\n");444}445}446447void ShaderWriter::ConstFloat(const char *name, float value) {448switch (lang_.shaderLanguage) {449case HLSL_D3D11:450case HLSL_D3D9:451F("static const float %s = %f;\n", name, value);452break;453default:454F("#define %s %f\n", name, value);455break;456}457}458459void ShaderWriter::DeclareSamplers(Slice<SamplerDef> samplers) {460for (int i = 0; i < (int)samplers.size(); i++) {461DeclareTexture2D(samplers[i]);462DeclareSampler2D(samplers[i]);463}464samplerDefs_ = samplers;465}466467void ShaderWriter::ApplySamplerMetadata(Slice<SamplerDef> samplers) {468samplerDefs_ = samplers;469}470471void ShaderWriter::DeclareTexture2D(const SamplerDef &def) {472switch (lang_.shaderLanguage) {473case HLSL_D3D11:474F("Texture2D<float4> %s : register(t%d);\n", def.name, def.binding);475break;476case HLSL_D3D9:477F("sampler %s: register(s%d);\n", def.name, def.binding);478break;479case GLSL_VULKAN:480// texBindingBase_ is used for the thin3d descriptor set layout, where they start at 1.481if (def.flags & SamplerFlags::ARRAY_ON_VULKAN) {482F("layout(set = 0, binding = %d) uniform sampler2DArray %s;\n", def.binding + texBindingBase_, def.name);483} else {484F("layout(set = 0, binding = %d) uniform sampler2D %s;\n", def.binding + texBindingBase_, def.name);485}486break;487default:488F("uniform sampler2D %s;\n", def.name);489break;490}491}492493void ShaderWriter::DeclareSampler2D(const SamplerDef &def) {494// We only use separate samplers in HLSL D3D11, where we have no choice.495switch (lang_.shaderLanguage) {496case HLSL_D3D11:497F("SamplerState %sSamp : register(s%d);\n", def.name, def.binding);498break;499default:500break;501}502}503504ShaderWriter &ShaderWriter::SampleTexture2D(const char *sampName, const char *uv) {505const SamplerDef *samp = GetSamplerDef(sampName);506switch (lang_.shaderLanguage) {507case HLSL_D3D11:508F("%s.Sample(%sSamp, %s)", sampName, sampName, uv);509break;510case HLSL_D3D9:511F("tex2D(%s, %s)", sampName, uv);512break;513default:514// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.515if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) {516const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "float(gl_ViewIndex)" : "0.0";517F("%s(%s, vec3(%s, %s))", lang_.texture, sampName, uv, index);518} else {519F("%s(%s, %s)", lang_.texture, sampName, uv);520}521break;522}523return *this;524}525526ShaderWriter &ShaderWriter::SampleTexture2DOffset(const char *sampName, const char *uv, int offX, int offY) {527const SamplerDef *samp = GetSamplerDef(sampName);528529switch (lang_.shaderLanguage) {530case HLSL_D3D11:531F("%s.Sample(%sSamp, %s, int2(%d, %d))", sampName, sampName, uv, offX, offY);532break;533case HLSL_D3D9:534// Not supported, we do a normal sample here to not crash or something535F("tex2D(%s, %s)", sampName, uv);536break;537default:538// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.539if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) {540const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "float(gl_ViewIndex)" : "0.0";541F("%sOffset(%s, vec3(%s, %s), ivec2(%d, %d))", lang_.texture, sampName, uv, index, offX, offY);542} else {543F("%sOffset(%s, %s, ivec2(%d, %d))", lang_.texture, sampName, uv, offX, offY);544}545break;546}547return *this;548}549550ShaderWriter &ShaderWriter::LoadTexture2D(const char *sampName, const char *uv, int level) {551const SamplerDef *samp = GetSamplerDef(sampName);552553switch (lang_.shaderLanguage) {554case HLSL_D3D11:555F("%s.Load(ivec3(%s, %d))", sampName, uv, level);556break;557case HLSL_D3D9:558// Not supported, we return a bad value559C("float4(1.0, 0.0, 1.0, 1.0)");560break;561default:562// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.563if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) {564const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "gl_ViewIndex" : "0";565F("texelFetch(%s, vec3(%s, %s), %d)", sampName, uv, index, level);566} else {567F("texelFetch(%s, %s, %d)", sampName, uv, level);568}569break;570}571return *this;572}573574ShaderWriter &ShaderWriter::GetTextureSize(const char *szVariable, const char *texName) {575switch (lang_.shaderLanguage) {576case HLSL_D3D11:577F(" float2 %s; %s.GetDimensions(%s.x, %s.y);", szVariable, texName, szVariable, szVariable);578break;579case HLSL_D3D9:580F(" float2 %s; %s.GetDimensions(%s.x, %s.y);", szVariable, texName, szVariable, szVariable);581break;582default:583// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.584F("vec2 %s = textureSize(%s, 0);", szVariable, texName);585break;586}587return *this;588}589590const SamplerDef *ShaderWriter::GetSamplerDef(const char *name) const {591for (int i = 0; i < (int)samplerDefs_.size(); i++) {592if (!strcmp(samplerDefs_[i].name, name)) {593return &samplerDefs_[i];594}595}596return nullptr;597}598599600