1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsSLPrerequisites.h"
6#include "Material/BsShader.h"
7#include "RenderAPI/BsGpuProgram.h"
8#include "RenderAPI/BsRasterizerState.h"
9#include "RenderAPI/BsDepthStencilState.h"
10#include "RenderAPI/BsBlendState.h"
11#include "Importer/BsShaderImportOptions.h"
12
13extern "C" {
14#include "BsASTFX.h"
15}
16
17namespace bs
18{
19 /** @addtogroup bsfSL
20 * @{
21 */
22
23 /** Contains the results of compilation returned from the BSLFXCompiler. */
24 struct BSLFXCompileResult
25 {
26 SPtr<Shader> shader; /**< Resulting shader if compilation was successful. Null if error occurred. */
27 String errorMessage; /**< Error message if compilation failed. */
28 int errorLine = 0; /**< Line of the error if one occurred. */
29 int errorColumn = 0; /**< Column of the error if one occurred. */
30 String errorFile; /**< File in which the error occurred. Empty if root file. */
31 };
32
33 /** Transforms a source file written in BSL FX syntax into a Shader object. */
34 class BSLFXCompiler
35 {
36 /** Possible types of code blocks within a shader. */
37 enum class CodeBlockType
38 {
39 Vertex, Fragment, Geometry, Hull, Domain, Compute, Common
40 };
41
42 /** Temporary data describing a pass during parsing. */
43 struct PassData
44 {
45 BLEND_STATE_DESC blendDesc;
46 RASTERIZER_STATE_DESC rasterizerDesc;
47 DEPTH_STENCIL_STATE_DESC depthStencilDesc;
48 UINT32 stencilRefValue = 0;
49 UINT32 seqIdx = 0;
50
51 bool blendIsDefault = true;
52 bool rasterizerIsDefault = true;
53 bool depthStencilIsDefault = true;
54
55 String code; // Parsed code block
56
57 String vertexCode;
58 String fragmentCode;
59 String geometryCode;
60 String hullCode;
61 String domainCode;
62 String computeCode;
63 };
64
65 /** A set of attributes describing a BSL construct. */
66 struct AttributeData
67 {
68 Vector<std::pair<INT32, String>> attributes;
69 };
70
71 /** Value of a single variation option along with an optional name. */
72 struct VariationOption
73 {
74 String name;
75 UINT32 value;
76 };
77
78 /** Information about different variations of a single shader. */
79 struct VariationData
80 {
81 String name;
82 String identifier;
83 bool internal = true;
84 Vector<VariationOption> values;
85 };
86
87 /** Information describing a shader/mixin node, without the actual contents. */
88 struct ShaderMetaData
89 {
90 String name;
91 Vector<String> includes;
92 bool isMixin;
93
94 String language;
95 String featureSet;
96
97 Vector<StringID> tags;
98 Vector<VariationData> variations;
99 };
100
101 /** Temporary data for describing a shader/mixin node during parsing. */
102 struct ShaderData
103 {
104 ShaderMetaData metaData;
105 Vector<PassData> passes;
106 };
107
108 /** Temporary data describing a sub-shader during parsing. */
109 struct SubShaderData
110 {
111 String name;
112 UINT32 codeBlockIndex;
113 };
114
115 public:
116 /** Transforms a source file written in BSL FX syntax into a Shader object. */
117 static BSLFXCompileResult compile(const String& name, const String& source,
118 const UnorderedMap<String, String>& defines, ShadingLanguageFlags languages);
119
120 private:
121 /** Converts the provided source into an abstract syntax tree using the lexer & parser for BSL FX syntax. */
122 static BSLFXCompileResult parseFX(ParseState* parseState, const char* source,
123 const UnorderedMap<String, String>& defines);
124
125 /** Parses the shader/mixin node and outputs the relevant meta-data. */
126 static ShaderMetaData parseShaderMetaData(ASTFXNode* shader);
127
128 /**
129 * Parses the root AST node and outputs a list of all mixins/shaders and their meta-data, sub-shader meta-data,
130 * as well as any global shader options.
131 */
132 static BSLFXCompileResult parseMetaDataAndOptions(ASTFXNode* rootNode,
133 Vector<std::pair<ASTFXNode*, ShaderMetaData>>& metaData, Vector<SubShaderData>& subShaders,
134 SHADER_DESC& shaderDesc);
135
136 /** Parses the sub-shader node and outputs the relevant data. */
137 static SubShaderData parseSubShader(ASTFXNode* subShader);
138
139 /** Parses shader variations and writes them to the provided meta-data object. */
140 static void parseVariations(ShaderMetaData& metaData, ASTFXNode* variations);
141
142 /** Parses a single variation option node. */
143 static VariationOption parseVariationOption(ASTFXNode* variationOption);
144
145 /** Parses BSL attributes. */
146 static AttributeData parseAttributes(ASTFXNode* attributes);
147
148 /** Maps BSL queue sort type enum into in-engine queue sort type mode. */
149 static QueueSortType parseSortType(CullAndSortModeValue sortType);
150
151 /** Maps BSL comparison function enum into in-engine compare function. */
152 static CompareFunction parseCompFunc(CompFuncValue compFunc);
153
154 /** Maps BSL operation to in-engine blend factor. */
155 static BlendFactor parseBlendFactor(OpValue factor);
156
157 /** Maps BSL blend operation to in-engine blend operation. */
158 static BlendOperation parseBlendOp(BlendOpValue op);
159
160 /** Maps BSL operation to in-engine stencil operation. */
161 static StencilOperation parseStencilOp(OpValue op);
162
163 /** Maps BSL cull mode enum to in-engine cull mode. */
164 static CullingMode parseCullMode(CullAndSortModeValue cm);
165
166 /** Maps BSL fill mode enum to in-engine fill mode. */
167 static PolygonMode parseFillMode(FillModeValue fm);
168
169 /**
170 * Populates the front facing operation portion of the depth-stencil state descriptor from the provided stencil-op
171 * AST node.
172 */
173 static void parseStencilFront(DEPTH_STENCIL_STATE_DESC& desc, ASTFXNode* stencilOpNode);
174
175 /**
176 * Populates the back backing operation portion of the depth-stencil state descriptor from the provided stencil-op
177 * AST node.
178 */
179 static void parseStencilBack(DEPTH_STENCIL_STATE_DESC& desc, ASTFXNode* stencilOpNode);
180
181 /** Populates the color (RGB) portion of the blend state descriptor from the provided blend definition AST node. */
182 static void parseColorBlendDef(RENDER_TARGET_BLEND_STATE_DESC& desc, ASTFXNode* blendDefNode);
183
184 /** Populates the alpha portion of the blend state descriptor from the provided blend definition AST node. */
185 static void parseAlphaBlendDef(RENDER_TARGET_BLEND_STATE_DESC& desc, ASTFXNode* blendDefNode);
186
187 /**
188 * Populates blend state descriptor for a single render target from the provided AST node. Which target gets
189 * updated depends on the index set in the AST node.
190 */
191 static void parseRenderTargetBlendState(BLEND_STATE_DESC& desc, ASTFXNode* targetNode, UINT32& index);
192
193 /**
194 * Parses the blend state AST node and populates the pass' blend state descriptor. Returns false if the descriptor
195 * wasn't modified.
196 */
197 static bool parseBlendState(PassData& passData, ASTFXNode* blendNode);
198
199 /**
200 * Parses the rasterizer state AST node and populates the pass' rasterizer state descriptor. Returns false if the
201 * descriptor wasn't modified.
202 */
203 static bool parseRasterizerState(PassData& passData, ASTFXNode* rasterNode);
204
205 /**
206 * Parses the depth state AST node and populates the pass' depth-stencil state descriptor. Returns false if the
207 * descriptor wasn't modified.
208 */
209 static bool parseDepthState(PassData& passData, ASTFXNode* depthNode);
210
211 /**
212 * Parses the stencil state AST node and populates the pass' depth-stencil state descriptor. Returns false if the
213 * descriptor wasn't modified.
214 */
215 static bool parseStencilState(PassData& passData, ASTFXNode* stencilNode);
216
217 /**
218 * Parses a code AST node and outputs the result in one of the streams within the provided pass data.
219 *
220 * @param[in] codeNode AST node to parse
221 * @param[in] codeBlocks GPU program source code.
222 * @param[in] passData Pass data containing temporary pass data, including the code streams that the code
223 * block code will be written to.
224 */
225 static void parseCodeBlock(ASTFXNode* codeNode, const Vector<String>& codeBlocks, PassData& passData);
226
227 /**
228 * Parses the pass AST node and populates the provided @p passData with all relevant pass parameters.
229 *
230 * @param[in] passNode Node to parse.
231 * @param[in] codeBlocks GPU program source code.
232 * @param[out] passData Will contain pass data after parsing.
233 */
234 static void parsePass(ASTFXNode* passNode, const Vector<String>& codeBlocks, PassData& passData);
235
236 /**
237 * Parses the shader AST node and generates a single shader object.
238 *
239 * @param[in] shaderNode Node to parse.
240 * @param[in] codeBlocks GPU program source code.
241 * @param[out] shaderData Will contain shader data after parsing.
242 */
243 static void parseShader(ASTFXNode* shaderNode, const Vector<String>& codeBlocks, ShaderData& shaderData);
244
245 /**
246 * Parser the options AST node that contains global shader options.
247 *
248 * @param[in] optionsNode Node to parse.
249 * @param[in] shaderDesc Descriptor to apply the found options to.
250 */
251 static void parseOptions(ASTFXNode* optionsNode, SHADER_DESC& shaderDesc);
252
253 /**
254 * Iterates over all provided mixins/shaders and inherits any variations. The variations are written in-place, to
255 * the @p shaderMetaData array, for any non-mixins.
256 */
257 static BSLFXCompileResult populateVariations(Vector<std::pair<ASTFXNode*, ShaderMetaData>>& shaderMetaData);
258
259 /** Populates the information about variation parameters and their values. */
260 static void populateVariationParamInfos(const ShaderMetaData& shaderMetaData, SHADER_DESC& desc);
261
262 /**
263 * Parses the provided source and generates a SHADER_DESC containing techniques for all shader variations, any
264 * present sub-shaders, as well as shader parameters. Also outputs a set of includes included by the shader code.
265 *
266 * @param[in] source BSL source that needs to be parsed.
267 * @param[in] defines An optional set of defines to set before parsing the source, that is to be
268 * applied to all variations.
269 * @param[in] languages Shading languages to generate techniques for. Each shader variation will be
270 * compiled into a separate technique for each of the provided languages.
271 * @param[out] shaderDesc Shader descriptor that resulting techniques, sub-shaders, and parameters will be
272 * registered with.
273 * @param[out] includes A list of all include files included by the BSL source.
274 * @return A result object containing an error message if not successful.
275 */
276 static BSLFXCompileResult compileShader(String source, const UnorderedMap<String, String>& defines,
277 ShadingLanguageFlags languages, SHADER_DESC& shaderDesc, Vector<String>& includes);
278
279 /**
280 * Uses the provided list of shaders/mixins to generate a list of techniques. A technique is generated for
281 * every variation and render backend.
282 *
283 * @param[in] shaderMetaData A list of mixins and shaders. Shaders should contain a list of variations to
284 * generate (usually populated via a previous call to populateVariations()).
285 * @param[in] source Original BSL source the mixins/shaders were parsed from. Required as the source
286 * needs to be re-parsed due to variations.
287 * @param[in] defines An optional set of defines to set before parsing the source, that is to be
288 * applied to all variations.
289 * @param[in] languages Shading languages to generate techniques for. Each shader variation will be
290 * compiled into a separate technique for each of the provided languages.
291 * @param[out] shaderDesc Shader descriptor that resulting techniques, and non-internal parameters will be
292 * registered with.
293 * @param[out] includes A list of all include files included by the BSL source.
294 * @return A result object containing an error message if not successful.
295 */
296 static BSLFXCompileResult compileTechniques(const Vector<std::pair<ASTFXNode*, ShaderMetaData>>& shaderMetaData,
297 const String& source, const UnorderedMap<String, String>& defines, ShadingLanguageFlags languages,
298 SHADER_DESC& shaderDesc, Vector<String>& includes);
299
300 /**
301 * Generates a set of techniques for a single variation. Uses AST parse state as input, which must be created using
302 * the defines of the relevant variation.
303 *
304 * @param[in, out] parseState Parser state object that has previously been initialized with the AST using
305 * parseFX().
306 * @param[in] name Name of the shader to generate the variation for.
307 * @param[in] codeBlocks Blocks containing GPU program source code that are referenced by the AST.
308 * @param[in] variation Shader variation the AST was parsed with.
309 * @param[in] languages Shading languages to generate techniques for. Each shader variation will be
310 * compiled into a separate technique for each of the provided languages.
311 * @param[out] includes Set to append newly found includes to.
312 * @param[out] shaderDesc Shader descriptor that resulting techniques, and non-internal parameters will be
313 * registered with.
314 * @return A result object containing an error message if not successful.
315 */
316 static BSLFXCompileResult compileTechniques(ParseState* parseState, const String& name,
317 const Vector<String>& codeBlocks, const ShaderVariation& variation, ShadingLanguageFlags languages,
318 UnorderedSet<String>& includes, SHADER_DESC& shaderDesc);
319
320 /**
321 * Converts a null-terminated string into a standard string, and eliminates quotes that are assumed to be at the
322 * first and last index.
323 */
324 static String removeQuotes(const char* input);
325 };
326
327 /** @} */
328}