Diligent Engine API Reference: D:/GitHub/DiligentEngine/DiligentCore/Graphics/HLSL2GLSLConverterLib/include/HLSL2GLSLConverterImpl.h Source File

Diligent Engine API Reference

HLSL2GLSLConverterImpl.h
1 /* Copyright 2015-2018 Egor Yusov
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
12 *
13 * In no event and under no legal theory, whether in tort (including negligence),
14 * contract, or otherwise, unless required by applicable law (such as deliberate
15 * and grossly negligent acts) or agreed to in writing, shall any Contributor be
16 * liable for any damages, including any direct, indirect, special, incidental,
17 * or consequential damages of any character arising as a result of this License or
18 * out of the use or inability to use the software (including but not limited to damages
19 * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
20 * all other commercial damages or losses), even if such Contributor has been advised
21 * of the possibility of such damages.
22 */
23
24 #pragma once
25
26 #include <list>
27 #include <unordered_set>
28 #include <unordered_map>
29
30 #include "HLSL2GLSLConverter.h"
31 #include "ObjectBase.h"
32 #include "HLSLKeywords.h"
33 #include "Shader.h"
34 #include "HashUtils.h"
35 #include "HLSLKeywords.h"
36
37 namespace Diligent
38 {
39 struct FunctionStubHashKey
40 {
41 FunctionStubHashKey(const String& _Obj, const String& _Func, Uint32 _NumArgs) :
42 Object(_Obj),
43 Function(_Func),
44 NumArguments(_NumArgs)
45 {
46 }
47
48 FunctionStubHashKey(const Char* _Obj, const Char* _Func, Uint32 _NumArgs) :
49 Object(_Obj),
50 Function(_Func),
51 NumArguments(_NumArgs)
52 {
53 }
54
55 FunctionStubHashKey( FunctionStubHashKey && Key ) :
56 Object(std::move(Key.Object)),
57 Function(std::move(Key.Function)),
58 NumArguments(Key.NumArguments)
59 {
60 }
61
62 bool operator==(const FunctionStubHashKey& rhs)const
63 {
64 return Object == rhs.Object &&
65 Function == rhs.Function &&
66 NumArguments == rhs.NumArguments;
67 }
68
69 HashMapStringKey Object;
70 HashMapStringKey Function;
71 Uint32 NumArguments;
72 };
73 }
74
75 namespace std
76 {
77 template<>struct hash < Diligent::FunctionStubHashKey >
78 {
79 size_t operator()( const Diligent::FunctionStubHashKey &Key ) const
80 {
81 return ComputeHash(Key.Object, Key.Function, Key.NumArguments);
82 }
83 };
84 }
85
86 namespace Diligent
87 {
88 class HLSL2GLSLConverterImpl
89 {
90 public:
91 static const HLSL2GLSLConverterImpl& GetInstance();
92 struct ConversionAttribs
93 {
94 IShaderSourceInputStreamFactory *pSourceStreamFactory = nullptr;
95 IHLSL2GLSLConversionStream **ppConversionStream = nullptr;
96 const Char* HLSLSource = nullptr;
97 size_t NumSymbols = 0;
98 const Char* EntryPoint = nullptr;
99 SHADER_TYPE ShaderType = SHADER_TYPE_UNKNOWN;
100 bool IncludeDefinitions = false;
101 const Char* InputFileName = nullptr;
102 };
103
104 String Convert(ConversionAttribs &Attribs)const;
105 void CreateStream(const Char* InputFileName,
106 IShaderSourceInputStreamFactory *pSourceStreamFactory,
107 const Char* HLSLSource,
108 size_t NumSymbols,
109 IHLSL2GLSLConversionStream **ppStream)const;
110
111 private:
112 HLSL2GLSLConverterImpl();
113
114 struct HLSLObjectInfo
115 {
116 String GLSLType; // sampler2D, sampler2DShadow, image2D, etc.
117 Uint32 NumComponents; // 0,1,2,3 or 4
118 // Texture2D<float4> -> 4
119 // Texture2D<uint> -> 1
120 // Texture2D -> 0
121 HLSLObjectInfo( const String& Type, Uint32 NComp ) :
122 GLSLType( Type ),
123 NumComponents( NComp )
124 {}
125 };
126 struct ObjectsTypeHashType
127 {
128 // This is only required to make the code compile on paranoid MSVC 2017 compiler (19.10.25017):
129 // https://stackoverflow.com/questions/47604029/move-constructors-of-stl-containers-in-msvc-2017-are-not-marked-as-noexcept
130 ObjectsTypeHashType()noexcept {}
131 ObjectsTypeHashType(ObjectsTypeHashType&& rhs)noexcept :
132 m(std::move(rhs.m))
133 {}
134 ObjectsTypeHashType& operator = (ObjectsTypeHashType&&) = delete;
135 ObjectsTypeHashType(ObjectsTypeHashType&) = delete;
136 ObjectsTypeHashType& operator = (ObjectsTypeHashType&) = delete;
137
138 std::unordered_map<HashMapStringKey, HLSLObjectInfo> m;
139 };
140
141 struct GLSLStubInfo
142 {
143 String Name;
144 String Swizzle;
145 GLSLStubInfo( const String& _Name, const char* _Swizzle ) :
146 Name( _Name ),
147 Swizzle( _Swizzle )
148 {}
149 };
150 // Hash map that maps GLSL object, method and number of arguments
151 // passed to the original function, to the GLSL stub function
152 // Example: {"sampler2D", "Sample", 2} -> {"Sample_2", "_SWIZZLE"}
153 std::unordered_map<FunctionStubHashKey, GLSLStubInfo> m_GLSLStubs;
154
155 enum class TokenType
156 {
157 Undefined,
158 #define ADD_KEYWORD(keyword)kw_##keyword,
159 ITERATE_KEYWORDS(ADD_KEYWORD)
160 #undef ADD_KEYWORD
161 PreprocessorDirective,
162 Operator,
163 OpenBrace,
164 ClosingBrace,
165 OpenBracket,
166 ClosingBracket,
167 OpenStaple,
168 ClosingStaple,
169 OpenAngleBracket,
170 ClosingAngleBracket,
171 Identifier,
172 NumericConstant,
173 SrtingConstant,
174 Semicolon,
175 Comma,
176 TextBlock,
177 Assignment,
178 ComparisonOp,
179 BooleanOp,
180 BitwiseOp,
181 IncDecOp,
182 MathOp
183 };
184
185 struct TokenInfo
186 {
187 TokenType Type;
188 String Literal;
189 String Delimiter;
190 bool IsBuiltInType()const
191 {
192 static_assert( static_cast<int>(TokenType::kw_bool) == 1 && static_cast<int>(TokenType::kw_void) == 191,
193 "If you updated built-in types, double check that all types are defined between bool and void");
194 return Type >= TokenType::kw_bool && Type <= TokenType::kw_void;
195 }
196 bool IsFlowControl()const
197 {
198 static_assert( static_cast<int>(TokenType::kw_break) == 192 && static_cast<int>(TokenType::kw_while) == 202,
199 "If you updated control flow keywords, double check that all keywords are defined between break and while");
200 return Type >= TokenType::kw_break && Type <= TokenType::kw_while;
201 }
202 TokenInfo( TokenType _Type = TokenType :: Undefined,
203 const Char* _Literal = "",
204 const Char* _Delimiter = "" ) :
205 Type( _Type ),
206 Literal( _Literal ),
207 Delimiter(_Delimiter)
208 {}
209 };
210 typedef std::list<TokenInfo> TokenListType;
211
212
213 class ConversionStream : public ObjectBase<IHLSL2GLSLConversionStream>
214 {
215 public:
216 typedef ObjectBase<IHLSL2GLSLConversionStream> TBase;
217 ConversionStream(IReferenceCounters *pRefCounters,
218 const HLSL2GLSLConverterImpl &Converter,
219 const char* InputFileName,
220 IShaderSourceInputStreamFactory* pInputStreamFactory,
221 const Char* HLSLSource,
222 size_t NumSymbols,
223 bool bPreserveTokens);
224
225 String Convert(const Char* EntryPoint, SHADER_TYPE ShaderType, bool IncludeDefintions);
226 virtual void Convert(const Char* EntryPoint, SHADER_TYPE ShaderType, bool IncludeDefintions, IDataBlob **ppGLSLSource)override;
227
228 IMPLEMENT_QUERY_INTERFACE_IN_PLACE( IID_HLSL2GLSLConversionStream, TBase )
229
230 const String& GetInputFileName()const{ return m_InputFileName; }
231 private:
232 void InsertIncludes(String &GLSLSource, IShaderSourceInputStreamFactory* pSourceStreamFactory);
233 void Tokenize(const String &Source);
234
235 typedef std::unordered_map<String, bool> SamplerHashType;
236
237 const HLSLObjectInfo *FindHLSLObject(const String &Name );
238
239 void ProcessShaderDeclaration(TokenListType::iterator EntryPointToken, SHADER_TYPE ShaderType);
240
241 void ProcessObjectMethods(const TokenListType::iterator &ScopeStart, const TokenListType::iterator &ScopeEnd);
242
243 void ProcessRWTextures(const TokenListType::iterator &ScopeStart, const TokenListType::iterator &ScopeEnd);
244
245 void ProcessAtomics(const TokenListType::iterator &ScopeStart,
246 const TokenListType::iterator &ScopeEnd);
247
248 void RegisterStruct(TokenListType::iterator &Token);
249
250 void ProcessConstantBuffer(TokenListType::iterator &Token);
251 void ProcessStructuredBuffer(TokenListType::iterator &Token);
252 void ParseSamplers(TokenListType::iterator &ScopeStart, SamplerHashType &SamplersHash);
253 void ProcessTextureDeclaration(TokenListType::iterator &Token, const std::vector<SamplerHashType> &SamplersHash, ObjectsTypeHashType &Objects);
254 bool ProcessObjectMethod(TokenListType::iterator &Token, const TokenListType::iterator &ScopeStart, const TokenListType::iterator &ScopeEnd);
255 Uint32 CountFunctionArguments(TokenListType::iterator &Token, const TokenListType::iterator &ScopeEnd);
256 bool ProcessRWTextureStore(TokenListType::iterator &Token, const TokenListType::iterator &ScopeEnd);
257 void RemoveFlowControlAttribute(TokenListType::iterator &Token);
258 void RemoveSemantics();
259 void RemoveSpecialShaderAttributes();
260 void RemoveSemanticsFromBlock(TokenListType::iterator &Token, TokenType OpenBracketType, TokenType ClosingBracketType);
261
262 // IteratorType may be String::iterator or String::const_iterator.
263 // While iterator is convertible to const_iterator,
264 // iterator& cannot be converted to const_iterator& (Microsoft compiler allows
265 // such conversion, while gcc does not)
266 template<typename IteratorType>
267 String PrintTokenContext(IteratorType &TargetToken, Int32 NumAdjacentLines);
268
269 struct ShaderParameterInfo
270 {
271 enum class StorageQualifier : Int8
272 {
273 Unknown = 0,
274 In = 1,
275 Out = 2,
276 InOut = 3,
277 Ret = 4
278 }storageQualifier;
279
280 struct GSAttributes
281 {
282 enum class PrimitiveType : Int8
283 {
284 Undefined = 0,
285 Point = 1,
286 Line = 2,
287 Triangle = 3,
288 LineAdj = 4,
289 TriangleAdj = 5
290 };
291 enum class StreamType : Int8
292 {
293 Undefined = 0,
294 Point = 1,
295 Line = 2,
296 Triangle = 3
297 };
298 PrimitiveType PrimType;
299 StreamType Stream;
300 GSAttributes() :
301 PrimType(PrimitiveType::Undefined),
302 Stream(StreamType::Undefined)
303 {}
304 }GSAttribs;
305
306 struct HSAttributes
307 {
308 enum class InOutPatchType : Int8
309 {
310 Undefined = 0,
311 InputPatch = 1,
312 OutputPatch = 2
313 }PatchType;
314 HSAttributes() :
315 PatchType(InOutPatchType::Undefined)
316 {}
317 }HSAttribs;
318
319 String ArraySize;
320 String Type;
321 String Name;
322 String Semantic;
323 std::vector<ShaderParameterInfo> members;
324
325 ShaderParameterInfo() :
326 storageQualifier(StorageQualifier::Unknown)
327 {}
328 };
329 void ParseShaderParameter(TokenListType::iterator &Token, ShaderParameterInfo &ParamInfo);
330 void ProcessFunctionParameters( TokenListType::iterator &Token, std::vector<ShaderParameterInfo>& Params, bool &bIsVoid );
331 String AddFlatQualifier(const String& Type);
332 void ProcessFragmentShaderArguments( std::vector<ShaderParameterInfo>& Params,
333 String &GlobalVariables,
334 std::stringstream &ReturnHandlerSS,
335 String &Prologue );
336
337 String BuildParameterName(const std::vector<const ShaderParameterInfo*>& MemberStack, Char Separator, const Char* Prefix = "", const Char *SubstituteInstName = "", const Char *Index = "");
338
339 template<typename THandler>
340 void ProcessScope(TokenListType::iterator &Token, TokenListType::iterator ScopeEnd, TokenType OpenParenType, TokenType ClosingParenType, THandler Handler);
341
342 template<typename TArgHandler>
343 void ProcessShaderArgument( const ShaderParameterInfo &Param,
344 int ShaderInd,
345 int IsOutVar,
346 std::stringstream &PrologueSS,
347 TArgHandler ArgHandler);
348
349 void ProcessVertexShaderArguments( std::vector<ShaderParameterInfo>& Params,
350 String &Globals,
351 std::stringstream &ReturnHandlerSS,
352 String &Prologue );
353
354 void ProcessGeometryShaderArguments( TokenListType::iterator &TypeToken,
355 std::vector<ShaderParameterInfo>& Params,
356 String &Globals,
357 String &Prologue );
358
359 void ProcessHullShaderConstantFunction( const Char *FuncName, bool &bTakesInputPatch );
360
361 void ProcessShaderAttributes( TokenListType::iterator &TypeToken,
362 std::unordered_map<HashMapStringKey, String>& Attributes);
363
364 void ProcessHullShaderArguments( TokenListType::iterator &TypeToken,
365 std::vector<ShaderParameterInfo>& Params,
366 String &Globals,
367 std::stringstream &ReturnHandlerSS,
368 String &Prologue );
369 void ProcessDomainShaderArguments( TokenListType::iterator &TypeToken,
370 std::vector<ShaderParameterInfo>& Params,
371 String &Globals,
372 std::stringstream &ReturnHandlerSS,
373 String &Prologue );
374 void ProcessComputeShaderArguments( TokenListType::iterator &TypeToken,
375 std::vector<ShaderParameterInfo>& Params,
376 String &Globals,
377 String &Prologue );
378
379 void FindClosingBracket( TokenListType::iterator &Token, const TokenListType::iterator &ScopeEnd, TokenType OpenBracketType, TokenType ClosingBracketType );
380
381 void ProcessReturnStatements( TokenListType::iterator &Token, bool IsVoid, const Char *EntryPoint, const Char *MacroName );
382
383 void ProcessGSOutStreamOperations( TokenListType::iterator &Token, const String &OutStreamName, const char *EntryPoint );
384
385 String BuildGLSLSource();
386
387 // Tokenized source code
388 TokenListType m_Tokens;
389
390 // List of tokens defining structs
391 std::unordered_map<HashMapStringKey, TokenListType::iterator> m_StructDefinitions;
392
393 // Stack of parsed objects, for every scope level.
394 // There are currently only two levels:
395 // level 0 - global scope, contains all global objects
396 // (textures, buffers)
397 // level 1 - function body, contains all objects
398 // defined as function arguments
399 std::vector< ObjectsTypeHashType > m_Objects;
400
401 const bool m_bPreserveTokens;
402 const HLSL2GLSLConverterImpl &m_Converter;
403
404 // This member is only used to compare input name
405 // when subsequent shaders are converted from already tokenized source
406 const String m_InputFileName;
407 };
408
409 // HLSL keyword->token info hash map
410 // Example: "Texture2D" -> TokenInfo(TokenType::Texture2D, "Texture2D")
411 std::unordered_map<HashMapStringKey, TokenInfo> m_HLSLKeywords;
412
413 // Set of all GLSL image types (image1D, uimage1D, iimage1D, image2D, ... )
414 std::unordered_set<HashMapStringKey> m_ImageTypes;
415
416 // Set of all HLSL atomic operations (InterlockedAdd, InterlockedOr, ...)
417 std::unordered_set<HashMapStringKey> m_AtomicOperations;
418
419 // HLSL semantic -> glsl variable, for every shader stage and input/output type (in == 0, out == 1)
420 // Example: [vertex, output] SV_Position -> gl_Position
421 // [fragment, input] SV_Position -> gl_FragCoord
422 static constexpr int InVar = 0;
423 static constexpr int OutVar = 1;
424 std::unordered_map<HashMapStringKey, String> m_HLSLSemanticToGLSLVar[6][2];
425 };
426 }
427
428 // Intro
429 // DirectX and OpenGL use different shading languages. While mostly being very similar,
430 // the language syntax differs substantially sometimes. Having two versions of each
431 // shader is clearly not an option for real projects. Maintaining intermediate representation
432 // that translates to both languages is one solution, but it might complicate shader development
433 // and debugging.
434 //
435 // HLSL converter allows HLSL shader files to be converted into GLSL source.
436 // The entire shader development can thus be performed using HLSL tools. Since no intermediate
437 // representation is used, shader files can be directly compiled by the HLSL compiler.
438 // All tools available for HLSL shader devlopment, analysis and optimization can be
439 // used. The source can then be transaprently converted to GLSL.
440 //
441 //
442 // Using HLSL Converter
443 // * The following rules are used to convert HLSL texture declaration into GLSL sampler:
444 // - HLSL texture dimension defines GLSL sampler dimension:
445 // - Texture2D -> sampler2D
446 // - TextureCube -> samplerCube
447 // - HLSL texture component type defines GLSL sampler type. If no type is specified, float4 is assumed:
448 // - Texture2D<float> -> sampler2D
449 // - Texture3D<uint4> -> usampler3D
450 // - Texture2DArray<int2> -> isampler2DArray
451 // - Texture2D -> sampler2D
452 // - To distinguish if sampler should be shadow or not, the converter tries to find <Texture Name>_sampler
453 // among samplers (global variables and function arguments). If the sampler type is comparison,
454 // the texture is converted to shadow sampler. If sampler state is either not comparison or not found,
455 // regular sampler is used.
456 // Examples:
457 // - Texture2D g_ShadowMap; -> sampler2DShadow g_ShadowMap;
458 // SamplerComparisonState g_ShadowMap_sampler;
459 // - Texture2D g_Tex2D; -> sampler2D g_Tex2D;
460 // SamplerState g_Tex2D_sampler;
461 // Texture3D g_Tex3D; -> sampler3D g_Tex3D;
462 //
463 // * GLSL requires format to be specified for all images allowing writes. HLSL converter allows GLSL image
464 // format specification inside the special comment block:
465 // Example:
466 // RWTexture2D<float /* format=r32f */ > Tex2D;
467 // * In OpenGL tessellation, domain, partitioning, and topology are properties of tessellation evaluation
468 // shader rather than tessellation control shader. The following specially formatted comment should be placed
469 // on top of domain shader declararion to specify the attributes
470 // /* partitioning = {integer|fractional_even|fractional_odd}, outputtopology = {triangle_cw|triangle_ccw} */
471 // Example:
472 // /* partitioning = fractional_even, outputtopology = triangle_cw */
473
474
475 // Requirements:
476 // * GLSL allows samplers to be declared as global variables or function arguments only.
477 // It does not allow local variables of sampler type.
478 //
479 // Important notes/known issues:
480 //
481 // * GLSL compiler does not handle float3 structure members correctly. It is
482 // strongly suggested not to use this type in structure definitions
483 //
484 // * At least NVidia GLSL compiler does not apply layout(row_major) to
485 // structure members. By default, all matrices in both HLSL and GLSL
486 // are column major
487 //
488 // * GLSL compiler does not properly handle structs passed as function arguments!!!!
489 // struct MyStruct
490 // {
491 // matrix Matr;
492 // }
493 // void Func(in MyStruct S)
494 // {
495 // ...
496 // mul(f4PosWS, S.Matr); <--- This will not work!!!
497 // }
498 // DO NOT pass structs to functions, use only built-in types!!!
499 //
500 // * GLSL does not support most of the implicit type conversions. The following are some
501 // examples of required modifications to HLSL code:
502 // ** float4 vec = 0; -> float4 vec = float4(0.0, 0.0, 0.0, 0.0);
503 // ** float x = 0; -> float x = 0.0;
504 // ** uint x = 0; -> uint x = 0u;
505 // ** GLES is immensely strict about type conversions. For instance,
506 // this code will produce compiler error: float4(0, 0, 0, 0)
507 // It must be written as float4(0.0, 0.0, 0.0, 0.0)
508 // * GLSL does not support relational and boolean operations on vector types:
509 // ** float2 p = float2(1.0,2.0), q = float2(3.0,4.0);
510 // bool2 b = x < y; -> Error
511 // all(p<q) -> Error
512 // ** To facilitate relational and boolean operations on vector types, the following
513 // functions are predefined:
514 // - Less
515 // - LessEqual
516 // - Greater
517 // - GreaterEqual
518 // - Equal
519 // - NotEqual
520 // - Not
521 // - And
522 // - Or
523 // - BoolToFloat
524 // ** Examples:
525 // bool2 b = x < y; -> bool2 b = Less(x, y);
526 // all(p>=q) -> all( GreaterEqual(p,q) )
527 //
528 // * When accessing elements of an HLSL matrix, the first index is always row:
529 // mat[row][column]
530 // In GLSL, the first index is always column:
531 // mat[column][row]
532 // MATRIX_ELEMENT(mat, row, col) macros is provided to facilitate matrix element retrieval
533
534 // * The following functions do not have counterparts in GLSL and should be avoided:
535 // ** Texture2DArray.SampleCmpLevelZero()
536 // ** TextureCube.SampleCmpLevelZero()
537 // ** TextureCubeArray.SampleCmpLevelZero()
538
539
540 // * Input variables to a shader stage must be listed in exact same order as outputs from
541 // the previous stage. Function return value counts as the first output argument.
Diligent::SHADER_TYPE
SHADER_TYPE
Describes the shader type.
Definition: Shader.h:46
Diligent
Namespace for the OpenGL implementation of the graphics engine.
Definition: BufferD3D11Impl.h:34
std
Definition: AdvancedMath.h:316
Diligent::SHADER_TYPE_UNKNOWN
Unknown shader type.
Definition: Shader.h:48