1 // Copyright 2012 Dolphin Emulator Project 2 // Licensed under GPLv2+ 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <cstdarg> 8 #include <cstring> 9 #include <iterator> 10 #include <string> 11 #include <type_traits> 12 #include <vector> 13 14 #include <fmt/format.h> 15 16 #include "Common/CommonTypes.h" 17 #include "Common/StringUtil.h" 18 19 enum class APIType; 20 21 /** 22 * Common interface for classes that need to go through the shader generation path 23 * (GenerateVertexShader, GenerateGeometryShader, GeneratePixelShader) 24 * In particular, this includes the shader code generator (ShaderCode). 25 * A different class (ShaderUid) can be used to uniquely identify each ShaderCode object. 26 * More interesting things can be done with this, e.g. ShaderConstantProfile checks what shader 27 * constants are being used. This can be used to optimize buffer management. 28 * If the class does not use one or more of these methods (e.g. Uid class does not need code), the 29 * method will be defined as a no-op by the base class, and the call 30 * should be optimized out. The reason for this implementation is so that shader 31 * selection/generation can be done in two passes, with only a cache lookup being 32 * required if the shader has already been generated. 33 */ 34 class ShaderGeneratorInterface 35 { 36 public: 37 /* 38 * Used when the shader generator would write a piece of ShaderCode. 39 * Can be used like printf. 40 * @note In the ShaderCode implementation, this does indeed write the parameter string to an 41 * internal buffer. However, you're free to do whatever you like with the parameter. 42 */ Write(const char *,...)43 void Write(const char*, ...) 44 #ifdef __GNUC__ 45 __attribute__((format(printf, 2, 3))) 46 #endif 47 { 48 } 49 50 /* 51 * Tells us that a specific constant range (including last_index) is being used by the shader 52 */ SetConstantsUsed(unsigned int first_index,unsigned int last_index)53 void SetConstantsUsed(unsigned int first_index, unsigned int last_index) {} 54 }; 55 56 /* 57 * Shader UID class used to uniquely identify the ShaderCode output written in the shader generator. 58 * uid_data can be any struct of parameters that uniquely identify each shader code output. 59 * Unless performance is not an issue, uid_data should be tightly packed to reduce memory footprint. 60 * Shader generators will write to specific uid_data fields; ShaderUid methods will only read raw 61 * u32 values from a union. 62 * NOTE: Because LinearDiskCache reads and writes the storage associated with a ShaderUid instance, 63 * ShaderUid must be trivially copyable. 64 */ 65 template <class uid_data> 66 class ShaderUid : public ShaderGeneratorInterface 67 { 68 public: 69 static_assert(std::is_trivially_copyable_v<uid_data>, 70 "uid_data must be a trivially copyable type"); 71 72 bool operator==(const ShaderUid& obj) const 73 { 74 return memcmp(GetUidData(), obj.GetUidData(), GetUidDataSize()) == 0; 75 } 76 77 bool operator!=(const ShaderUid& obj) const { return !operator==(obj); } 78 79 // determines the storage order inside STL containers 80 bool operator<(const ShaderUid& obj) const 81 { 82 return memcmp(GetUidData(), obj.GetUidData(), GetUidDataSize()) < 0; 83 } 84 85 // Returns a pointer to an internally stored object of the uid_data type. GetUidData()86 uid_data* GetUidData() { return &data; } 87 88 // Returns a pointer to an internally stored object of the uid_data type. GetUidData()89 const uid_data* GetUidData() const { return &data; } 90 91 // Returns the raw bytes that make up the shader UID. GetUidDataRaw()92 const u8* GetUidDataRaw() const { return reinterpret_cast<const u8*>(&data); } 93 94 // Returns the size of the underlying UID data structure in bytes. GetUidDataSize()95 size_t GetUidDataSize() const { return sizeof(data); } 96 97 private: 98 uid_data data{}; 99 }; 100 101 class ShaderCode : public ShaderGeneratorInterface 102 { 103 public: ShaderCode()104 ShaderCode() { m_buffer.reserve(16384); } GetBuffer()105 const std::string& GetBuffer() const { return m_buffer; } 106 107 // Deprecated: Writes format strings using traditional printf format strings. Write(const char * fmt,...)108 void Write(const char* fmt, ...) 109 #ifdef __GNUC__ 110 __attribute__((format(printf, 2, 3))) 111 #endif 112 { 113 va_list arglist; 114 va_start(arglist, fmt); 115 m_buffer += StringFromFormatV(fmt, arglist); 116 va_end(arglist); 117 } 118 119 // Writes format strings using fmtlib format strings. 120 template <typename... Args> WriteFmt(std::string_view format,Args &&...args)121 void WriteFmt(std::string_view format, Args&&... args) 122 { 123 fmt::format_to(std::back_inserter(m_buffer), format, std::forward<Args>(args)...); 124 } 125 126 protected: 127 std::string m_buffer; 128 }; 129 130 /** 131 * Generates a shader constant profile which can be used to query which constants are used in a 132 * shader 133 */ 134 class ShaderConstantProfile : public ShaderGeneratorInterface 135 { 136 public: ShaderConstantProfile(int num_constants)137 ShaderConstantProfile(int num_constants) { constant_usage.resize(num_constants); } SetConstantsUsed(unsigned int first_index,unsigned int last_index)138 void SetConstantsUsed(unsigned int first_index, unsigned int last_index) 139 { 140 for (unsigned int i = first_index; i < last_index + 1; ++i) 141 constant_usage[i] = true; 142 } 143 ConstantIsUsed(unsigned int index)144 bool ConstantIsUsed(unsigned int index) const 145 { 146 // TODO: Not ready for usage yet 147 return true; 148 // return constant_usage[index]; 149 } 150 151 private: 152 std::vector<bool> constant_usage; // TODO: Is vector<bool> appropriate here? 153 }; 154 155 // Host config contains the settings which can influence generated shaders. 156 union ShaderHostConfig 157 { 158 u32 bits; 159 160 struct 161 { 162 u32 msaa : 1; 163 u32 ssaa : 1; 164 u32 stereo : 1; 165 u32 wireframe : 1; 166 u32 per_pixel_lighting : 1; 167 u32 vertex_rounding : 1; 168 u32 fast_depth_calc : 1; 169 u32 bounding_box : 1; 170 u32 backend_dual_source_blend : 1; 171 u32 backend_geometry_shaders : 1; 172 u32 backend_early_z : 1; 173 u32 backend_bbox : 1; 174 u32 backend_gs_instancing : 1; 175 u32 backend_clip_control : 1; 176 u32 backend_ssaa : 1; 177 u32 backend_atomics : 1; 178 u32 backend_depth_clamp : 1; 179 u32 backend_reversed_depth_range : 1; 180 u32 backend_bitfield : 1; 181 u32 backend_dynamic_sampler_indexing : 1; 182 u32 backend_shader_framebuffer_fetch : 1; 183 u32 backend_logic_op : 1; 184 u32 backend_palette_conversion : 1; 185 u32 pad : 9; 186 }; 187 188 static ShaderHostConfig GetCurrent(); 189 }; 190 191 // Gets the filename of the specified type of cache object (e.g. vertex shader, pipeline). 192 std::string GetDiskShaderCacheFileName(APIType api_type, const char* type, bool include_gameid, 193 bool include_host_config, bool include_api = true); 194 195 void GenerateVSOutputMembers(ShaderCode& object, APIType api_type, u32 texgens, 196 const ShaderHostConfig& host_config, std::string_view qualifier); 197 198 void AssignVSOutputMembers(ShaderCode& object, std::string_view a, std::string_view b, u32 texgens, 199 const ShaderHostConfig& host_config); 200 201 // We use the flag "centroid" to fix some MSAA rendering bugs. With MSAA, the 202 // pixel shader will be executed for each pixel which has at least one passed sample. 203 // So there may be rendered pixels where the center of the pixel isn't in the primitive. 204 // As the pixel shader usually renders at the center of the pixel, this position may be 205 // outside the primitive. This will lead to sampling outside the texture, sign changes, ... 206 // As a workaround, we interpolate at the centroid of the coveraged pixel, which 207 // is always inside the primitive. 208 // Without MSAA, this flag is defined to have no effect. 209 const char* GetInterpolationQualifier(bool msaa, bool ssaa, bool in_glsl_interface_block = false, 210 bool in = false); 211 212 // Constant variable names 213 #define I_COLORS "color" 214 #define I_KCOLORS "k" 215 #define I_ALPHA "alphaRef" 216 #define I_TEXDIMS "texdim" 217 #define I_ZBIAS "czbias" 218 #define I_INDTEXSCALE "cindscale" 219 #define I_INDTEXMTX "cindmtx" 220 #define I_FOGCOLOR "cfogcolor" 221 #define I_FOGI "cfogi" 222 #define I_FOGF "cfogf" 223 #define I_FOGRANGE "cfogrange" 224 #define I_ZSLOPE "czslope" 225 #define I_EFBSCALE "cefbscale" 226 227 #define I_POSNORMALMATRIX "cpnmtx" 228 #define I_PROJECTION "cproj" 229 #define I_MATERIALS "cmtrl" 230 #define I_LIGHTS "clights" 231 #define I_TEXMATRICES "ctexmtx" 232 #define I_TRANSFORMMATRICES "ctrmtx" 233 #define I_NORMALMATRICES "cnmtx" 234 #define I_POSTTRANSFORMMATRICES "cpostmtx" 235 #define I_PIXELCENTERCORRECTION "cpixelcenter" 236 #define I_VIEWPORT_SIZE "cviewport" 237 238 #define I_STEREOPARAMS "cstereo" 239 #define I_LINEPTPARAMS "clinept" 240 #define I_TEXOFFSET "ctexoffset" 241 242 static const char s_shader_uniforms[] = "\tuint components;\n" 243 "\tuint xfmem_dualTexInfo;\n" 244 "\tuint xfmem_numColorChans;\n" 245 "\tfloat4 " I_POSNORMALMATRIX "[6];\n" 246 "\tfloat4 " I_PROJECTION "[4];\n" 247 "\tint4 " I_MATERIALS "[4];\n" 248 "\tLight " I_LIGHTS "[8];\n" 249 "\tfloat4 " I_TEXMATRICES "[24];\n" 250 "\tfloat4 " I_TRANSFORMMATRICES "[64];\n" 251 "\tfloat4 " I_NORMALMATRICES "[32];\n" 252 "\tfloat4 " I_POSTTRANSFORMMATRICES "[64];\n" 253 "\tfloat4 " I_PIXELCENTERCORRECTION ";\n" 254 "\tfloat2 " I_VIEWPORT_SIZE ";\n" 255 "\tuint4 xfmem_pack1[8];\n" 256 "\t#define xfmem_texMtxInfo(i) (xfmem_pack1[(i)].x)\n" 257 "\t#define xfmem_postMtxInfo(i) (xfmem_pack1[(i)].y)\n" 258 "\t#define xfmem_color(i) (xfmem_pack1[(i)].z)\n" 259 "\t#define xfmem_alpha(i) (xfmem_pack1[(i)].w)\n"; 260