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