├── .travis.yml ├── .gitignore ├── premake4.lua ├── Makefile ├── hlslparser.sln ├── LICENSE ├── src ├── CodeWriter.h ├── HLSLGenerator.h ├── MSLGenerator.h ├── CodeWriter.cpp ├── Main.cpp ├── Engine.cpp ├── HLSLTokenizer.h ├── Engine.h ├── HLSLParser.h ├── GLSLGenerator.h ├── HLSLTokenizer.cpp ├── HLSLTree.h ├── HLSLGenerator.cpp └── HLSLTree.cpp ├── README.md ├── hlslparser.vcxproj.filters └── hlslparser.vcxproj /.travis.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - linux 3 | - osx 4 | sudo: required 5 | dist: trusty 6 | language: cpp 7 | script: make 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.user 2 | *.ncb 3 | *.suo 4 | *.tlog 5 | *.lastbuildstate 6 | *.unsuccessfulbuild 7 | *.ipch 8 | *.resources 9 | *.pdb 10 | *.aps 11 | *.bak 12 | /Debug 13 | /Release 14 | *.log 15 | *.sdf 16 | *.opensdf 17 | /build 18 | -------------------------------------------------------------------------------- /premake4.lua: -------------------------------------------------------------------------------- 1 | solution "HLSLParser" 2 | location "build" 3 | configurations { "Debug", "Release" } 4 | 5 | project "HLSLParser" 6 | kind "ConsoleApp" 7 | language "C++" 8 | files { "src/**.h", "src/**.cpp" } 9 | 10 | configuration "Debug" 11 | targetdir "bin/debug" 12 | defines { "DEBUG" } 13 | flags { "Symbols" } 14 | 15 | configuration "Release" 16 | targetdir "bin/release" 17 | defines { "NDEBUG" } 18 | flags { "Optimize" } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .SUFFIXES: 2 | MAKEFLAGS+=-r 3 | 4 | BUILD=build 5 | 6 | SOURCES=$(wildcard src/*.cpp src/base/*.cpp) 7 | OBJECTS=$(SOURCES:%=$(BUILD)/%.o) 8 | 9 | EXECUTABLE=$(BUILD)/hlslparser 10 | 11 | CXXFLAGS=-g -Wall -Wformat -Wformat-nonliteral -std=c++11 12 | 13 | all: $(EXECUTABLE) 14 | 15 | $(EXECUTABLE): $(OBJECTS) 16 | $(CXX) $(OBJECTS) $(LDFLAGS) -o $@ 17 | 18 | $(BUILD)/%.o: % 19 | @mkdir -p $(dir $@) 20 | $(CXX) $< $(CXXFLAGS) -c -MMD -MP -o $@ 21 | 22 | -include $(OBJECTS:.o=.d) 23 | clean: 24 | rm -rf $(BUILD) 25 | 26 | .PHONY: all clean 27 | -------------------------------------------------------------------------------- /hlslparser.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hlslparser", "hlslparser.vcxproj", "{FAA5AD82-3351-479F-A315-F287EBD0A816}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {FAA5AD82-3351-479F-A315-F287EBD0A816}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {FAA5AD82-3351-479F-A315-F287EBD0A816}.Debug|Win32.Build.0 = Debug|Win32 16 | {FAA5AD82-3351-479F-A315-F287EBD0A816}.Release|Win32.ActiveCfg = Release|Win32 17 | {FAA5AD82-3351-479F-A315-F287EBD0A816}.Release|Win32.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2014 Unknown Worlds Entertainment, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/CodeWriter.h: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // 3 | // Render/CodeWriter.h 4 | // 5 | // Created by Max McGuire (max@unknownworlds.com) 6 | // Copyright (c) 2013, Unknown Worlds Entertainment, Inc. 7 | // 8 | //============================================================================= 9 | 10 | #ifndef CODE_WRITER_H 11 | #define CODE_WRITER_H 12 | 13 | #include "Engine.h" 14 | #include 15 | 16 | #if defined(__GNUC__) 17 | #define M4_PRINTF_ATTR(string_index, first_to_check) __attribute__((format(printf, string_index, first_to_check))) 18 | #else 19 | #define M4_PRINTF_ATTR(string_index, first_to_check) 20 | #endif 21 | 22 | namespace M4 23 | { 24 | 25 | class Allocator; 26 | 27 | /** 28 | * This class is used for outputting code. It handles indentation and inserting #line markers 29 | * to match the desired output line numbers. 30 | */ 31 | class CodeWriter 32 | { 33 | 34 | public: 35 | CodeWriter(bool writeFileNames = true); 36 | 37 | void BeginLine(int indent, const char* fileName = NULL, int lineNumber = -1); 38 | M4_PRINTF_ATTR(2, 3) void Write(const char* format, ...); 39 | void EndLine(const char* text = NULL); 40 | 41 | M4_PRINTF_ATTR(3, 4) void WriteLine(int indent, const char* format, ...); 42 | M4_PRINTF_ATTR(5, 6) void WriteLineTagged(int indent, const char* fileName, int lineNumber, const char* format, ...); 43 | 44 | const char* GetResult() const; 45 | void Reset(); 46 | 47 | private: 48 | 49 | std::string m_buffer; 50 | int m_currentLine; 51 | const char* m_currentFileName; 52 | int m_spacesPerIndent; 53 | bool m_writeLines; 54 | bool m_writeFileNames; 55 | 56 | }; 57 | 58 | } 59 | 60 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | HLSLParser 2 | ========== 3 | 4 | This is a fork of [Unknownworld's hlslparser](https://github.com/unknownworlds/hlslparser) adapted to our needs in [The Witness](http://the-witness.net). We currently use it to translate pseudo-HLSL shaders (using the legacy D3D9 syntax) to HLSL10 and Metal Shading Language (MSL). There's also a GLSL translator available that we do not use yet, but that is being maintained by community contributions. 5 | 6 | The HLSL parser has been extended with many HLSL10 features, but retaining the original HLSL C-based syntax. 7 | 8 | For example, the following functions in our HLSL dialect: 9 | 10 | ```C 11 | float tex2Dcmp(sampler2DShadow s, float3 texcoord_comparevalue); 12 | float4 tex2DMSfetch(sampler2DMS s, int2 texcoord, int sample); 13 | int2 tex2Dsize(sampler2D s); 14 | ``` 15 | 16 | Are equivalent to these methods in HLSL10: 17 | 18 | ```C++ 19 | float Texture2D::SampleCmp(SamplerComparisonState s, float2 texcoord, float comparevalue); 20 | float4 Texture2DMS::Load(int2 texcoord, int sample); 21 | void Texture2D::GetDimensions(out uint w, out uint h); 22 | ``` 23 | 24 | 25 | 26 | Here are the original release notes: 27 | 28 | 29 | > HLSL Parser and GLSL code generator 30 | > 31 | > This is the code we used in Natural Selection 2 to convert HLSL shader code to 32 | GLSL for use with OpenGL. The code is pulled from a larger codebase and has some 33 | dependencies which have been replaced with stubs. These dependencies are all very 34 | basic (array classes, memory allocators, etc.) so replacing them with our own 35 | equivalent should be simple if you want to use this code. 36 | > 37 | > The parser is designed to work with HLSL code written in the legacy Direct3D 9 38 | style (e.g. D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY should be used with D3D11). 39 | The parser works with cbuffers for uniforms, so in addition to generating GLSL, 40 | there is a class provided for generating D3D9-compatible HLSL which doesn't 41 | support cbuffers. The GLSL code requires version 3.1 for support of uniform blocks. 42 | The parser is designed to catch all errors and generate "clean" GLSL which can 43 | then be compiled without any errors. 44 | > 45 | > The HLSL parsing is done though a basic recursive descent parser coded by hand 46 | rather than using a parser generator. We believe makes the code easier to 47 | understand and work with. 48 | > 49 | > To get consistent results from Direct3D and OpenGL, our engine renders in OpenGL 50 | "upside down". This is automatically added into the generated GLSL vertex shaders. 51 | > 52 | > Although this code was written specifically for our use, we hope that it may be 53 | useful as an educational tool or a base for someone who wants to do something 54 | similar. 55 | -------------------------------------------------------------------------------- /hlslparser.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/HLSLGenerator.h: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // 3 | // Render/HLSLGenerator.h 4 | // 5 | // Created by Max McGuire (max@unknownworlds.com) 6 | // Copyright (c) 2013, Unknown Worlds Entertainment, Inc. 7 | // 8 | //============================================================================= 9 | 10 | #ifndef HLSL_GENERATOR_H 11 | #define HLSL_GENERATOR_H 12 | 13 | #include "CodeWriter.h" 14 | #include "HLSLTree.h" 15 | 16 | namespace M4 17 | { 18 | 19 | class HLSLTree; 20 | struct HLSLFunction; 21 | struct HLSLStruct; 22 | 23 | /** 24 | * This class is used to generate HLSL which is compatible with the D3D9 25 | * compiler (i.e. no cbuffers). 26 | */ 27 | class HLSLGenerator 28 | { 29 | 30 | public: 31 | 32 | enum Target 33 | { 34 | Target_VertexShader, 35 | Target_PixelShader, 36 | }; 37 | 38 | HLSLGenerator(); 39 | 40 | bool Generate(HLSLTree* tree, Target target, const char* entryName, bool legacy); 41 | const char* GetResult() const; 42 | 43 | private: 44 | 45 | void OutputExpressionList(HLSLExpression* expression); 46 | void OutputExpression(HLSLExpression* expression); 47 | void OutputArguments(HLSLArgument* argument); 48 | void OutputAttributes(int indent, HLSLAttribute* attribute); 49 | void OutputStatements(int indent, HLSLStatement* statement); 50 | void OutputDeclaration(HLSLDeclaration* declaration); 51 | void OutputDeclaration(const HLSLType& type, const char* name, const char* semantic = NULL, const char* registerName = NULL, HLSLExpression* defaultValue = NULL); 52 | void OutputDeclarationType(const HLSLType& type); 53 | void OutputDeclarationBody(const HLSLType& type, const char* name, const char* semantic =NULL, const char* registerName = NULL, HLSLExpression * assignment = NULL); 54 | 55 | /** Generates a name of the format "base+n" where n is an integer such that the name 56 | * isn't used in the syntax tree. */ 57 | bool ChooseUniqueName(const char* base, char* dst, int dstLength) const; 58 | 59 | private: 60 | 61 | CodeWriter m_writer; 62 | 63 | const HLSLTree* m_tree; 64 | const char* m_entryName; 65 | Target m_target; 66 | bool m_legacy; 67 | bool m_isInsideBuffer; 68 | 69 | char m_textureSampler2DStruct[64]; 70 | char m_textureSampler2DCtor[64]; 71 | char m_textureSampler2DShadowStruct[64]; 72 | char m_textureSampler2DShadowCtor[64]; 73 | char m_textureSampler3DStruct[64]; 74 | char m_textureSampler3DCtor[64]; 75 | char m_textureSamplerCubeStruct[64]; 76 | char m_textureSamplerCubeCtor[64]; 77 | char m_tex2DFunction[64]; 78 | char m_tex2DProjFunction[64]; 79 | char m_tex2DLodFunction[64]; 80 | char m_tex2DBiasFunction[64]; 81 | char m_tex2DGradFunction[64]; 82 | char m_tex2DGatherFunction[64]; 83 | char m_tex2DSizeFunction[64]; 84 | char m_tex2DFetchFunction[64]; 85 | char m_tex2DCmpFunction[64]; 86 | char m_tex2DMSFetchFunction[64]; 87 | char m_tex2DMSSizeFunction[64]; 88 | char m_tex3DFunction[64]; 89 | char m_tex3DLodFunction[64]; 90 | char m_tex3DBiasFunction[64]; 91 | char m_tex3DSizeFunction[64]; 92 | char m_texCubeFunction[64]; 93 | char m_texCubeLodFunction[64]; 94 | char m_texCubeBiasFunction[64]; 95 | char m_texCubeSizeFunction[64]; 96 | }; 97 | 98 | } // M4 99 | 100 | #endif -------------------------------------------------------------------------------- /src/MSLGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef MSL_GENERATOR_H 2 | #define MSL_GENERATOR_H 3 | 4 | #include "CodeWriter.h" 5 | #include "HLSLTree.h" 6 | 7 | namespace M4 8 | { 9 | 10 | class HLSLTree; 11 | struct HLSLFunction; 12 | struct HLSLStruct; 13 | 14 | /** 15 | * This class is used to generate MSL shaders. 16 | */ 17 | class MSLGenerator 18 | { 19 | public: 20 | enum Target 21 | { 22 | Target_VertexShader, 23 | Target_FragmentShader, 24 | }; 25 | 26 | enum Flags 27 | { 28 | Flag_ConstShadowSampler = 1 << 0, 29 | Flag_PackMatrixRowMajor = 1 << 1, 30 | Flag_NoIndexAttribute = 1 << 2, 31 | }; 32 | 33 | struct Options 34 | { 35 | unsigned int flags; 36 | unsigned int bufferRegisterOffset; 37 | int (*attributeCallback)(const char* name, unsigned int index); 38 | 39 | Options() 40 | { 41 | flags = 0; 42 | bufferRegisterOffset = 0; 43 | attributeCallback = NULL; 44 | } 45 | }; 46 | 47 | MSLGenerator(); 48 | 49 | bool Generate(HLSLTree* tree, Target target, const char* entryName, const Options& options = Options()); 50 | const char* GetResult() const; 51 | 52 | private: 53 | 54 | // @@ Rename class argument. Add buffers & textures. 55 | struct ClassArgument 56 | { 57 | const char* name; 58 | HLSLType type; 59 | //const char* typeName; // @@ Do we need more than the type name? 60 | const char* registerName; 61 | 62 | ClassArgument * nextArg; 63 | 64 | ClassArgument(const char* name, HLSLType type, const char * registerName) : 65 | name(name), type(type), registerName(registerName) 66 | { 67 | nextArg = NULL; 68 | } 69 | }; 70 | 71 | void AddClassArgument(ClassArgument * arg); 72 | 73 | void Prepass(HLSLTree* tree, Target target, HLSLFunction* entryFunction); 74 | void CleanPrepass(); 75 | 76 | void PrependDeclarations(); 77 | 78 | void OutputStatements(int indent, HLSLStatement* statement); 79 | void OutputAttributes(int indent, HLSLAttribute* attribute); 80 | void OutputDeclaration(HLSLDeclaration* declaration); 81 | void OutputStruct(int indent, HLSLStruct* structure); 82 | void OutputBuffer(int indent, HLSLBuffer* buffer); 83 | void OutputFunction(int indent, HLSLFunction* function); 84 | void OutputExpression(HLSLExpression* expression, HLSLExpression* parentExpression); 85 | void OutputCast(const HLSLType& type); 86 | 87 | void OutputArguments(HLSLArgument* argument); 88 | void OutputDeclaration(const HLSLType& type, const char* name, HLSLExpression* assignment, bool isRef = false, bool isConst = false, int alignment = 0); 89 | void OutputDeclarationType(const HLSLType& type, bool isConst = false, bool isRef = false, int alignment = 0); 90 | void OutputDeclarationBody(const HLSLType& type, const char* name, HLSLExpression* assignment, bool isRef = false); 91 | void OutputExpressionList(HLSLExpression* expression); 92 | void OutputFunctionCallStatement(int indent, HLSLFunctionCall* functionCall); 93 | void OutputFunctionCall(HLSLFunctionCall* functionCall); 94 | 95 | const char* TranslateInputSemantic(const char* semantic); 96 | const char* TranslateOutputSemantic(const char* semantic); 97 | 98 | void Error(const char* format, ...); 99 | 100 | private: 101 | 102 | CodeWriter m_writer; 103 | 104 | HLSLTree* m_tree; 105 | const char* m_entryName; 106 | Target m_target; 107 | Options m_options; 108 | 109 | bool m_error; 110 | 111 | ClassArgument * m_firstClassArgument; 112 | ClassArgument * m_lastClassArgument; 113 | }; 114 | 115 | } // M4 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /src/CodeWriter.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // 3 | // Render/CodeWriter.cpp 4 | // 5 | // Created by Max McGuire (max@unknownworlds.com) 6 | // Copyright (c) 2013, Unknown Worlds Entertainment, Inc. 7 | // 8 | //============================================================================= 9 | 10 | //#include "Engine/Assert.h" 11 | //#include "Engine/String.h" 12 | #include "Engine.h" 13 | 14 | #include "CodeWriter.h" 15 | 16 | #include 17 | 18 | namespace M4 19 | { 20 | 21 | static const int _maxLineLength = 2048; 22 | 23 | CodeWriter::CodeWriter(bool writeFileNames) 24 | { 25 | m_currentLine = 1; 26 | m_currentFileName = NULL; 27 | m_spacesPerIndent = 4; 28 | m_writeLines = true; 29 | m_writeFileNames = writeFileNames; 30 | } 31 | 32 | void CodeWriter::BeginLine(int indent, const char* fileName, int lineNumber) 33 | { 34 | if (m_writeLines) 35 | { 36 | bool outputLine = false; 37 | bool outputFile = false; 38 | 39 | // Output a line number pragma if necessary. 40 | if (fileName != NULL && m_currentFileName != fileName) 41 | { 42 | m_currentFileName = fileName; 43 | fileName = m_currentFileName; 44 | outputFile = true; 45 | } 46 | if (lineNumber != -1 && m_currentLine != lineNumber) 47 | { 48 | m_currentLine = lineNumber; 49 | outputLine = true; 50 | } 51 | if (outputLine || outputFile) 52 | { 53 | char buffer[256]; 54 | String_Printf(buffer, sizeof(buffer), "#line %d", lineNumber); 55 | m_buffer += buffer; 56 | if (outputFile && m_writeFileNames) 57 | { 58 | m_buffer += " \""; 59 | m_buffer += fileName; 60 | m_buffer += "\"\n"; 61 | } 62 | else 63 | { 64 | m_buffer += "\n"; 65 | } 66 | } 67 | } 68 | 69 | // Handle the indentation. 70 | for (int i = 0; i < indent * m_spacesPerIndent; ++i) 71 | { 72 | m_buffer += " "; 73 | } 74 | } 75 | 76 | void CodeWriter::EndLine(const char* text) 77 | { 78 | if (text != NULL) 79 | { 80 | m_buffer += text; 81 | } 82 | m_buffer += "\n"; 83 | ++m_currentLine; 84 | } 85 | 86 | void CodeWriter::Write(const char* format, ...) 87 | { 88 | va_list args; 89 | va_start(args, format); 90 | 91 | char buffer[_maxLineLength]; 92 | String_PrintfArgList(buffer, sizeof(buffer), format, args); 93 | 94 | m_buffer += buffer; 95 | 96 | va_end(args); 97 | } 98 | 99 | void CodeWriter::WriteLine(int indent, const char* format, ...) 100 | { 101 | va_list args; 102 | va_start(args, format); 103 | 104 | char buffer[_maxLineLength]; 105 | 106 | int result = String_PrintfArgList(buffer, sizeof(buffer), format, args); 107 | ASSERT(result != -1); 108 | 109 | for (int i = 0; i < indent * m_spacesPerIndent; ++i) 110 | { 111 | m_buffer += " "; 112 | } 113 | m_buffer += buffer; 114 | 115 | EndLine(); 116 | 117 | va_end(args); 118 | } 119 | 120 | void CodeWriter::WriteLineTagged(int indent, const char* fileName, int lineNumber, const char* format, ...) 121 | { 122 | va_list args; 123 | va_start(args, format); 124 | 125 | BeginLine(indent, fileName, lineNumber); 126 | 127 | char buffer[_maxLineLength]; 128 | int result = String_PrintfArgList(buffer, sizeof(buffer), format, args); 129 | ASSERT(result != -1); 130 | 131 | m_buffer += buffer; 132 | 133 | EndLine(); 134 | 135 | va_end(args); 136 | } 137 | 138 | const char* CodeWriter::GetResult() const 139 | { 140 | return m_buffer.c_str(); 141 | } 142 | 143 | void CodeWriter::Reset() 144 | { 145 | m_buffer.clear(); 146 | } 147 | 148 | } -------------------------------------------------------------------------------- /src/Main.cpp: -------------------------------------------------------------------------------- 1 | #include "HLSLParser.h" 2 | 3 | #include "GLSLGenerator.h" 4 | #include "HLSLGenerator.h" 5 | #include "MSLGenerator.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | enum Target 12 | { 13 | Target_VertexShader, 14 | Target_FragmentShader, 15 | }; 16 | 17 | enum Language 18 | { 19 | Language_GLSL, 20 | Language_HLSL, 21 | Language_LegacyHLSL, 22 | Language_Metal, 23 | }; 24 | 25 | std::string ReadFile( const char* fileName ) 26 | { 27 | std::ifstream ifs( fileName ); 28 | std::stringstream buffer; 29 | buffer << ifs.rdbuf(); 30 | return buffer.str(); 31 | } 32 | 33 | void PrintUsage() 34 | { 35 | std::cerr << "usage: hlslparser [-h] [-fs | -vs] FILENAME ENTRYNAME\n" 36 | << "\n" 37 | << "Translate HLSL shader to GLSL shader.\n" 38 | << "\n" 39 | << "positional arguments:\n" 40 | << " FILENAME input file name\n" 41 | << " ENTRYNAME entry point of the shader\n" 42 | << "\n" 43 | << "optional arguments:\n" 44 | << " -h, --help show this help message and exit\n" 45 | << " -fs generate fragment shader (default)\n" 46 | << " -vs generate vertex shader\n" 47 | << " -glsl generate GLSL (default)\n" 48 | << " -hlsl generate HLSL\n" 49 | << " -legacyhlsl generate legacy HLSL\n" 50 | << " -metal generate MSL\n"; 51 | } 52 | 53 | int main( int argc, char* argv[] ) 54 | { 55 | using namespace M4; 56 | 57 | // Parse arguments 58 | const char* fileName = NULL; 59 | const char* entryName = NULL; 60 | 61 | Target target = Target_FragmentShader; 62 | Language language = Language_GLSL; 63 | 64 | for( int argn = 1; argn < argc; ++argn ) 65 | { 66 | const char* const arg = argv[ argn ]; 67 | 68 | if( String_Equal( arg, "-h" ) || String_Equal( arg, "--help" ) ) 69 | { 70 | PrintUsage(); 71 | return 0; 72 | } 73 | else if( String_Equal( arg, "-fs" ) ) 74 | { 75 | target = Target_FragmentShader; 76 | } 77 | else if( String_Equal( arg, "-vs" ) ) 78 | { 79 | target = Target_VertexShader; 80 | } 81 | else if( String_Equal( arg, "-glsl" ) ) 82 | { 83 | language = Language_GLSL; 84 | } 85 | else if( String_Equal( arg, "-hlsl" ) ) 86 | { 87 | language = Language_HLSL; 88 | } 89 | else if( String_Equal( arg, "-legacyhlsl" ) ) 90 | { 91 | language = Language_LegacyHLSL; 92 | } 93 | else if( String_Equal( arg, "-metal" ) ) 94 | { 95 | language = Language_Metal; 96 | } 97 | else if( fileName == NULL ) 98 | { 99 | fileName = arg; 100 | } 101 | else if( entryName == NULL ) 102 | { 103 | entryName = arg; 104 | } 105 | else 106 | { 107 | Log_Error( "Too many arguments\n" ); 108 | PrintUsage(); 109 | return 1; 110 | } 111 | } 112 | 113 | if( fileName == NULL || entryName == NULL ) 114 | { 115 | Log_Error( "Missing arguments\n" ); 116 | PrintUsage(); 117 | return 1; 118 | } 119 | 120 | // Read input file 121 | const std::string source = ReadFile( fileName ); 122 | 123 | // Parse input file 124 | Allocator allocator; 125 | HLSLParser parser( &allocator, fileName, source.data(), source.size() ); 126 | HLSLTree tree( &allocator ); 127 | if( !parser.Parse( &tree ) ) 128 | { 129 | Log_Error( "Parsing failed, aborting\n" ); 130 | return 1; 131 | } 132 | 133 | // Generate output 134 | if (language == Language_GLSL) 135 | { 136 | GLSLGenerator generator; 137 | if (!generator.Generate( &tree, GLSLGenerator::Target(target), GLSLGenerator::Version_140, entryName )) 138 | { 139 | Log_Error( "Translation failed, aborting\n" ); 140 | return 1; 141 | } 142 | 143 | std::cout << generator.GetResult(); 144 | } 145 | else if (language == Language_HLSL) 146 | { 147 | HLSLGenerator generator; 148 | if (!generator.Generate( &tree, HLSLGenerator::Target(target), entryName, language == Language_LegacyHLSL )) 149 | { 150 | Log_Error( "Translation failed, aborting\n" ); 151 | return 1; 152 | } 153 | 154 | std::cout << generator.GetResult(); 155 | } 156 | else if (language == Language_Metal) 157 | { 158 | MSLGenerator generator; 159 | if (!generator.Generate( &tree, MSLGenerator::Target(target), entryName )) 160 | { 161 | Log_Error( "Translation failed, aborting\n" ); 162 | return 1; 163 | } 164 | 165 | std::cout << generator.GetResult(); 166 | } 167 | 168 | return 0; 169 | } 170 | -------------------------------------------------------------------------------- /hlslparser.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {FAA5AD82-3351-479F-A315-F287EBD0A816} 15 | hlslparser 16 | 17 | 18 | 19 | Application 20 | true 21 | v120 22 | MultiByte 23 | 24 | 25 | Application 26 | false 27 | v120 28 | true 29 | MultiByte 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | Level3 45 | Disabled 46 | true 47 | 48 | 49 | true 50 | 51 | 52 | 53 | 54 | Level3 55 | MaxSpeed 56 | true 57 | true 58 | true 59 | 60 | 61 | true 62 | true 63 | true 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/Engine.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Engine.h" 3 | 4 | #include // vsnprintf 5 | #include // strcmp, strcasecmp 6 | #include // strtod, strtol 7 | 8 | 9 | namespace M4 { 10 | 11 | // Engine/String.cpp 12 | 13 | int String_PrintfArgList(char * buffer, int size, const char * format, va_list args) { 14 | 15 | va_list tmp; 16 | va_copy(tmp, args); 17 | 18 | #if _MSC_VER >= 1400 19 | int n = vsnprintf_s(buffer, size, _TRUNCATE, format, tmp); 20 | #else 21 | int n = vsnprintf(buffer, size, format, tmp); 22 | #endif 23 | 24 | va_end(tmp); 25 | 26 | if (n < 0 || n > size) return -1; 27 | return n; 28 | } 29 | 30 | int String_Printf(char * buffer, int size, const char * format, ...) { 31 | 32 | va_list args; 33 | va_start(args, format); 34 | 35 | int n = String_PrintfArgList(buffer, size, format, args); 36 | 37 | va_end(args); 38 | 39 | return n; 40 | } 41 | 42 | int String_FormatFloat(char * buffer, int size, float value) { 43 | return String_Printf(buffer, size, "%f", value); 44 | } 45 | 46 | bool String_Equal(const char * a, const char * b) { 47 | if (a == b) return true; 48 | if (a == NULL || b == NULL) return false; 49 | return strcmp(a, b) == 0; 50 | } 51 | 52 | bool String_EqualNoCase(const char * a, const char * b) { 53 | if (a == b) return true; 54 | if (a == NULL || b == NULL) return false; 55 | #if _MSC_VER 56 | return _stricmp(a, b) == 0; 57 | #else 58 | return strcasecmp(a, b) == 0; 59 | #endif 60 | } 61 | 62 | double String_ToDouble(const char * str, char ** endptr) { 63 | return strtod(str, endptr); 64 | } 65 | 66 | int String_ToInteger(const char * str, char ** endptr) { 67 | return strtol(str, endptr, 10); 68 | } 69 | 70 | int String_ToIntegerHex(const char * str, char ** endptr) { 71 | return strtol(str, endptr, 16); 72 | } 73 | 74 | 75 | 76 | // Engine/Log.cpp 77 | 78 | void Log_Error(const char * format, ...) { 79 | va_list args; 80 | va_start(args, format); 81 | Log_ErrorArgList(format, args); 82 | va_end(args); 83 | } 84 | 85 | void Log_ErrorArgList(const char * format, va_list args) { 86 | #if 1 // @@ Don't we need to do this? 87 | va_list tmp; 88 | va_copy(tmp, args); 89 | vprintf( format, args ); 90 | va_end(tmp); 91 | #else 92 | vprintf( format, args ); 93 | #endif 94 | } 95 | 96 | 97 | // Engine/StringPool.cpp 98 | 99 | StringPool::StringPool(Allocator * allocator) : stringArray(allocator) { 100 | } 101 | StringPool::~StringPool() { 102 | for (int i = 0; i < stringArray.GetSize(); i++) { 103 | free((void *)stringArray[i]); 104 | stringArray[i] = NULL; 105 | } 106 | } 107 | 108 | const char * StringPool::AddString(const char * string) { 109 | for (int i = 0; i < stringArray.GetSize(); i++) { 110 | if (String_Equal(stringArray[i], string)) return stringArray[i]; 111 | } 112 | #if _MSC_VER 113 | const char * dup = _strdup(string); 114 | #else 115 | const char * dup = strdup(string); 116 | #endif 117 | stringArray.PushBack(dup); 118 | return dup; 119 | } 120 | 121 | // @@ From mprintf.cpp 122 | static char *mprintf_valist(int size, const char *fmt, va_list args) { 123 | ASSERT(size > 0); 124 | char *res = NULL; 125 | va_list tmp; 126 | 127 | while (1) { 128 | res = new char[size]; 129 | if (!res) return NULL; 130 | 131 | va_copy(tmp, args); 132 | int len = vsnprintf(res, size, fmt, tmp); 133 | va_end(tmp); 134 | 135 | if ((len >= 0) && (size >= len + 1)) { 136 | break; 137 | } 138 | 139 | delete [] res; 140 | 141 | if (len > -1 ) { 142 | size = len + 1; 143 | } 144 | else { 145 | size *= 2; 146 | } 147 | } 148 | 149 | return res; 150 | } 151 | 152 | const char * StringPool::AddStringFormatList(const char * format, va_list args) { 153 | va_list tmp; 154 | va_copy(tmp, args); 155 | const char * string = mprintf_valist(256, format, tmp); 156 | va_end(tmp); 157 | 158 | for (int i = 0; i < stringArray.GetSize(); i++) { 159 | if (String_Equal(stringArray[i], string)) { 160 | delete [] string; 161 | return stringArray[i]; 162 | } 163 | } 164 | 165 | stringArray.PushBack(string); 166 | return string; 167 | } 168 | 169 | const char * StringPool::AddStringFormat(const char * format, ...) { 170 | va_list args; 171 | va_start(args, format); 172 | const char * string = AddStringFormatList(format, args); 173 | va_end(args); 174 | 175 | return string; 176 | } 177 | 178 | bool StringPool::GetContainsString(const char * string) const { 179 | for (int i = 0; i < stringArray.GetSize(); i++) { 180 | if (String_Equal(stringArray[i], string)) return true; 181 | } 182 | return false; 183 | } 184 | 185 | } // M4 namespace 186 | -------------------------------------------------------------------------------- /src/HLSLTokenizer.h: -------------------------------------------------------------------------------- 1 | #ifndef HLSL_TOKENIZER_H 2 | #define HLSL_TOKENIZER_H 3 | 4 | namespace M4 5 | { 6 | 7 | /** In addition to the values in this enum, all of the ASCII characters are 8 | valid tokens. */ 9 | enum HLSLToken 10 | { 11 | // Built-in types. 12 | HLSLToken_Float = 256, 13 | HLSLToken_Float2, 14 | HLSLToken_Float3, 15 | HLSLToken_Float4, 16 | HLSLToken_Float2x2, 17 | HLSLToken_Float3x3, 18 | HLSLToken_Float4x4, 19 | HLSLToken_Float4x3, 20 | HLSLToken_Float4x2, 21 | HLSLToken_Half, 22 | HLSLToken_Half2, 23 | HLSLToken_Half3, 24 | HLSLToken_Half4, 25 | HLSLToken_Half2x2, 26 | HLSLToken_Half3x3, 27 | HLSLToken_Half4x4, 28 | HLSLToken_Half4x3, 29 | HLSLToken_Half4x2, 30 | HLSLToken_Bool, 31 | HLSLToken_Bool2, 32 | HLSLToken_Bool3, 33 | HLSLToken_Bool4, 34 | HLSLToken_Int, 35 | HLSLToken_Int2, 36 | HLSLToken_Int3, 37 | HLSLToken_Int4, 38 | HLSLToken_Uint, 39 | HLSLToken_Uint2, 40 | HLSLToken_Uint3, 41 | HLSLToken_Uint4, 42 | HLSLToken_Texture, 43 | HLSLToken_Sampler, 44 | HLSLToken_Sampler2D, 45 | HLSLToken_Sampler3D, 46 | HLSLToken_SamplerCube, 47 | HLSLToken_Sampler2DShadow, 48 | HLSLToken_Sampler2DMS, 49 | HLSLToken_Sampler2DArray, 50 | 51 | // Reserved words. 52 | HLSLToken_If, 53 | HLSLToken_Else, 54 | HLSLToken_For, 55 | HLSLToken_While, 56 | HLSLToken_Break, 57 | HLSLToken_True, 58 | HLSLToken_False, 59 | HLSLToken_Void, 60 | HLSLToken_Struct, 61 | HLSLToken_CBuffer, 62 | HLSLToken_TBuffer, 63 | HLSLToken_Register, 64 | HLSLToken_Return, 65 | HLSLToken_Continue, 66 | HLSLToken_Discard, 67 | HLSLToken_Const, 68 | HLSLToken_Static, 69 | HLSLToken_Inline, 70 | 71 | // Input modifiers. 72 | HLSLToken_Uniform, 73 | HLSLToken_In, 74 | HLSLToken_Out, 75 | HLSLToken_InOut, 76 | 77 | // Effect keywords. 78 | HLSLToken_SamplerState, 79 | HLSLToken_Technique, 80 | HLSLToken_Pass, 81 | 82 | // Multi-character symbols. 83 | HLSLToken_LessEqual, 84 | HLSLToken_GreaterEqual, 85 | HLSLToken_EqualEqual, 86 | HLSLToken_NotEqual, 87 | HLSLToken_PlusPlus, 88 | HLSLToken_MinusMinus, 89 | HLSLToken_PlusEqual, 90 | HLSLToken_MinusEqual, 91 | HLSLToken_TimesEqual, 92 | HLSLToken_DivideEqual, 93 | HLSLToken_AndAnd, // && 94 | HLSLToken_BarBar, // || 95 | 96 | // Other token types. 97 | HLSLToken_FloatLiteral, 98 | HLSLToken_HalfLiteral, 99 | HLSLToken_IntLiteral, 100 | HLSLToken_Identifier, 101 | 102 | HLSLToken_EndOfStream, 103 | }; 104 | 105 | class HLSLTokenizer 106 | { 107 | 108 | public: 109 | 110 | /// Maximum string length of an identifier. 111 | static const int s_maxIdentifier = 255 + 1; 112 | 113 | /** The file name is only used for error reporting. */ 114 | HLSLTokenizer(const char* fileName, const char* buffer, size_t length); 115 | 116 | /** Advances to the next token in the stream. */ 117 | void Next(); 118 | 119 | /** Returns the current token in the stream. */ 120 | int GetToken() const; 121 | 122 | /** Returns the number of the current token. */ 123 | float GetFloat() const; 124 | int GetInt() const; 125 | 126 | /** Returns the identifier for the current token. */ 127 | const char* GetIdentifier() const; 128 | 129 | /** Returns the line number where the current token began. */ 130 | int GetLineNumber() const; 131 | 132 | /** Returns the file name where the current token began. */ 133 | const char* GetFileName() const; 134 | 135 | /** Gets a human readable text description of the current token. */ 136 | void GetTokenName(char buffer[s_maxIdentifier]) const; 137 | 138 | /** Reports an error using printf style formatting. The current line number 139 | is included. Only the first error reported will be output. */ 140 | void Error(const char* format, ...); 141 | 142 | /** Gets a human readable text description of the specified token. */ 143 | static void GetTokenName(int token, char buffer[s_maxIdentifier]); 144 | 145 | private: 146 | 147 | bool SkipWhitespace(); 148 | bool SkipComment(); 149 | bool SkipPragmaDirective(); 150 | bool ScanNumber(); 151 | bool ScanLineDirective(); 152 | 153 | private: 154 | 155 | const char* m_fileName; 156 | const char* m_buffer; 157 | const char* m_bufferEnd; 158 | int m_lineNumber; 159 | bool m_error; 160 | 161 | int m_token; 162 | float m_fValue; 163 | int m_iValue; 164 | char m_identifier[s_maxIdentifier]; 165 | char m_lineDirectiveFileName[s_maxIdentifier]; 166 | int m_tokenLineNumber; 167 | 168 | }; 169 | 170 | } 171 | 172 | #endif -------------------------------------------------------------------------------- /src/Engine.h: -------------------------------------------------------------------------------- 1 | #ifndef ENGINE_H 2 | #define ENGINE_H 3 | 4 | #if _MSC_VER 5 | #define _CRT_SECURE_NO_WARNINGS 1 6 | #endif 7 | 8 | #include // va_list, vsnprintf 9 | #include // malloc 10 | #include // for placement new 11 | 12 | #ifndef NULL 13 | #define NULL 0 14 | #endif 15 | 16 | #ifndef va_copy 17 | #define va_copy(a, b) (a) = (b) 18 | #endif 19 | 20 | // Engine/Assert.h 21 | 22 | #define ASSERT(...) 23 | 24 | namespace M4 { 25 | 26 | 27 | // Engine/Allocator.h 28 | 29 | class Allocator { 30 | public: 31 | template T * New() { 32 | return (T *)malloc(sizeof(T)); 33 | } 34 | template T * New(size_t count) { 35 | return (T *)malloc(sizeof(T) * count); 36 | } 37 | template void Delete(T * ptr) { 38 | free((void *)ptr); 39 | } 40 | template T * Realloc(T * ptr, size_t count) { 41 | return (T *)realloc(ptr, sizeof(T) * count); 42 | } 43 | }; 44 | 45 | 46 | // Engine/String.h 47 | 48 | int String_Printf(char * buffer, int size, const char * format, ...); 49 | int String_PrintfArgList(char * buffer, int size, const char * format, va_list args); 50 | int String_FormatFloat(char * buffer, int size, float value); 51 | bool String_Equal(const char * a, const char * b); 52 | bool String_EqualNoCase(const char * a, const char * b); 53 | double String_ToDouble(const char * str, char ** end); 54 | int String_ToInteger(const char * str, char ** end); 55 | 56 | 57 | // Engine/Log.h 58 | 59 | void Log_Error(const char * format, ...); 60 | void Log_ErrorArgList(const char * format, va_list args); 61 | 62 | 63 | // Engine/Array.h 64 | 65 | template 66 | void ConstructRange(T * buffer, int new_size, int old_size) { 67 | for (int i = old_size; i < new_size; i++) { 68 | new(buffer+i) T; // placement new 69 | } 70 | } 71 | 72 | template 73 | void ConstructRange(T * buffer, int new_size, int old_size, const T & val) { 74 | for (int i = old_size; i < new_size; i++) { 75 | new(buffer+i) T(val); // placement new 76 | } 77 | } 78 | 79 | template 80 | void DestroyRange(T * buffer, int new_size, int old_size) { 81 | for (int i = new_size; i < old_size; i++) { 82 | (buffer+i)->~T(); // Explicit call to the destructor 83 | } 84 | } 85 | 86 | 87 | template 88 | class Array { 89 | public: 90 | Array(Allocator * allocator) : allocator(allocator), buffer(NULL), size(0), capacity(0) {} 91 | 92 | void PushBack(const T & val) { 93 | ASSERT(&val < buffer || &val >= buffer+size); 94 | 95 | int old_size = size; 96 | int new_size = size + 1; 97 | 98 | SetSize(new_size); 99 | 100 | ConstructRange(buffer, new_size, old_size, val); 101 | } 102 | T & PushBackNew() { 103 | int old_size = size; 104 | int new_size = size + 1; 105 | 106 | SetSize(new_size); 107 | 108 | ConstructRange(buffer, new_size, old_size); 109 | 110 | return buffer[old_size]; 111 | } 112 | void Resize(int new_size) { 113 | int old_size = size; 114 | 115 | DestroyRange(buffer, new_size, old_size); 116 | 117 | SetSize(new_size); 118 | 119 | ConstructRange(buffer, new_size, old_size); 120 | } 121 | 122 | int GetSize() const { return size; } 123 | const T & operator[](int i) const { ASSERT(i < size); return buffer[i]; } 124 | T & operator[](int i) { ASSERT(i < size); return buffer[i]; } 125 | 126 | private: 127 | 128 | // Change array size. 129 | void SetSize(int new_size) { 130 | size = new_size; 131 | 132 | if (new_size > capacity) { 133 | int new_buffer_size; 134 | if (capacity == 0) { 135 | // first allocation is exact 136 | new_buffer_size = new_size; 137 | } 138 | else { 139 | // following allocations grow array by 25% 140 | new_buffer_size = new_size + (new_size >> 2); 141 | } 142 | 143 | SetCapacity(new_buffer_size); 144 | } 145 | } 146 | 147 | // Change array capacity. 148 | void SetCapacity(int new_capacity) { 149 | ASSERT(new_capacity >= size); 150 | 151 | if (new_capacity == 0) { 152 | // free the buffer. 153 | if (buffer != NULL) { 154 | allocator->Delete(buffer); 155 | buffer = NULL; 156 | } 157 | } 158 | else { 159 | // realloc the buffer 160 | buffer = allocator->Realloc(buffer, new_capacity); 161 | } 162 | 163 | capacity = new_capacity; 164 | } 165 | 166 | 167 | private: 168 | Allocator * allocator; // @@ Do we really have to keep a pointer to this? 169 | T * buffer; 170 | int size; 171 | int capacity; 172 | }; 173 | 174 | 175 | // Engine/StringPool.h 176 | 177 | // @@ Implement this with a hash table! 178 | struct StringPool { 179 | StringPool(Allocator * allocator); 180 | ~StringPool(); 181 | 182 | const char * AddString(const char * string); 183 | const char * AddStringFormat(const char * fmt, ...); 184 | const char * AddStringFormatList(const char * fmt, va_list args); 185 | bool GetContainsString(const char * string) const; 186 | 187 | Array stringArray; 188 | }; 189 | 190 | 191 | } // M4 namespace 192 | 193 | #endif // ENGINE_H 194 | -------------------------------------------------------------------------------- /src/HLSLParser.h: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // 3 | // Render/HLSLParser.h 4 | // 5 | // Created by Max McGuire (max@unknownworlds.com) 6 | // Copyright (c) 2013, Unknown Worlds Entertainment, Inc. 7 | // 8 | //============================================================================= 9 | 10 | #ifndef HLSL_PARSER_H 11 | #define HLSL_PARSER_H 12 | 13 | //#include "Engine/StringPool.h" 14 | //#include "Engine/Array.h" 15 | #include "Engine.h" 16 | 17 | #include "HLSLTokenizer.h" 18 | #include "HLSLTree.h" 19 | 20 | namespace M4 21 | { 22 | 23 | struct EffectState; 24 | 25 | class HLSLParser 26 | { 27 | 28 | public: 29 | 30 | HLSLParser(Allocator* allocator, const char* fileName, const char* buffer, size_t length); 31 | 32 | bool Parse(HLSLTree* tree); 33 | 34 | private: 35 | 36 | bool Accept(int token); 37 | bool Expect(int token); 38 | 39 | /** 40 | * Special form of Accept for accepting a word that is not actually a token 41 | * but will be treated like one. This is useful for HLSL keywords that are 42 | * only tokens in specific contexts (like in/inout in parameter lists). 43 | */ 44 | bool Accept(const char* token); 45 | bool Expect(const char* token); 46 | 47 | bool AcceptIdentifier(const char*& identifier); 48 | bool ExpectIdentifier(const char*& identifier); 49 | bool AcceptFloat(float& value); 50 | bool AcceptHalf( float& value ); 51 | bool AcceptInt(int& value); 52 | bool AcceptType(bool allowVoid, HLSLBaseType& type, const char*& typeName, int* typeFlags); 53 | bool ExpectType(bool allowVoid, HLSLBaseType& type, const char*& typeName, int* typeFlags); 54 | bool AcceptBinaryOperator(int priority, HLSLBinaryOp& binaryOp); 55 | bool AcceptUnaryOperator(bool pre, HLSLUnaryOp& unaryOp); 56 | bool AcceptAssign(HLSLBinaryOp& binaryOp); 57 | bool AcceptTypeModifier(int & typeFlags); 58 | bool AcceptInterpolationModifier(int& flags); 59 | 60 | /** 61 | * Handles a declaration like: "float2 name[5]". If allowUnsizedArray is true, it is 62 | * is acceptable for the declaration to not specify the bounds of the array (i.e. name[]). 63 | */ 64 | bool AcceptDeclaration(bool allowUnsizedArray, HLSLType& type, const char*& name); 65 | bool ExpectDeclaration(bool allowUnsizedArray, HLSLType& type, const char*& name); 66 | 67 | bool ParseTopLevel(HLSLStatement*& statement); 68 | bool ParseBlock(HLSLStatement*& firstStatement, const HLSLType& returnType); 69 | bool ParseStatementOrBlock(HLSLStatement*& firstStatement, const HLSLType& returnType); 70 | bool ParseStatement(HLSLStatement*& statement, const HLSLType& returnType); 71 | bool ParseDeclaration(HLSLDeclaration*& declaration); 72 | bool ParseFieldDeclaration(HLSLStructField*& field); 73 | //bool ParseBufferFieldDeclaration(HLSLBufferField*& field); 74 | bool ParseExpression(HLSLExpression*& expression); 75 | bool ParseBinaryExpression(int priority, HLSLExpression*& expression); 76 | bool ParseTerminalExpression(HLSLExpression*& expression, bool& needsEndParen); 77 | bool ParseExpressionList(int endToken, bool allowEmptyEnd, HLSLExpression*& firstExpression, int& numExpressions); 78 | bool ParseArgumentList(HLSLArgument*& firstArgument, int& numArguments); 79 | bool ParseDeclarationAssignment(HLSLDeclaration* declaration); 80 | bool ParsePartialConstructor(HLSLExpression*& expression, HLSLBaseType type, const char* typeName); 81 | 82 | bool ParseStateName(bool isSamplerState, bool isPipelineState, const char*& name, const EffectState *& state); 83 | bool ParseColorMask(int& mask); 84 | bool ParseStateValue(const EffectState * state, HLSLStateAssignment* stateAssignment); 85 | bool ParseStateAssignment(HLSLStateAssignment*& stateAssignment, bool isSamplerState, bool isPipelineState); 86 | bool ParseSamplerState(HLSLExpression*& expression); 87 | bool ParseTechnique(HLSLStatement*& statement); 88 | bool ParsePass(HLSLPass*& pass); 89 | bool ParsePipeline(HLSLStatement*& pipeline); 90 | bool ParseStage(HLSLStatement*& stage); 91 | 92 | bool ParseAttributeList(HLSLAttribute*& attribute); 93 | bool ParseAttributeBlock(HLSLAttribute*& attribute); 94 | 95 | bool CheckForUnexpectedEndOfStream(int endToken); 96 | 97 | const HLSLStruct* FindUserDefinedType(const char* name) const; 98 | 99 | void BeginScope(); 100 | void EndScope(); 101 | 102 | void DeclareVariable(const char* name, const HLSLType& type); 103 | 104 | /** Returned pointer is only valid until Declare or Begin/EndScope is called. */ 105 | const HLSLType* FindVariable(const char* name, bool& global) const; 106 | 107 | const HLSLFunction* FindFunction(const char* name) const; 108 | const HLSLFunction* FindFunction(const HLSLFunction* fun) const; 109 | 110 | bool GetIsFunction(const char* name) const; 111 | 112 | /** Finds the overloaded function that matches the specified call. */ 113 | const HLSLFunction* MatchFunctionCall(const HLSLFunctionCall* functionCall, const char* name); 114 | 115 | /** Gets the type of the named field on the specified object type (fieldName can also specify a swizzle. ) */ 116 | bool GetMemberType(const HLSLType& objectType, HLSLMemberAccess * memberAccess); 117 | 118 | bool CheckTypeCast(const HLSLType& srcType, const HLSLType& dstType); 119 | 120 | const char* GetFileName(); 121 | int GetLineNumber() const; 122 | 123 | private: 124 | 125 | struct Variable 126 | { 127 | const char* name; 128 | HLSLType type; 129 | }; 130 | 131 | HLSLTokenizer m_tokenizer; 132 | Array m_userTypes; 133 | Array m_variables; 134 | Array m_functions; 135 | int m_numGlobals; 136 | 137 | HLSLTree* m_tree; 138 | }; 139 | 140 | } 141 | 142 | #endif -------------------------------------------------------------------------------- /src/GLSLGenerator.h: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // 3 | // Render/GLSLGenerator.h 4 | // 5 | // Created by Max McGuire (max@unknownworlds.com) 6 | // Copyright (c) 2013, Unknown Worlds Entertainment, Inc. 7 | // 8 | //============================================================================= 9 | 10 | #ifndef GLSL_GENERATOR_H 11 | #define GLSL_GENERATOR_H 12 | 13 | #include "CodeWriter.h" 14 | #include "HLSLTree.h" 15 | 16 | namespace M4 17 | { 18 | 19 | class GLSLGenerator 20 | { 21 | 22 | public: 23 | enum Target 24 | { 25 | Target_VertexShader, 26 | Target_FragmentShader, 27 | }; 28 | 29 | enum Version 30 | { 31 | Version_110, // OpenGL 2.0 32 | Version_140, // OpenGL 3.1 33 | Version_150, // OpenGL 3.2 34 | Version_100_ES, // OpenGL ES 2.0 35 | Version_300_ES, // OpenGL ES 3.0 36 | }; 37 | 38 | enum Flags 39 | { 40 | Flag_FlipPositionOutput = 1 << 0, 41 | Flag_EmulateConstantBuffer = 1 << 1, 42 | Flag_PackMatrixRowMajor = 1 << 2, 43 | Flag_LowerMatrixMultiplication = 1 << 3, 44 | }; 45 | 46 | struct Options 47 | { 48 | unsigned int flags; 49 | const char* constantBufferPrefix; 50 | 51 | Options() 52 | { 53 | flags = 0; 54 | constantBufferPrefix = ""; 55 | } 56 | }; 57 | 58 | GLSLGenerator(); 59 | 60 | bool Generate(HLSLTree* tree, Target target, Version versiom, const char* entryName, const Options& options = Options()); 61 | const char* GetResult() const; 62 | 63 | private: 64 | 65 | enum AttributeModifier 66 | { 67 | AttributeModifier_In, 68 | AttributeModifier_Out, 69 | }; 70 | 71 | void OutputExpressionList(HLSLExpression* expression, HLSLArgument* argument = NULL); 72 | void OutputExpression(HLSLExpression* expression, const HLSLType* dstType = NULL); 73 | void OutputIdentifier(const char* name); 74 | void OutputArguments(HLSLArgument* argument); 75 | 76 | /** 77 | * If the statements are part of a function, then returnType can be used to specify the type 78 | * that a return statement is expected to produce so that correct casts will be generated. 79 | */ 80 | void OutputStatements(int indent, HLSLStatement* statement, const HLSLType* returnType = NULL); 81 | 82 | void OutputAttribute(const HLSLType& type, const char* semantic, AttributeModifier modifier); 83 | void OutputAttributes(HLSLFunction* entryFunction); 84 | void OutputEntryCaller(HLSLFunction* entryFunction); 85 | void OutputDeclaration(HLSLDeclaration* declaration); 86 | void OutputDeclarationType( const HLSLType& type ); 87 | void OutputDeclarationBody( const HLSLType& type, const char* name ); 88 | void OutputDeclaration(const HLSLType& type, const char* name); 89 | void OutputCast(const HLSLType& type); 90 | 91 | void OutputSetOutAttribute(const char* semantic, const char* resultName); 92 | 93 | void LayoutBuffer(HLSLBuffer* buffer, unsigned int& offset); 94 | void LayoutBuffer(const HLSLType& type, unsigned int& offset); 95 | void LayoutBufferElement(const HLSLType& type, unsigned int& offset); 96 | void LayoutBufferAlign(const HLSLType& type, unsigned int& offset); 97 | 98 | HLSLBuffer* GetBufferAccessExpression(HLSLExpression* expression); 99 | void OutputBufferAccessExpression(HLSLBuffer* buffer, HLSLExpression* expression, const HLSLType& type, unsigned int postOffset); 100 | unsigned int OutputBufferAccessIndex(HLSLExpression* expression, unsigned int postOffset); 101 | 102 | void OutputBuffer(int indent, HLSLBuffer* buffer); 103 | 104 | HLSLFunction* FindFunction(HLSLRoot* root, const char* name); 105 | HLSLStruct* FindStruct(HLSLRoot* root, const char* name); 106 | 107 | void Error(const char* format, ...); 108 | 109 | /** GLSL contains some reserved words that don't exist in HLSL. This function will 110 | * sanitize those names. */ 111 | const char* GetSafeIdentifierName(const char* name) const; 112 | 113 | /** Generates a name of the format "base+n" where n is an integer such that the name 114 | * isn't used in the syntax tree. */ 115 | bool ChooseUniqueName(const char* base, char* dst, int dstLength) const; 116 | 117 | const char* GetBuiltInSemantic(const char* semantic, AttributeModifier modifier, int* outputIndex = 0); 118 | const char* GetAttribQualifier(AttributeModifier modifier); 119 | 120 | private: 121 | 122 | static const int s_numReservedWords = 7; 123 | static const char* s_reservedWord[s_numReservedWords]; 124 | 125 | CodeWriter m_writer; 126 | 127 | HLSLTree* m_tree; 128 | const char* m_entryName; 129 | Target m_target; 130 | Version m_version; 131 | bool m_versionLegacy; 132 | Options m_options; 133 | 134 | bool m_outputPosition; 135 | int m_outputTargets; 136 | 137 | const char* m_outAttribPrefix; 138 | const char* m_inAttribPrefix; 139 | 140 | char m_matrixRowFunction[64]; 141 | char m_matrixCtorFunction[64]; 142 | char m_matrixMulFunction[64]; 143 | char m_clipFunction[64]; 144 | char m_tex2DlodFunction[64]; 145 | char m_tex2DbiasFunction[64]; 146 | char m_tex2DgradFunction[64]; 147 | char m_tex3DlodFunction[64]; 148 | char m_texCUBEbiasFunction[64]; 149 | char m_texCUBElodFunction[ 64 ]; 150 | char m_scalarSwizzle2Function[64]; 151 | char m_scalarSwizzle3Function[64]; 152 | char m_scalarSwizzle4Function[64]; 153 | char m_sinCosFunction[64]; 154 | char m_bvecTernary[ 64 ]; 155 | 156 | bool m_error; 157 | 158 | char m_reservedWord[s_numReservedWords][64]; 159 | 160 | }; 161 | 162 | } 163 | 164 | #endif -------------------------------------------------------------------------------- /src/HLSLTokenizer.cpp: -------------------------------------------------------------------------------- 1 | //#include "Engine/Log.h" 2 | //#include "Engine/String.h" 3 | #include "Engine.h" 4 | 5 | #include "HLSLTokenizer.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace M4 14 | { 15 | 16 | // The order here must match the order in the Token enum. 17 | static const char* _reservedWords[] = 18 | { 19 | "float", 20 | "float2", 21 | "float3", 22 | "float4", 23 | "float2x2", 24 | "float3x3", 25 | "float4x4", 26 | "float4x3", 27 | "float4x2", 28 | "half", 29 | "half2", 30 | "half3", 31 | "half4", 32 | "half2x2", 33 | "half3x3", 34 | "half4x4", 35 | "half4x3", 36 | "half4x2", 37 | "bool", 38 | "bool2", 39 | "bool3", 40 | "bool4", 41 | "int", 42 | "int2", 43 | "int3", 44 | "int4", 45 | "uint", 46 | "uint2", 47 | "uint3", 48 | "uint4", 49 | "texture", 50 | "sampler", 51 | "sampler2D", 52 | "sampler3D", 53 | "samplerCUBE", 54 | "sampler2DShadow", 55 | "sampler2DMS", 56 | "sampler2DArray", 57 | "if", 58 | "else", 59 | "for", 60 | "while", 61 | "break", 62 | "true", 63 | "false", 64 | "void", 65 | "struct", 66 | "cbuffer", 67 | "tbuffer", 68 | "register", 69 | "return", 70 | "continue", 71 | "discard", 72 | "const", 73 | "static", 74 | "inline", 75 | "uniform", 76 | "in", 77 | "out", 78 | "inout", 79 | "sampler_state", 80 | "technique", 81 | "pass", 82 | }; 83 | 84 | static bool GetIsSymbol(char c) 85 | { 86 | switch (c) 87 | { 88 | case ';': 89 | case ':': 90 | case '(': case ')': 91 | case '[': case ']': 92 | case '{': case '}': 93 | case '-': case '+': 94 | case '*': case '/': 95 | case '?': 96 | case '!': 97 | case ',': 98 | case '=': 99 | case '.': 100 | case '<': case '>': 101 | case '|': case '&': case '^': case '~': 102 | return true; 103 | } 104 | return false; 105 | } 106 | 107 | /** Returns true if the character is a valid token separator at the end of a number type token */ 108 | static bool GetIsNumberSeparator(char c) 109 | { 110 | return c == 0 || isspace(c) || GetIsSymbol(c); 111 | } 112 | 113 | HLSLTokenizer::HLSLTokenizer(const char* fileName, const char* buffer, size_t length) 114 | { 115 | m_buffer = buffer; 116 | m_bufferEnd = buffer + length; 117 | m_fileName = fileName; 118 | m_lineNumber = 1; 119 | m_tokenLineNumber = 1; 120 | m_error = false; 121 | Next(); 122 | } 123 | 124 | void HLSLTokenizer::Next() 125 | { 126 | 127 | while( SkipWhitespace() || SkipComment() || ScanLineDirective() || SkipPragmaDirective() ) 128 | { 129 | } 130 | 131 | if (m_error) 132 | { 133 | m_token = HLSLToken_EndOfStream; 134 | return; 135 | } 136 | 137 | m_tokenLineNumber = m_lineNumber; 138 | 139 | if (m_buffer >= m_bufferEnd || *m_buffer == '\0') 140 | { 141 | m_token = HLSLToken_EndOfStream; 142 | return; 143 | } 144 | 145 | const char* start = m_buffer; 146 | 147 | // +=, -=, *=, /=, ==, <=, >= 148 | if (m_buffer[0] == '+' && m_buffer[1] == '=') 149 | { 150 | m_token = HLSLToken_PlusEqual; 151 | m_buffer += 2; 152 | return; 153 | } 154 | else if (m_buffer[0] == '-' && m_buffer[1] == '=') 155 | { 156 | m_token = HLSLToken_MinusEqual; 157 | m_buffer += 2; 158 | return; 159 | } 160 | else if (m_buffer[0] == '*' && m_buffer[1] == '=') 161 | { 162 | m_token = HLSLToken_TimesEqual; 163 | m_buffer += 2; 164 | return; 165 | } 166 | else if (m_buffer[0] == '/' && m_buffer[1] == '=') 167 | { 168 | m_token = HLSLToken_DivideEqual; 169 | m_buffer += 2; 170 | return; 171 | } 172 | else if (m_buffer[0] == '=' && m_buffer[1] == '=') 173 | { 174 | m_token = HLSLToken_EqualEqual; 175 | m_buffer += 2; 176 | return; 177 | } 178 | else if (m_buffer[0] == '!' && m_buffer[1] == '=') 179 | { 180 | m_token = HLSLToken_NotEqual; 181 | m_buffer += 2; 182 | return; 183 | } 184 | else if (m_buffer[0] == '<' && m_buffer[1] == '=') 185 | { 186 | m_token = HLSLToken_LessEqual; 187 | m_buffer += 2; 188 | return; 189 | } 190 | else if (m_buffer[0] == '>' && m_buffer[1] == '=') 191 | { 192 | m_token = HLSLToken_GreaterEqual; 193 | m_buffer += 2; 194 | return; 195 | } 196 | else if (m_buffer[0] == '&' && m_buffer[1] == '&') 197 | { 198 | m_token = HLSLToken_AndAnd; 199 | m_buffer += 2; 200 | return; 201 | } 202 | else if (m_buffer[0] == '|' && m_buffer[1] == '|') 203 | { 204 | m_token = HLSLToken_BarBar; 205 | m_buffer += 2; 206 | return; 207 | } 208 | 209 | // ++, -- 210 | if ((m_buffer[0] == '-' || m_buffer[0] == '+') && (m_buffer[1] == m_buffer[0])) 211 | { 212 | m_token = (m_buffer[0] == '+') ? HLSLToken_PlusPlus : HLSLToken_MinusMinus; 213 | m_buffer += 2; 214 | return; 215 | } 216 | 217 | // Check for the start of a number. 218 | if (ScanNumber()) 219 | { 220 | return; 221 | } 222 | 223 | if (GetIsSymbol(m_buffer[0])) 224 | { 225 | m_token = static_cast(m_buffer[0]); 226 | ++m_buffer; 227 | return; 228 | } 229 | 230 | // Must be an identifier or a reserved word. 231 | 232 | while (m_buffer < m_bufferEnd && m_buffer[0] != 0 && !GetIsSymbol(m_buffer[0]) && !isspace(m_buffer[0])) 233 | { 234 | ++m_buffer; 235 | } 236 | 237 | size_t length = m_buffer - start; 238 | memcpy(m_identifier, start, length); 239 | m_identifier[length] = 0; 240 | 241 | const int numReservedWords = sizeof(_reservedWords) / sizeof(const char*); 242 | for (int i = 0; i < numReservedWords; ++i) 243 | { 244 | if (strcmp(_reservedWords[i], m_identifier) == 0) 245 | { 246 | m_token = 256 + i; 247 | return; 248 | } 249 | } 250 | 251 | m_token = HLSLToken_Identifier; 252 | 253 | } 254 | 255 | bool HLSLTokenizer::SkipWhitespace() 256 | { 257 | bool result = false; 258 | while (m_buffer < m_bufferEnd && isspace(m_buffer[0])) 259 | { 260 | result = true; 261 | if (m_buffer[0] == '\n') 262 | { 263 | ++m_lineNumber; 264 | } 265 | ++m_buffer; 266 | } 267 | return result; 268 | } 269 | 270 | bool HLSLTokenizer::SkipComment() 271 | { 272 | bool result = false; 273 | if (m_buffer[0] == '/') 274 | { 275 | if (m_buffer[1] == '/') 276 | { 277 | // Single line comment. 278 | result = true; 279 | m_buffer += 2; 280 | while (m_buffer < m_bufferEnd) 281 | { 282 | if (*(m_buffer++) == '\n') 283 | { 284 | ++m_lineNumber; 285 | break; 286 | } 287 | } 288 | } 289 | else if (m_buffer[1] == '*') 290 | { 291 | // Multi-line comment. 292 | result = true; 293 | m_buffer += 2; 294 | while (m_buffer < m_bufferEnd) 295 | { 296 | if (m_buffer[0] == '\n') 297 | { 298 | ++m_lineNumber; 299 | } 300 | if (m_buffer[0] == '*' && m_buffer[1] == '/') 301 | { 302 | break; 303 | } 304 | ++m_buffer; 305 | } 306 | if (m_buffer < m_bufferEnd) 307 | { 308 | m_buffer += 2; 309 | } 310 | } 311 | } 312 | return result; 313 | } 314 | 315 | bool HLSLTokenizer::SkipPragmaDirective() 316 | { 317 | bool result = false; 318 | if( m_bufferEnd - m_buffer > 7 && *m_buffer == '#' ) 319 | { 320 | const char* ptr = m_buffer + 1; 321 | while( isspace( *ptr ) ) 322 | ptr++; 323 | 324 | if( strncmp( ptr, "pragma", 6 ) == 0 && isspace( ptr[ 6 ] ) ) 325 | { 326 | m_buffer = ptr + 6; 327 | result = true; 328 | while( m_buffer < m_bufferEnd ) 329 | { 330 | if( *( m_buffer++ ) == '\n' ) 331 | { 332 | ++m_lineNumber; 333 | break; 334 | } 335 | } 336 | } 337 | } 338 | return result; 339 | } 340 | 341 | bool HLSLTokenizer::ScanNumber() 342 | { 343 | 344 | // Don't treat the + or - as part of the number. 345 | if (m_buffer[0] == '+' || m_buffer[0] == '-') 346 | { 347 | return false; 348 | } 349 | 350 | // Parse hex literals. 351 | if (m_bufferEnd - m_buffer > 2 && m_buffer[0] == '0' && m_buffer[1] == 'x') 352 | { 353 | char* hEnd = NULL; 354 | int iValue = strtol(m_buffer+2, &hEnd, 16); 355 | if (GetIsNumberSeparator(hEnd[0])) 356 | { 357 | m_buffer = hEnd; 358 | m_token = HLSLToken_IntLiteral; 359 | m_iValue = iValue; 360 | return true; 361 | } 362 | } 363 | 364 | char* fEnd = NULL; 365 | double fValue = String_ToDouble(m_buffer, &fEnd); 366 | 367 | if (fEnd == m_buffer) 368 | { 369 | return false; 370 | } 371 | 372 | char* iEnd = NULL; 373 | int iValue = String_ToInteger(m_buffer, &iEnd); 374 | 375 | // If the character after the number is an f then the f is treated as part 376 | // of the number (to handle 1.0f syntax). 377 | if( ( fEnd[ 0 ] == 'f' || fEnd[ 0 ] == 'h' ) && fEnd < m_bufferEnd ) 378 | { 379 | ++fEnd; 380 | } 381 | 382 | if( fEnd > iEnd && GetIsNumberSeparator( fEnd[ 0 ] ) ) 383 | { 384 | m_buffer = fEnd; 385 | m_token = fEnd[ 0 ] == 'f' ? HLSLToken_FloatLiteral : HLSLToken_HalfLiteral; 386 | m_fValue = static_cast(fValue); 387 | return true; 388 | } 389 | else if (iEnd > m_buffer && GetIsNumberSeparator(iEnd[0])) 390 | { 391 | m_buffer = iEnd; 392 | m_token = HLSLToken_IntLiteral; 393 | m_iValue = iValue; 394 | return true; 395 | } 396 | 397 | return false; 398 | } 399 | 400 | bool HLSLTokenizer::ScanLineDirective() 401 | { 402 | 403 | if (m_bufferEnd - m_buffer > 5 && strncmp(m_buffer, "#line", 5) == 0 && isspace(m_buffer[5])) 404 | { 405 | 406 | m_buffer += 5; 407 | 408 | while (m_buffer < m_bufferEnd && isspace(m_buffer[0])) 409 | { 410 | if (m_buffer[0] == '\n') 411 | { 412 | Error("Syntax error: expected line number after #line"); 413 | return false; 414 | } 415 | ++m_buffer; 416 | } 417 | 418 | char* iEnd = NULL; 419 | int lineNumber = String_ToInteger(m_buffer, &iEnd); 420 | 421 | if (!isspace(*iEnd)) 422 | { 423 | Error("Syntax error: expected line number after #line"); 424 | return false; 425 | } 426 | 427 | m_buffer = iEnd; 428 | while (m_buffer < m_bufferEnd && isspace(m_buffer[0])) 429 | { 430 | char c = m_buffer[0]; 431 | ++m_buffer; 432 | if (c == '\n') 433 | { 434 | m_lineNumber = lineNumber; 435 | return true; 436 | } 437 | } 438 | 439 | if (m_buffer >= m_bufferEnd) 440 | { 441 | m_lineNumber = lineNumber; 442 | return true; 443 | } 444 | 445 | if (m_buffer[0] != '"') 446 | { 447 | Error("Syntax error: expected '\"' after line number near #line"); 448 | return false; 449 | } 450 | 451 | ++m_buffer; 452 | 453 | int i = 0; 454 | while (i + 1 < s_maxIdentifier && m_buffer < m_bufferEnd && m_buffer[0] != '"') 455 | { 456 | if (m_buffer[0] == '\n') 457 | { 458 | Error("Syntax error: expected '\"' before end of line near #line"); 459 | return false; 460 | } 461 | 462 | m_lineDirectiveFileName[i] = *m_buffer; 463 | ++m_buffer; 464 | ++i; 465 | } 466 | 467 | m_lineDirectiveFileName[i] = 0; 468 | 469 | if (m_buffer >= m_bufferEnd) 470 | { 471 | Error("Syntax error: expected '\"' before end of file near #line"); 472 | return false; 473 | } 474 | 475 | if (i + 1 >= s_maxIdentifier) 476 | { 477 | Error("Syntax error: file name too long near #line"); 478 | return false; 479 | } 480 | 481 | // Skip the closing quote 482 | ++m_buffer; 483 | 484 | while (m_buffer < m_bufferEnd && m_buffer[0] != '\n') 485 | { 486 | if (!isspace(m_buffer[0])) 487 | { 488 | Error("Syntax error: unexpected input after file name near #line"); 489 | return false; 490 | } 491 | ++m_buffer; 492 | } 493 | 494 | // Skip new line 495 | ++m_buffer; 496 | 497 | m_lineNumber = lineNumber; 498 | m_fileName = m_lineDirectiveFileName; 499 | 500 | return true; 501 | 502 | } 503 | 504 | return false; 505 | 506 | } 507 | 508 | int HLSLTokenizer::GetToken() const 509 | { 510 | return m_token; 511 | } 512 | 513 | float HLSLTokenizer::GetFloat() const 514 | { 515 | return m_fValue; 516 | } 517 | 518 | int HLSLTokenizer::GetInt() const 519 | { 520 | return m_iValue; 521 | } 522 | 523 | const char* HLSLTokenizer::GetIdentifier() const 524 | { 525 | return m_identifier; 526 | } 527 | 528 | int HLSLTokenizer::GetLineNumber() const 529 | { 530 | return m_tokenLineNumber; 531 | } 532 | 533 | const char* HLSLTokenizer::GetFileName() const 534 | { 535 | return m_fileName; 536 | } 537 | 538 | void HLSLTokenizer::Error(const char* format, ...) 539 | { 540 | // It's not always convenient to stop executing when an error occurs, 541 | // so just track once we've hit an error and stop reporting them until 542 | // we successfully bail out of execution. 543 | if (m_error) 544 | { 545 | return; 546 | } 547 | m_error = true; 548 | 549 | 550 | char buffer[1024]; 551 | va_list args; 552 | va_start(args, format); 553 | int result = vsnprintf(buffer, sizeof(buffer) - 1, format, args); 554 | va_end(args); 555 | 556 | Log_Error("%s(%d) : %s\n", m_fileName, m_lineNumber, buffer); 557 | } 558 | 559 | void HLSLTokenizer::GetTokenName(char buffer[s_maxIdentifier]) const 560 | { 561 | if (m_token == HLSLToken_FloatLiteral || m_token == HLSLToken_HalfLiteral ) 562 | { 563 | sprintf(buffer, "%f", m_fValue); 564 | } 565 | else if (m_token == HLSLToken_IntLiteral) 566 | { 567 | sprintf(buffer, "%d", m_iValue); 568 | } 569 | else if (m_token == HLSLToken_Identifier) 570 | { 571 | strcpy(buffer, m_identifier); 572 | } 573 | else 574 | { 575 | GetTokenName(m_token, buffer); 576 | } 577 | } 578 | 579 | void HLSLTokenizer::GetTokenName(int token, char buffer[s_maxIdentifier]) 580 | { 581 | if (token < 256) 582 | { 583 | buffer[0] = (char)token; 584 | buffer[1] = 0; 585 | } 586 | else if (token < HLSLToken_LessEqual) 587 | { 588 | strcpy(buffer, _reservedWords[token - 256]); 589 | } 590 | else 591 | { 592 | switch (token) 593 | { 594 | case HLSLToken_PlusPlus: 595 | strcpy(buffer, "++"); 596 | break; 597 | case HLSLToken_MinusMinus: 598 | strcpy(buffer, "--"); 599 | break; 600 | case HLSLToken_PlusEqual: 601 | strcpy(buffer, "+="); 602 | break; 603 | case HLSLToken_MinusEqual: 604 | strcpy(buffer, "-="); 605 | break; 606 | case HLSLToken_TimesEqual: 607 | strcpy(buffer, "*="); 608 | break; 609 | case HLSLToken_DivideEqual: 610 | strcpy(buffer, "/="); 611 | break; 612 | case HLSLToken_HalfLiteral: 613 | strcpy( buffer, "half" ); 614 | break; 615 | case HLSLToken_FloatLiteral: 616 | strcpy(buffer, "float"); 617 | break; 618 | case HLSLToken_IntLiteral: 619 | strcpy(buffer, "int"); 620 | break; 621 | case HLSLToken_Identifier: 622 | strcpy(buffer, "identifier"); 623 | break; 624 | case HLSLToken_EndOfStream: 625 | strcpy(buffer, ""); 626 | break; 627 | default: 628 | strcpy(buffer, "unknown"); 629 | break; 630 | } 631 | } 632 | 633 | } 634 | 635 | } 636 | -------------------------------------------------------------------------------- /src/HLSLTree.h: -------------------------------------------------------------------------------- 1 | #ifndef HLSL_TREE_H 2 | #define HLSL_TREE_H 3 | 4 | //#include "Engine/StringPool.h" 5 | #include "Engine.h" 6 | 7 | #include 8 | 9 | namespace M4 10 | { 11 | 12 | enum HLSLNodeType 13 | { 14 | HLSLNodeType_Root, 15 | HLSLNodeType_Declaration, 16 | HLSLNodeType_Struct, 17 | HLSLNodeType_StructField, 18 | HLSLNodeType_Buffer, 19 | HLSLNodeType_BufferField, 20 | HLSLNodeType_Function, 21 | HLSLNodeType_Argument, 22 | HLSLNodeType_ExpressionStatement, 23 | HLSLNodeType_Expression, 24 | HLSLNodeType_ReturnStatement, 25 | HLSLNodeType_DiscardStatement, 26 | HLSLNodeType_BreakStatement, 27 | HLSLNodeType_ContinueStatement, 28 | HLSLNodeType_IfStatement, 29 | HLSLNodeType_ForStatement, 30 | HLSLNodeType_BlockStatement, 31 | HLSLNodeType_UnaryExpression, 32 | HLSLNodeType_BinaryExpression, 33 | HLSLNodeType_ConditionalExpression, 34 | HLSLNodeType_CastingExpression, 35 | HLSLNodeType_LiteralExpression, 36 | HLSLNodeType_IdentifierExpression, 37 | HLSLNodeType_ConstructorExpression, 38 | HLSLNodeType_MemberAccess, 39 | HLSLNodeType_ArrayAccess, 40 | HLSLNodeType_FunctionCall, 41 | HLSLNodeType_StateAssignment, 42 | HLSLNodeType_SamplerState, 43 | HLSLNodeType_Pass, 44 | HLSLNodeType_Technique, 45 | HLSLNodeType_Attribute, 46 | HLSLNodeType_Pipeline, 47 | HLSLNodeType_Stage, 48 | }; 49 | 50 | enum HLSLBaseType 51 | { 52 | HLSLBaseType_Unknown, 53 | HLSLBaseType_Void, 54 | HLSLBaseType_Float, 55 | HLSLBaseType_FirstNumeric = HLSLBaseType_Float, 56 | HLSLBaseType_Float2, 57 | HLSLBaseType_Float3, 58 | HLSLBaseType_Float4, 59 | HLSLBaseType_Float2x2, 60 | HLSLBaseType_Float3x3, 61 | HLSLBaseType_Float4x4, 62 | HLSLBaseType_Float4x3, 63 | HLSLBaseType_Float4x2, 64 | HLSLBaseType_Half, 65 | HLSLBaseType_Half2, 66 | HLSLBaseType_Half3, 67 | HLSLBaseType_Half4, 68 | HLSLBaseType_Half2x2, 69 | HLSLBaseType_Half3x3, 70 | HLSLBaseType_Half4x4, 71 | HLSLBaseType_Half4x3, 72 | HLSLBaseType_Half4x2, 73 | HLSLBaseType_Bool, 74 | HLSLBaseType_FirstInteger = HLSLBaseType_Bool, 75 | HLSLBaseType_Bool2, 76 | HLSLBaseType_Bool3, 77 | HLSLBaseType_Bool4, 78 | HLSLBaseType_Int, 79 | HLSLBaseType_Int2, 80 | HLSLBaseType_Int3, 81 | HLSLBaseType_Int4, 82 | HLSLBaseType_Uint, 83 | HLSLBaseType_Uint2, 84 | HLSLBaseType_Uint3, 85 | HLSLBaseType_Uint4, 86 | HLSLBaseType_LastInteger = HLSLBaseType_Uint4, 87 | HLSLBaseType_LastNumeric = HLSLBaseType_Uint4, 88 | HLSLBaseType_Texture, 89 | HLSLBaseType_Sampler, // @@ use type inference to determine sampler type. 90 | HLSLBaseType_Sampler2D, 91 | HLSLBaseType_Sampler3D, 92 | HLSLBaseType_SamplerCube, 93 | HLSLBaseType_Sampler2DShadow, 94 | HLSLBaseType_Sampler2DMS, 95 | HLSLBaseType_Sampler2DArray, 96 | HLSLBaseType_UserDefined, // struct 97 | 98 | HLSLBaseType_Count, 99 | HLSLBaseType_NumericCount = HLSLBaseType_LastNumeric - HLSLBaseType_FirstNumeric + 1 100 | }; 101 | 102 | inline bool IsSamplerType(HLSLBaseType baseType) 103 | { 104 | return baseType == HLSLBaseType_Sampler || 105 | baseType == HLSLBaseType_Sampler2D || 106 | baseType == HLSLBaseType_Sampler3D || 107 | baseType == HLSLBaseType_SamplerCube || 108 | baseType == HLSLBaseType_Sampler2DShadow || 109 | baseType == HLSLBaseType_Sampler2DMS || 110 | baseType == HLSLBaseType_Sampler2DArray; 111 | } 112 | 113 | inline bool IsMatrixType(HLSLBaseType baseType) 114 | { 115 | return baseType == HLSLBaseType_Float3x3 || baseType == HLSLBaseType_Float4x4 || baseType == HLSLBaseType_Float4x3 || baseType == HLSLBaseType_Float4x2 || 116 | baseType == HLSLBaseType_Half3x3 || baseType == HLSLBaseType_Half4x4 || baseType == HLSLBaseType_Half4x3 || baseType == HLSLBaseType_Half4x2; 117 | } 118 | 119 | inline bool isScalarType( HLSLBaseType baseType ) 120 | { 121 | return baseType == HLSLBaseType_Float || 122 | baseType == HLSLBaseType_Half || 123 | baseType == HLSLBaseType_Bool || 124 | baseType == HLSLBaseType_Int || 125 | baseType == HLSLBaseType_Uint; 126 | } 127 | 128 | inline bool isVectorType( HLSLBaseType baseType ) 129 | { 130 | return baseType == HLSLBaseType_Float2 || 131 | baseType == HLSLBaseType_Float3 || 132 | baseType == HLSLBaseType_Float4 || 133 | baseType == HLSLBaseType_Half2 || 134 | baseType == HLSLBaseType_Half3 || 135 | baseType == HLSLBaseType_Half4 || 136 | baseType == HLSLBaseType_Bool2 || 137 | baseType == HLSLBaseType_Bool3 || 138 | baseType == HLSLBaseType_Bool4 || 139 | baseType == HLSLBaseType_Int2 || 140 | baseType == HLSLBaseType_Int3 || 141 | baseType == HLSLBaseType_Int4 || 142 | baseType == HLSLBaseType_Uint2 || 143 | baseType == HLSLBaseType_Uint3 || 144 | baseType == HLSLBaseType_Uint4; 145 | } 146 | 147 | 148 | enum HLSLBinaryOp 149 | { 150 | HLSLBinaryOp_And, 151 | HLSLBinaryOp_Or, 152 | HLSLBinaryOp_Add, 153 | HLSLBinaryOp_Sub, 154 | HLSLBinaryOp_Mul, 155 | HLSLBinaryOp_Div, 156 | HLSLBinaryOp_Less, 157 | HLSLBinaryOp_Greater, 158 | HLSLBinaryOp_LessEqual, 159 | HLSLBinaryOp_GreaterEqual, 160 | HLSLBinaryOp_Equal, 161 | HLSLBinaryOp_NotEqual, 162 | HLSLBinaryOp_BitAnd, 163 | HLSLBinaryOp_BitOr, 164 | HLSLBinaryOp_BitXor, 165 | HLSLBinaryOp_Assign, 166 | HLSLBinaryOp_AddAssign, 167 | HLSLBinaryOp_SubAssign, 168 | HLSLBinaryOp_MulAssign, 169 | HLSLBinaryOp_DivAssign, 170 | }; 171 | 172 | inline bool isCompareOp( HLSLBinaryOp op ) 173 | { 174 | return op == HLSLBinaryOp_Less || 175 | op == HLSLBinaryOp_Greater || 176 | op == HLSLBinaryOp_LessEqual || 177 | op == HLSLBinaryOp_GreaterEqual || 178 | op == HLSLBinaryOp_Equal || 179 | op == HLSLBinaryOp_NotEqual; 180 | } 181 | 182 | enum HLSLUnaryOp 183 | { 184 | HLSLUnaryOp_Negative, // -x 185 | HLSLUnaryOp_Positive, // +x 186 | HLSLUnaryOp_Not, // !x 187 | HLSLUnaryOp_PreIncrement, // ++x 188 | HLSLUnaryOp_PreDecrement, // --x 189 | HLSLUnaryOp_PostIncrement, // x++ 190 | HLSLUnaryOp_PostDecrement, // x++ 191 | HLSLUnaryOp_BitNot, // ~x 192 | }; 193 | 194 | enum HLSLArgumentModifier 195 | { 196 | HLSLArgumentModifier_None, 197 | HLSLArgumentModifier_In, 198 | HLSLArgumentModifier_Out, 199 | HLSLArgumentModifier_Inout, 200 | HLSLArgumentModifier_Uniform, 201 | HLSLArgumentModifier_Const, 202 | }; 203 | 204 | enum HLSLTypeFlags 205 | { 206 | HLSLTypeFlag_None = 0, 207 | HLSLTypeFlag_Const = 0x01, 208 | HLSLTypeFlag_Static = 0x02, 209 | //HLSLTypeFlag_Uniform = 0x04, 210 | //HLSLTypeFlag_Extern = 0x10, 211 | //HLSLTypeFlag_Volatile = 0x20, 212 | //HLSLTypeFlag_Shared = 0x40, 213 | //HLSLTypeFlag_Precise = 0x80, 214 | 215 | HLSLTypeFlag_Input = 0x100, 216 | HLSLTypeFlag_Output = 0x200, 217 | 218 | // Interpolation modifiers. 219 | HLSLTypeFlag_Linear = 0x10000, 220 | HLSLTypeFlag_Centroid = 0x20000, 221 | HLSLTypeFlag_NoInterpolation = 0x40000, 222 | HLSLTypeFlag_NoPerspective = 0x80000, 223 | HLSLTypeFlag_Sample = 0x100000, 224 | 225 | // Misc. 226 | //HLSLTypeFlag_Swizzle_BGRA = 0x200000, 227 | }; 228 | 229 | enum HLSLAttributeType 230 | { 231 | HLSLAttributeType_Unknown, 232 | HLSLAttributeType_Unroll, 233 | HLSLAttributeType_Branch, 234 | HLSLAttributeType_Flatten, 235 | }; 236 | 237 | enum HLSLAddressSpace 238 | { 239 | HLSLAddressSpace_Undefined, 240 | HLSLAddressSpace_Constant, 241 | HLSLAddressSpace_Device, 242 | HLSLAddressSpace_Thread, 243 | HLSLAddressSpace_Shared, 244 | }; 245 | 246 | 247 | struct HLSLNode; 248 | struct HLSLRoot; 249 | struct HLSLStatement; 250 | struct HLSLAttribute; 251 | struct HLSLDeclaration; 252 | struct HLSLStruct; 253 | struct HLSLStructField; 254 | struct HLSLBuffer; 255 | struct HLSLFunction; 256 | struct HLSLArgument; 257 | struct HLSLExpressionStatement; 258 | struct HLSLExpression; 259 | struct HLSLBinaryExpression; 260 | struct HLSLLiteralExpression; 261 | struct HLSLIdentifierExpression; 262 | struct HLSLConstructorExpression; 263 | struct HLSLFunctionCall; 264 | struct HLSLArrayAccess; 265 | struct HLSLAttribute; 266 | 267 | struct HLSLType 268 | { 269 | explicit HLSLType(HLSLBaseType _baseType = HLSLBaseType_Unknown) 270 | { 271 | baseType = _baseType; 272 | typeName = NULL; 273 | array = false; 274 | arraySize = NULL; 275 | flags = 0; 276 | addressSpace = HLSLAddressSpace_Undefined; 277 | } 278 | HLSLBaseType baseType; 279 | const char* typeName; // For user defined types. 280 | bool array; 281 | HLSLExpression* arraySize; 282 | int flags; 283 | HLSLAddressSpace addressSpace; 284 | }; 285 | 286 | inline bool IsSamplerType(const HLSLType & type) 287 | { 288 | return IsSamplerType(type.baseType); 289 | } 290 | 291 | inline bool isScalarType(const HLSLType & type) 292 | { 293 | return isScalarType(type.baseType); 294 | } 295 | 296 | inline bool isVectorType(const HLSLType & type) 297 | { 298 | return isVectorType(type.baseType); 299 | } 300 | 301 | 302 | /** Base class for all nodes in the HLSL AST */ 303 | struct HLSLNode 304 | { 305 | HLSLNodeType nodeType; 306 | const char* fileName; 307 | int line; 308 | }; 309 | 310 | struct HLSLRoot : public HLSLNode 311 | { 312 | static const HLSLNodeType s_type = HLSLNodeType_Root; 313 | HLSLRoot() { statement = NULL; } 314 | HLSLStatement* statement; // First statement. 315 | }; 316 | 317 | struct HLSLStatement : public HLSLNode 318 | { 319 | HLSLStatement() 320 | { 321 | nextStatement = NULL; 322 | attributes = NULL; 323 | hidden = false; 324 | } 325 | HLSLStatement* nextStatement; // Next statement in the block. 326 | HLSLAttribute* attributes; 327 | mutable bool hidden; 328 | }; 329 | 330 | struct HLSLAttribute : public HLSLNode 331 | { 332 | static const HLSLNodeType s_type = HLSLNodeType_Attribute; 333 | HLSLAttribute() 334 | { 335 | attributeType = HLSLAttributeType_Unknown; 336 | argument = NULL; 337 | nextAttribute = NULL; 338 | } 339 | HLSLAttributeType attributeType; 340 | HLSLExpression* argument; 341 | HLSLAttribute* nextAttribute; 342 | }; 343 | 344 | struct HLSLDeclaration : public HLSLStatement 345 | { 346 | static const HLSLNodeType s_type = HLSLNodeType_Declaration; 347 | HLSLDeclaration() 348 | { 349 | name = NULL; 350 | registerName = NULL; 351 | semantic = NULL; 352 | nextDeclaration = NULL; 353 | assignment = NULL; 354 | buffer = NULL; 355 | } 356 | const char* name; 357 | HLSLType type; 358 | const char* registerName; // @@ Store register index? 359 | const char* semantic; 360 | HLSLDeclaration* nextDeclaration; // If multiple variables declared on a line. 361 | HLSLExpression* assignment; 362 | HLSLBuffer* buffer; 363 | }; 364 | 365 | struct HLSLStruct : public HLSLStatement 366 | { 367 | static const HLSLNodeType s_type = HLSLNodeType_Struct; 368 | HLSLStruct() 369 | { 370 | name = NULL; 371 | field = NULL; 372 | } 373 | const char* name; 374 | HLSLStructField* field; // First field in the structure. 375 | }; 376 | 377 | struct HLSLStructField : public HLSLNode 378 | { 379 | static const HLSLNodeType s_type = HLSLNodeType_StructField; 380 | HLSLStructField() 381 | { 382 | name = NULL; 383 | semantic = NULL; 384 | sv_semantic = NULL; 385 | nextField = NULL; 386 | hidden = false; 387 | } 388 | const char* name; 389 | HLSLType type; 390 | const char* semantic; 391 | const char* sv_semantic; 392 | HLSLStructField* nextField; // Next field in the structure. 393 | bool hidden; 394 | }; 395 | 396 | /** A cbuffer or tbuffer declaration. */ 397 | struct HLSLBuffer : public HLSLStatement 398 | { 399 | static const HLSLNodeType s_type = HLSLNodeType_Buffer; 400 | HLSLBuffer() 401 | { 402 | name = NULL; 403 | registerName = NULL; 404 | field = NULL; 405 | } 406 | const char* name; 407 | const char* registerName; 408 | HLSLDeclaration* field; 409 | }; 410 | 411 | 412 | /** Function declaration */ 413 | struct HLSLFunction : public HLSLStatement 414 | { 415 | static const HLSLNodeType s_type = HLSLNodeType_Function; 416 | HLSLFunction() 417 | { 418 | name = NULL; 419 | semantic = NULL; 420 | sv_semantic = NULL; 421 | statement = NULL; 422 | argument = NULL; 423 | numArguments = 0; 424 | forward = NULL; 425 | } 426 | const char* name; 427 | HLSLType returnType; 428 | const char* semantic; 429 | const char* sv_semantic; 430 | int numArguments; 431 | HLSLArgument* argument; 432 | HLSLStatement* statement; 433 | HLSLFunction* forward; // Which HLSLFunction this one forward-declares 434 | }; 435 | 436 | /** Declaration of an argument to a function. */ 437 | struct HLSLArgument : public HLSLNode 438 | { 439 | static const HLSLNodeType s_type = HLSLNodeType_Argument; 440 | HLSLArgument() 441 | { 442 | name = NULL; 443 | modifier = HLSLArgumentModifier_None; 444 | semantic = NULL; 445 | sv_semantic = NULL; 446 | defaultValue = NULL; 447 | nextArgument = NULL; 448 | hidden = false; 449 | } 450 | const char* name; 451 | HLSLArgumentModifier modifier; 452 | HLSLType type; 453 | const char* semantic; 454 | const char* sv_semantic; 455 | HLSLExpression* defaultValue; 456 | HLSLArgument* nextArgument; 457 | bool hidden; 458 | }; 459 | 460 | /** A expression which forms a complete statement. */ 461 | struct HLSLExpressionStatement : public HLSLStatement 462 | { 463 | static const HLSLNodeType s_type = HLSLNodeType_ExpressionStatement; 464 | HLSLExpressionStatement() 465 | { 466 | expression = NULL; 467 | } 468 | HLSLExpression* expression; 469 | }; 470 | 471 | struct HLSLReturnStatement : public HLSLStatement 472 | { 473 | static const HLSLNodeType s_type = HLSLNodeType_ReturnStatement; 474 | HLSLReturnStatement() 475 | { 476 | expression = NULL; 477 | } 478 | HLSLExpression* expression; 479 | }; 480 | 481 | struct HLSLDiscardStatement : public HLSLStatement 482 | { 483 | static const HLSLNodeType s_type = HLSLNodeType_DiscardStatement; 484 | }; 485 | 486 | struct HLSLBreakStatement : public HLSLStatement 487 | { 488 | static const HLSLNodeType s_type = HLSLNodeType_BreakStatement; 489 | }; 490 | 491 | struct HLSLContinueStatement : public HLSLStatement 492 | { 493 | static const HLSLNodeType s_type = HLSLNodeType_ContinueStatement; 494 | }; 495 | 496 | struct HLSLIfStatement : public HLSLStatement 497 | { 498 | static const HLSLNodeType s_type = HLSLNodeType_IfStatement; 499 | HLSLIfStatement() 500 | { 501 | condition = NULL; 502 | statement = NULL; 503 | elseStatement = NULL; 504 | } 505 | HLSLExpression* condition; 506 | HLSLStatement* statement; 507 | HLSLStatement* elseStatement; 508 | }; 509 | 510 | struct HLSLForStatement : public HLSLStatement 511 | { 512 | static const HLSLNodeType s_type = HLSLNodeType_ForStatement; 513 | HLSLForStatement() 514 | { 515 | initialization = NULL; 516 | condition = NULL; 517 | increment = NULL; 518 | statement = NULL; 519 | } 520 | HLSLDeclaration* initialization; 521 | HLSLExpression* condition; 522 | HLSLExpression* increment; 523 | HLSLStatement* statement; 524 | }; 525 | 526 | struct HLSLBlockStatement : public HLSLStatement 527 | { 528 | static const HLSLNodeType s_type = HLSLNodeType_BlockStatement; 529 | HLSLBlockStatement() 530 | { 531 | statement = NULL; 532 | } 533 | HLSLStatement* statement; 534 | }; 535 | 536 | 537 | /** Base type for all types of expressions. */ 538 | struct HLSLExpression : public HLSLNode 539 | { 540 | static const HLSLNodeType s_type = HLSLNodeType_Expression; 541 | HLSLExpression() 542 | { 543 | nextExpression = NULL; 544 | } 545 | HLSLType expressionType; 546 | HLSLExpression* nextExpression; // Used when the expression is part of a list, like in a function call. 547 | }; 548 | 549 | struct HLSLUnaryExpression : public HLSLExpression 550 | { 551 | static const HLSLNodeType s_type = HLSLNodeType_UnaryExpression; 552 | HLSLUnaryExpression() 553 | { 554 | expression = NULL; 555 | } 556 | HLSLUnaryOp unaryOp; 557 | HLSLExpression* expression; 558 | }; 559 | 560 | struct HLSLBinaryExpression : public HLSLExpression 561 | { 562 | static const HLSLNodeType s_type = HLSLNodeType_BinaryExpression; 563 | HLSLBinaryExpression() 564 | { 565 | expression1 = NULL; 566 | expression2 = NULL; 567 | } 568 | HLSLBinaryOp binaryOp; 569 | HLSLExpression* expression1; 570 | HLSLExpression* expression2; 571 | }; 572 | 573 | /** ? : construct */ 574 | struct HLSLConditionalExpression : public HLSLExpression 575 | { 576 | static const HLSLNodeType s_type = HLSLNodeType_ConditionalExpression; 577 | HLSLConditionalExpression() 578 | { 579 | condition = NULL; 580 | trueExpression = NULL; 581 | falseExpression = NULL; 582 | } 583 | HLSLExpression* condition; 584 | HLSLExpression* trueExpression; 585 | HLSLExpression* falseExpression; 586 | }; 587 | 588 | struct HLSLCastingExpression : public HLSLExpression 589 | { 590 | static const HLSLNodeType s_type = HLSLNodeType_CastingExpression; 591 | HLSLCastingExpression() 592 | { 593 | expression = NULL; 594 | } 595 | HLSLType type; 596 | HLSLExpression* expression; 597 | }; 598 | 599 | /** Float, integer, boolean, etc. literal constant. */ 600 | struct HLSLLiteralExpression : public HLSLExpression 601 | { 602 | static const HLSLNodeType s_type = HLSLNodeType_LiteralExpression; 603 | HLSLBaseType type; // Note, not all types can be literals. 604 | union 605 | { 606 | bool bValue; 607 | float fValue; 608 | int iValue; 609 | }; 610 | }; 611 | 612 | /** An identifier, typically a variable name or structure field name. */ 613 | struct HLSLIdentifierExpression : public HLSLExpression 614 | { 615 | static const HLSLNodeType s_type = HLSLNodeType_IdentifierExpression; 616 | HLSLIdentifierExpression() 617 | { 618 | name = NULL; 619 | global = false; 620 | } 621 | const char* name; 622 | bool global; // This is a global variable. 623 | }; 624 | 625 | /** float2(1, 2) */ 626 | struct HLSLConstructorExpression : public HLSLExpression 627 | { 628 | static const HLSLNodeType s_type = HLSLNodeType_ConstructorExpression; 629 | HLSLConstructorExpression() 630 | { 631 | argument = NULL; 632 | } 633 | HLSLType type; 634 | HLSLExpression* argument; 635 | }; 636 | 637 | /** object.member **/ 638 | struct HLSLMemberAccess : public HLSLExpression 639 | { 640 | static const HLSLNodeType s_type = HLSLNodeType_MemberAccess; 641 | HLSLMemberAccess() 642 | { 643 | object = NULL; 644 | field = NULL; 645 | swizzle = false; 646 | } 647 | HLSLExpression* object; 648 | const char* field; 649 | bool swizzle; 650 | }; 651 | 652 | /** array[index] **/ 653 | struct HLSLArrayAccess : public HLSLExpression 654 | { 655 | static const HLSLNodeType s_type = HLSLNodeType_ArrayAccess; 656 | HLSLArrayAccess() 657 | { 658 | array = NULL; 659 | index = NULL; 660 | } 661 | HLSLExpression* array; 662 | HLSLExpression* index; 663 | }; 664 | 665 | struct HLSLFunctionCall : public HLSLExpression 666 | { 667 | static const HLSLNodeType s_type = HLSLNodeType_FunctionCall; 668 | HLSLFunctionCall() 669 | { 670 | function = NULL; 671 | argument = NULL; 672 | numArguments = 0; 673 | } 674 | const HLSLFunction* function; 675 | HLSLExpression* argument; 676 | int numArguments; 677 | }; 678 | 679 | struct HLSLStateAssignment : public HLSLNode 680 | { 681 | static const HLSLNodeType s_type = HLSLNodeType_StateAssignment; 682 | HLSLStateAssignment() 683 | { 684 | stateName = NULL; 685 | sValue = NULL; 686 | nextStateAssignment = NULL; 687 | } 688 | 689 | const char* stateName; 690 | int d3dRenderState; 691 | union { 692 | int iValue; 693 | float fValue; 694 | const char * sValue; 695 | }; 696 | HLSLStateAssignment* nextStateAssignment; 697 | }; 698 | 699 | struct HLSLSamplerState : public HLSLExpression // @@ Does this need to be an expression? Does it have a type? I guess type is useful. 700 | { 701 | static const HLSLNodeType s_type = HLSLNodeType_SamplerState; 702 | HLSLSamplerState() 703 | { 704 | numStateAssignments = 0; 705 | stateAssignments = NULL; 706 | } 707 | 708 | int numStateAssignments; 709 | HLSLStateAssignment* stateAssignments; 710 | }; 711 | 712 | struct HLSLPass : public HLSLNode 713 | { 714 | static const HLSLNodeType s_type = HLSLNodeType_Pass; 715 | HLSLPass() 716 | { 717 | name = NULL; 718 | numStateAssignments = 0; 719 | stateAssignments = NULL; 720 | nextPass = NULL; 721 | } 722 | 723 | const char* name; 724 | int numStateAssignments; 725 | HLSLStateAssignment* stateAssignments; 726 | HLSLPass* nextPass; 727 | }; 728 | 729 | struct HLSLTechnique : public HLSLStatement 730 | { 731 | static const HLSLNodeType s_type = HLSLNodeType_Technique; 732 | HLSLTechnique() 733 | { 734 | name = NULL; 735 | numPasses = 0; 736 | passes = NULL; 737 | } 738 | 739 | const char* name; 740 | int numPasses; 741 | HLSLPass* passes; 742 | }; 743 | 744 | struct HLSLPipeline : public HLSLStatement 745 | { 746 | static const HLSLNodeType s_type = HLSLNodeType_Pipeline; 747 | HLSLPipeline() 748 | { 749 | name = NULL; 750 | numStateAssignments = 0; 751 | stateAssignments = NULL; 752 | } 753 | 754 | const char* name; 755 | int numStateAssignments; 756 | HLSLStateAssignment* stateAssignments; 757 | }; 758 | 759 | struct HLSLStage : public HLSLStatement 760 | { 761 | static const HLSLNodeType s_type = HLSLNodeType_Stage; 762 | HLSLStage() 763 | { 764 | name = NULL; 765 | statement = NULL; 766 | inputs = NULL; 767 | outputs = NULL; 768 | } 769 | 770 | const char* name; 771 | HLSLStatement* statement; 772 | HLSLDeclaration* inputs; 773 | HLSLDeclaration* outputs; 774 | }; 775 | 776 | 777 | /** 778 | * Abstract syntax tree for parsed HLSL code. 779 | */ 780 | class HLSLTree 781 | { 782 | 783 | public: 784 | 785 | explicit HLSLTree(Allocator* allocator); 786 | ~HLSLTree(); 787 | 788 | /** Adds a string to the string pool used by the tree. */ 789 | const char* AddString(const char* string); 790 | const char* AddStringFormat(const char* string, ...); 791 | 792 | /** Returns true if the string is contained within the tree. */ 793 | bool GetContainsString(const char* string) const; 794 | 795 | /** Returns the root block in the tree */ 796 | HLSLRoot* GetRoot() const; 797 | 798 | /** Adds a new node to the tree with the specified type. */ 799 | template 800 | T* AddNode(const char* fileName, int line) 801 | { 802 | HLSLNode* node = new (AllocateMemory(sizeof(T))) T(); 803 | node->nodeType = T::s_type; 804 | node->fileName = fileName; 805 | node->line = line; 806 | return static_cast(node); 807 | } 808 | 809 | HLSLFunction * FindFunction(const char * name); 810 | HLSLDeclaration * FindGlobalDeclaration(const char * name, HLSLBuffer ** buffer_out = NULL); 811 | HLSLStruct * FindGlobalStruct(const char * name); 812 | HLSLTechnique * FindTechnique(const char * name); 813 | HLSLPipeline * FindFirstPipeline(); 814 | HLSLPipeline * FindNextPipeline(HLSLPipeline * current); 815 | HLSLPipeline * FindPipeline(const char * name); 816 | HLSLBuffer * FindBuffer(const char * name); 817 | 818 | bool GetExpressionValue(HLSLExpression * expression, int & value); 819 | int GetExpressionValue(HLSLExpression * expression, float values[4]); 820 | 821 | bool NeedsFunction(const char * name); 822 | 823 | private: 824 | 825 | void* AllocateMemory(size_t size); 826 | void AllocatePage(); 827 | 828 | private: 829 | 830 | static const size_t s_nodePageSize = 1024 * 4; 831 | 832 | struct NodePage 833 | { 834 | NodePage* next; 835 | char buffer[s_nodePageSize]; 836 | }; 837 | 838 | Allocator* m_allocator; 839 | StringPool m_stringPool; 840 | HLSLRoot* m_root; 841 | 842 | NodePage* m_firstPage; 843 | NodePage* m_currentPage; 844 | size_t m_currentPageOffset; 845 | 846 | }; 847 | 848 | 849 | 850 | class HLSLTreeVisitor 851 | { 852 | public: 853 | virtual void VisitType(HLSLType & type); 854 | 855 | virtual void VisitRoot(HLSLRoot * node); 856 | virtual void VisitTopLevelStatement(HLSLStatement * node); 857 | virtual void VisitStatements(HLSLStatement * statement); 858 | virtual void VisitStatement(HLSLStatement * node); 859 | virtual void VisitDeclaration(HLSLDeclaration * node); 860 | virtual void VisitStruct(HLSLStruct * node); 861 | virtual void VisitStructField(HLSLStructField * node); 862 | virtual void VisitBuffer(HLSLBuffer * node); 863 | //virtual void VisitBufferField(HLSLBufferField * node); 864 | virtual void VisitFunction(HLSLFunction * node); 865 | virtual void VisitArgument(HLSLArgument * node); 866 | virtual void VisitExpressionStatement(HLSLExpressionStatement * node); 867 | virtual void VisitExpression(HLSLExpression * node); 868 | virtual void VisitReturnStatement(HLSLReturnStatement * node); 869 | virtual void VisitDiscardStatement(HLSLDiscardStatement * node); 870 | virtual void VisitBreakStatement(HLSLBreakStatement * node); 871 | virtual void VisitContinueStatement(HLSLContinueStatement * node); 872 | virtual void VisitIfStatement(HLSLIfStatement * node); 873 | virtual void VisitForStatement(HLSLForStatement * node); 874 | virtual void VisitBlockStatement(HLSLBlockStatement * node); 875 | virtual void VisitUnaryExpression(HLSLUnaryExpression * node); 876 | virtual void VisitBinaryExpression(HLSLBinaryExpression * node); 877 | virtual void VisitConditionalExpression(HLSLConditionalExpression * node); 878 | virtual void VisitCastingExpression(HLSLCastingExpression * node); 879 | virtual void VisitLiteralExpression(HLSLLiteralExpression * node); 880 | virtual void VisitIdentifierExpression(HLSLIdentifierExpression * node); 881 | virtual void VisitConstructorExpression(HLSLConstructorExpression * node); 882 | virtual void VisitMemberAccess(HLSLMemberAccess * node); 883 | virtual void VisitArrayAccess(HLSLArrayAccess * node); 884 | virtual void VisitFunctionCall(HLSLFunctionCall * node); 885 | virtual void VisitStateAssignment(HLSLStateAssignment * node); 886 | virtual void VisitSamplerState(HLSLSamplerState * node); 887 | virtual void VisitPass(HLSLPass * node); 888 | virtual void VisitTechnique(HLSLTechnique * node); 889 | 890 | virtual void VisitFunctions(HLSLRoot * root); 891 | virtual void VisitParameters(HLSLRoot * root); 892 | 893 | HLSLFunction * FindFunction(HLSLRoot * root, const char * name); 894 | HLSLDeclaration * FindGlobalDeclaration(HLSLRoot * root, const char * name); 895 | HLSLStruct * FindGlobalStruct(HLSLRoot * root, const char * name); 896 | }; 897 | 898 | 899 | // Tree transformations: 900 | extern void PruneTree(HLSLTree* tree, const char* entryName0, const char* entryName1 = NULL); 901 | extern void SortTree(HLSLTree* tree); 902 | extern void GroupParameters(HLSLTree* tree); 903 | extern void HideUnusedArguments(HLSLFunction * function); 904 | extern bool EmulateAlphaTest(HLSLTree* tree, const char* entryName, float alphaRef = 0.5f); 905 | 906 | } // M4 907 | 908 | #endif 909 | -------------------------------------------------------------------------------- /src/HLSLGenerator.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // 3 | // Render/HLSLGenerator.cpp 4 | // 5 | // Created by Max McGuire (max@unknownworlds.com) 6 | // Copyright (c) 2013, Unknown Worlds Entertainment, Inc. 7 | // 8 | //============================================================================= 9 | 10 | //#include "Engine/String.h" 11 | //#include "Engine/Log.h" 12 | #include "Engine.h" 13 | 14 | #include "HLSLGenerator.h" 15 | #include "HLSLParser.h" 16 | #include "HLSLTree.h" 17 | 18 | namespace M4 19 | { 20 | 21 | static const char* GetTypeName(const HLSLType& type) 22 | { 23 | switch (type.baseType) 24 | { 25 | case HLSLBaseType_Void: return "void"; 26 | case HLSLBaseType_Float: return "float"; 27 | case HLSLBaseType_Float2: return "float2"; 28 | case HLSLBaseType_Float3: return "float3"; 29 | case HLSLBaseType_Float4: return "float4"; 30 | case HLSLBaseType_Float2x2: return "float2x2"; 31 | case HLSLBaseType_Float3x3: return "float3x3"; 32 | case HLSLBaseType_Float4x4: return "float4x4"; 33 | case HLSLBaseType_Float4x3: return "float4x3"; 34 | case HLSLBaseType_Float4x2: return "float4x2"; 35 | case HLSLBaseType_Half: return "half"; 36 | case HLSLBaseType_Half2: return "half2"; 37 | case HLSLBaseType_Half3: return "half3"; 38 | case HLSLBaseType_Half4: return "half4"; 39 | case HLSLBaseType_Half2x2: return "half2x2"; 40 | case HLSLBaseType_Half3x3: return "half3x3"; 41 | case HLSLBaseType_Half4x4: return "half4x4"; 42 | case HLSLBaseType_Half4x3: return "half4x3"; 43 | case HLSLBaseType_Half4x2: return "half4x2"; 44 | case HLSLBaseType_Bool: return "bool"; 45 | case HLSLBaseType_Bool2: return "bool2"; 46 | case HLSLBaseType_Bool3: return "bool3"; 47 | case HLSLBaseType_Bool4: return "bool4"; 48 | case HLSLBaseType_Int: return "int"; 49 | case HLSLBaseType_Int2: return "int2"; 50 | case HLSLBaseType_Int3: return "int3"; 51 | case HLSLBaseType_Int4: return "int4"; 52 | case HLSLBaseType_Uint: return "uint"; 53 | case HLSLBaseType_Uint2: return "uint2"; 54 | case HLSLBaseType_Uint3: return "uint3"; 55 | case HLSLBaseType_Uint4: return "uint4"; 56 | case HLSLBaseType_Texture: return "texture"; 57 | case HLSLBaseType_Sampler: return "sampler"; 58 | case HLSLBaseType_Sampler2D: return "sampler2D"; 59 | case HLSLBaseType_Sampler3D: return "sampler3D"; 60 | case HLSLBaseType_SamplerCube: return "samplerCUBE"; 61 | case HLSLBaseType_Sampler2DShadow: return "sampler2DShadow"; 62 | case HLSLBaseType_Sampler2DMS: return "sampler2DMS"; 63 | case HLSLBaseType_Sampler2DArray: return "sampler2DArray"; 64 | case HLSLBaseType_UserDefined: return type.typeName; 65 | default: return ""; 66 | } 67 | } 68 | 69 | static int GetFunctionArguments(HLSLFunctionCall* functionCall, HLSLExpression* expression[], int maxArguments) 70 | { 71 | HLSLExpression* argument = functionCall->argument; 72 | int numArguments = 0; 73 | while (argument != NULL) 74 | { 75 | if (numArguments < maxArguments) 76 | { 77 | expression[numArguments] = argument; 78 | } 79 | argument = argument->nextExpression; 80 | ++numArguments; 81 | } 82 | return numArguments; 83 | } 84 | 85 | HLSLGenerator::HLSLGenerator() 86 | { 87 | m_tree = NULL; 88 | m_entryName = NULL; 89 | m_legacy = false; 90 | m_target = Target_VertexShader; 91 | m_isInsideBuffer = false; 92 | m_textureSampler2DStruct[0] = 0; 93 | m_textureSampler2DCtor[0] = 0; 94 | m_textureSampler3DStruct[0] = 0; 95 | m_textureSampler3DCtor[0] = 0; 96 | m_textureSamplerCubeStruct[0] = 0; 97 | m_textureSamplerCubeCtor[0] = 0; 98 | m_tex2DFunction[0] = 0; 99 | m_tex2DProjFunction[0] = 0; 100 | m_tex2DLodFunction[0] = 0; 101 | m_tex2DBiasFunction[0] = 0; 102 | m_tex2DGradFunction[0] = 0; 103 | m_tex2DGatherFunction[0] = 0; 104 | m_tex2DSizeFunction[0] = 0; 105 | m_tex2DFetchFunction[0] = 0; 106 | m_tex2DCmpFunction[0] = 0; 107 | m_tex2DMSFetchFunction[0] = 0; 108 | m_tex3DFunction[0] = 0; 109 | m_tex3DLodFunction[0] = 0; 110 | m_tex3DBiasFunction[0] = 0; 111 | m_texCubeFunction[0] = 0; 112 | m_texCubeLodFunction[0] = 0; 113 | m_texCubeBiasFunction[0] = 0; 114 | } 115 | 116 | 117 | // @@ We need a better way of doing semantic replacement: 118 | // - Look at the function being generated. 119 | // - Return semantic, semantics associated to fields of the return structure, or output arguments, or fields of structures associated to output arguments -> output semantic replacement. 120 | // - Semantics associated input arguments or fields of the input arguments -> input semantic replacement. 121 | static const char * TranslateSemantic(const char* semantic, bool output, HLSLGenerator::Target target) 122 | { 123 | if (target == HLSLGenerator::Target_VertexShader) 124 | { 125 | if (output) 126 | { 127 | if (String_Equal("POSITION", semantic)) return "SV_Position"; 128 | } 129 | else { 130 | if (String_Equal("INSTANCE_ID", semantic)) return "SV_InstanceID"; 131 | } 132 | } 133 | else if (target == HLSLGenerator::Target_PixelShader) 134 | { 135 | if (output) 136 | { 137 | if (String_Equal("DEPTH", semantic)) return "SV_Depth"; 138 | if (String_Equal("COLOR", semantic)) return "SV_Target"; 139 | if (String_Equal("COLOR0", semantic)) return "SV_Target0"; 140 | if (String_Equal("COLOR0_1", semantic)) return "SV_Target1"; 141 | if (String_Equal("COLOR1", semantic)) return "SV_Target1"; 142 | if (String_Equal("COLOR2", semantic)) return "SV_Target2"; 143 | if (String_Equal("COLOR3", semantic)) return "SV_Target3"; 144 | } 145 | else 146 | { 147 | if (String_Equal("VPOS", semantic)) return "SV_Position"; 148 | if (String_Equal("VFACE", semantic)) return "SV_IsFrontFace"; // bool @@ Should we do type replacement too? 149 | } 150 | } 151 | return NULL; 152 | } 153 | 154 | bool HLSLGenerator::Generate(HLSLTree* tree, Target target, const char* entryName, bool legacy) 155 | { 156 | m_tree = tree; 157 | m_entryName = entryName; 158 | m_target = target; 159 | m_legacy = legacy; 160 | m_isInsideBuffer = false; 161 | 162 | m_writer.Reset(); 163 | 164 | // @@ Should we generate an entirely new copy of the tree so that we can modify it in place? 165 | if (!legacy) 166 | { 167 | HLSLFunction * function = tree->FindFunction(entryName); 168 | 169 | // Handle return value semantics 170 | if (function->semantic != NULL) { 171 | function->sv_semantic = TranslateSemantic(function->semantic, /*output=*/true, target); 172 | } 173 | if (function->returnType.baseType == HLSLBaseType_UserDefined) { 174 | HLSLStruct * s = tree->FindGlobalStruct(function->returnType.typeName); 175 | 176 | HLSLStructField * sv_fields = NULL; 177 | 178 | HLSLStructField * lastField = NULL; 179 | HLSLStructField * field = s->field; 180 | while (field) { 181 | HLSLStructField * nextField = field->nextField; 182 | 183 | if (field->semantic) { 184 | field->hidden = false; 185 | field->sv_semantic = TranslateSemantic(field->semantic, /*output=*/true, target); 186 | 187 | // Fields with SV semantics are stored at the end to avoid linkage problems. 188 | if (field->sv_semantic != NULL) { 189 | // Unlink from last. 190 | if (lastField != NULL) lastField->nextField = nextField; 191 | else s->field = nextField; 192 | 193 | // Add to sv_fields. 194 | field->nextField = sv_fields; 195 | sv_fields = field; 196 | } 197 | } 198 | 199 | if (field != sv_fields) lastField = field; 200 | field = nextField; 201 | } 202 | 203 | // Append SV fields at the end. 204 | if (sv_fields != NULL) { 205 | if (lastField == NULL) { 206 | s->field = sv_fields; 207 | } 208 | else { 209 | ASSERT(lastField->nextField == NULL); 210 | lastField->nextField = sv_fields; 211 | } 212 | } 213 | } 214 | 215 | // Handle argument semantics. 216 | // @@ It would be nice to flag arguments that are used by the program and skip or hide the unused ones. 217 | HLSLArgument * argument = function->argument; 218 | while (argument) { 219 | bool output = argument->modifier == HLSLArgumentModifier_Out; 220 | if (argument->semantic) { 221 | argument->sv_semantic = TranslateSemantic(argument->semantic, output, target); 222 | } 223 | 224 | if (argument->type.baseType == HLSLBaseType_UserDefined) { 225 | HLSLStruct * s = tree->FindGlobalStruct(argument->type.typeName); 226 | 227 | HLSLStructField * field = s->field; 228 | while (field) { 229 | if (field->semantic) { 230 | field->hidden = false; 231 | 232 | if (target == Target_PixelShader && !output && String_EqualNoCase(field->semantic, "POSITION")) { 233 | ASSERT(String_EqualNoCase(field->sv_semantic, "SV_Position")); 234 | field->hidden = true; 235 | } 236 | 237 | field->sv_semantic = TranslateSemantic(field->semantic, output, target); 238 | } 239 | 240 | field = field->nextField; 241 | } 242 | } 243 | 244 | argument = argument->nextArgument; 245 | } 246 | } 247 | 248 | ChooseUniqueName("TextureSampler2D", m_textureSampler2DStruct, sizeof(m_textureSampler2DStruct)); 249 | ChooseUniqueName("CreateTextureSampler2D", m_textureSampler2DCtor, sizeof(m_textureSampler2DCtor)); 250 | ChooseUniqueName("TextureSampler2DShadow", m_textureSampler2DShadowStruct, sizeof(m_textureSampler2DShadowStruct)); 251 | ChooseUniqueName("CreateTextureSampler2DShadow",m_textureSampler2DShadowCtor, sizeof(m_textureSampler2DShadowCtor)); 252 | ChooseUniqueName("TextureSampler3D", m_textureSampler3DStruct, sizeof(m_textureSampler3DStruct)); 253 | ChooseUniqueName("CreateTextureSampler3D", m_textureSampler3DCtor, sizeof(m_textureSampler3DCtor)); 254 | ChooseUniqueName("TextureSamplerCube", m_textureSamplerCubeStruct, sizeof(m_textureSamplerCubeStruct)); 255 | ChooseUniqueName("CreateTextureSamplerCube", m_textureSamplerCubeCtor, sizeof(m_textureSamplerCubeCtor)); 256 | ChooseUniqueName("tex2D", m_tex2DFunction, sizeof(m_tex2DFunction)); 257 | ChooseUniqueName("tex2Dproj", m_tex2DProjFunction, sizeof(m_tex2DProjFunction)); 258 | ChooseUniqueName("tex2Dlod", m_tex2DLodFunction, sizeof(m_tex2DLodFunction)); 259 | ChooseUniqueName("tex2Dbias", m_tex2DBiasFunction, sizeof(m_tex2DBiasFunction)); 260 | ChooseUniqueName("tex2Dgrad", m_tex2DGradFunction, sizeof(m_tex2DGradFunction)); 261 | ChooseUniqueName("tex2Dgather", m_tex2DGatherFunction, sizeof(m_tex2DGatherFunction)); 262 | ChooseUniqueName("tex2Dsize", m_tex2DSizeFunction, sizeof(m_tex2DSizeFunction)); 263 | ChooseUniqueName("tex2Dfetch", m_tex2DFetchFunction, sizeof(m_tex2DFetchFunction)); 264 | ChooseUniqueName("tex2Dcmp", m_tex2DCmpFunction, sizeof(m_tex2DCmpFunction)); 265 | ChooseUniqueName("tex2DMSfetch", m_tex2DMSFetchFunction, sizeof(m_tex2DMSFetchFunction)); 266 | ChooseUniqueName("tex2DMSsize", m_tex2DMSSizeFunction, sizeof(m_tex2DMSSizeFunction)); 267 | ChooseUniqueName("tex3D", m_tex3DFunction, sizeof(m_tex3DFunction)); 268 | ChooseUniqueName("tex3Dlod", m_tex3DLodFunction, sizeof(m_tex3DLodFunction)); 269 | ChooseUniqueName("tex3Dbias", m_tex3DBiasFunction, sizeof(m_tex3DBiasFunction)); 270 | ChooseUniqueName("tex3Dsize", m_tex3DSizeFunction, sizeof(m_tex3DSizeFunction)); 271 | ChooseUniqueName("texCUBE", m_texCubeFunction, sizeof(m_texCubeFunction)); 272 | ChooseUniqueName("texCUBElod", m_texCubeLodFunction, sizeof(m_texCubeLodFunction)); 273 | ChooseUniqueName("texCUBEbias", m_texCubeBiasFunction, sizeof(m_texCubeBiasFunction)); 274 | ChooseUniqueName("texCUBEsize", m_texCubeSizeFunction, sizeof(m_texCubeSizeFunction)); 275 | 276 | if (!m_legacy) 277 | { 278 | // @@ Only emit code for sampler types that are actually used? 279 | 280 | m_writer.WriteLine(0, "struct %s {", m_textureSampler2DStruct); 281 | m_writer.WriteLine(1, "Texture2D t;"); 282 | m_writer.WriteLine(1, "SamplerState s;"); 283 | m_writer.WriteLine(0, "};"); 284 | 285 | m_writer.WriteLine(0, "struct %s {", m_textureSampler2DShadowStruct); 286 | m_writer.WriteLine(1, "Texture2D t;"); 287 | m_writer.WriteLine(1, "SamplerComparisonState s;"); 288 | m_writer.WriteLine(0, "};"); 289 | 290 | m_writer.WriteLine(0, "struct %s {", m_textureSampler3DStruct); 291 | m_writer.WriteLine(1, "Texture3D t;"); 292 | m_writer.WriteLine(1, "SamplerState s;"); 293 | m_writer.WriteLine(0, "};"); 294 | 295 | m_writer.WriteLine(0, "struct %s {", m_textureSamplerCubeStruct); 296 | m_writer.WriteLine(1, "TextureCube t;"); 297 | m_writer.WriteLine(1, "SamplerState s;"); 298 | m_writer.WriteLine(0, "};"); 299 | 300 | m_writer.WriteLine(0, "%s %s(Texture2D t, SamplerState s) {", m_textureSampler2DStruct, m_textureSampler2DCtor); 301 | m_writer.WriteLine(1, "%s ts;", m_textureSampler2DStruct); 302 | m_writer.WriteLine(1, "ts.t = t; ts.s = s;"); 303 | m_writer.WriteLine(1, "return ts;"); 304 | m_writer.WriteLine(0, "}"); 305 | 306 | m_writer.WriteLine(0, "%s %s(Texture2D t, SamplerComparisonState s) {", m_textureSampler2DShadowStruct, m_textureSampler2DShadowCtor); 307 | m_writer.WriteLine(1, "%s ts;", m_textureSampler2DShadowStruct); 308 | m_writer.WriteLine(1, "ts.t = t; ts.s = s;"); 309 | m_writer.WriteLine(1, "return ts;"); 310 | m_writer.WriteLine(0, "}"); 311 | 312 | m_writer.WriteLine(0, "%s %s(Texture3D t, SamplerState s) {", m_textureSampler3DStruct, m_textureSampler3DCtor); 313 | m_writer.WriteLine(1, "%s ts;", m_textureSampler3DStruct); 314 | m_writer.WriteLine(1, "ts.t = t; ts.s = s;"); 315 | m_writer.WriteLine(1, "return ts;"); 316 | m_writer.WriteLine(0, "}"); 317 | 318 | m_writer.WriteLine(0, "%s %s(TextureCube t, SamplerState s) {", m_textureSamplerCubeStruct, m_textureSamplerCubeCtor); 319 | m_writer.WriteLine(1, "%s ts;", m_textureSamplerCubeStruct); 320 | m_writer.WriteLine(1, "ts.t = t; ts.s = s;"); 321 | m_writer.WriteLine(1, "return ts;"); 322 | m_writer.WriteLine(0, "}"); 323 | 324 | if (m_tree->GetContainsString("tex2D")) 325 | { 326 | m_writer.WriteLine(0, "float4 %s(%s ts, float2 texCoord) {", m_tex2DFunction, m_textureSampler2DStruct); 327 | m_writer.WriteLine(1, "return ts.t.Sample(ts.s, texCoord);"); 328 | m_writer.WriteLine(0, "}"); 329 | } 330 | if (m_tree->GetContainsString("tex2Dproj")) 331 | { 332 | m_writer.WriteLine(0, "float4 %s(%s ts, float4 texCoord) {", m_tex2DProjFunction, m_textureSampler2DStruct); 333 | m_writer.WriteLine(1, "return ts.t.Sample(ts.s, texCoord.xy / texCoord.w);"); 334 | m_writer.WriteLine(0, "}"); 335 | } 336 | if (m_tree->GetContainsString("tex2Dlod")) 337 | { 338 | m_writer.WriteLine(0, "float4 %s(%s ts, float4 texCoord, int2 offset=0) {", m_tex2DLodFunction, m_textureSampler2DStruct); 339 | m_writer.WriteLine(1, "return ts.t.SampleLevel(ts.s, texCoord.xy, texCoord.w, offset);"); 340 | m_writer.WriteLine(0, "}"); 341 | } 342 | if (m_tree->GetContainsString("tex2Dbias")) 343 | { 344 | m_writer.WriteLine(0, "float4 %s(%s ts, float4 texCoord) {", m_tex2DBiasFunction, m_textureSampler2DStruct); 345 | m_writer.WriteLine(1, "return ts.t.SampleBias(ts.s, texCoord.xy, texCoord.w);"); 346 | m_writer.WriteLine(0, "}"); 347 | } 348 | if (m_tree->GetContainsString("tex2Dgrad")) 349 | { 350 | m_writer.WriteLine(0, "float4 %s(%s ts, float2 texCoord, float2 ddx, float2 ddy) {", m_tex2DGradFunction, m_textureSampler2DStruct); 351 | m_writer.WriteLine(1, "return ts.t.SampleGrad(ts.s, texCoord.xy, ddx, ddy);"); 352 | m_writer.WriteLine(0, "}"); 353 | } 354 | if (m_tree->GetContainsString("tex2Dgather")) 355 | { 356 | m_writer.WriteLine(0, "float4 %s(%s ts, float2 texCoord, int component, int2 offset=0) {", m_tex2DGatherFunction, m_textureSampler2DStruct); 357 | m_writer.WriteLine(1, "if(component == 0) return ts.t.GatherRed(ts.s, texCoord, offset);"); 358 | m_writer.WriteLine(1, "if(component == 1) return ts.t.GatherGreen(ts.s, texCoord, offset);"); 359 | m_writer.WriteLine(1, "if(component == 2) return ts.t.GatherBlue(ts.s, texCoord, offset);"); 360 | m_writer.WriteLine(1, "return ts.t.GatherAlpha(ts.s, texCoord, offset);"); 361 | m_writer.WriteLine(0, "}"); 362 | } 363 | if (m_tree->GetContainsString("tex2Dsize")) 364 | { 365 | m_writer.WriteLine(0, "int2 %s(%s ts) {", m_tex2DSizeFunction, m_textureSampler2DStruct); 366 | m_writer.WriteLine(1, "int2 size; ts.t.GetDimensions(size.x, size.y); return size;"); 367 | m_writer.WriteLine(0, "}"); 368 | } 369 | if (m_tree->GetContainsString("tex2Dfetch")) 370 | { 371 | m_writer.WriteLine(0, "int2 %s(%s ts, int3 texCoord) {", m_tex2DFetchFunction, m_textureSampler2DStruct); 372 | m_writer.WriteLine(1, "return ts.t.Load(texCoord.xyz);"); 373 | m_writer.WriteLine(0, "}"); 374 | } 375 | if (m_tree->GetContainsString("tex2Dcmp")) 376 | { 377 | m_writer.WriteLine(0, "float4 %s(%s ts, float4 texCoord) {", m_tex2DCmpFunction, m_textureSampler2DShadowStruct); 378 | m_writer.WriteLine(1, "return ts.t.SampleCmpLevelZero(ts.s, texCoord.xy, texCoord.z);"); 379 | m_writer.WriteLine(0, "}"); 380 | } 381 | if (m_tree->GetContainsString("tex2DMSfetch")) 382 | { 383 | m_writer.WriteLine(0, "float4 %s(Texture2DMS t, int2 texCoord, int sample) {", m_tex2DMSFetchFunction); 384 | m_writer.WriteLine(1, "return t.Load(texCoord, sample);"); 385 | m_writer.WriteLine(0, "}"); 386 | } 387 | if (m_tree->GetContainsString("tex2DMSsize")) 388 | { 389 | m_writer.WriteLine(0, "int3 %s(Texture2DMS t) {", m_tex2DMSSizeFunction); 390 | m_writer.WriteLine(1, "int3 size; t.GetDimensions(size.x, size.y, size.z); return size;"); // @@ Not tested, does this return the number of samples in the third argument? 391 | m_writer.WriteLine(0, "}"); 392 | } 393 | if (m_tree->GetContainsString("tex3D")) 394 | { 395 | m_writer.WriteLine(0, "float4 %s(%s ts, float3 texCoord) {", m_tex3DFunction, m_textureSampler3DStruct); 396 | m_writer.WriteLine(1, "return ts.t.Sample(ts.s, texCoord);"); 397 | m_writer.WriteLine(0, "}"); 398 | } 399 | if (m_tree->GetContainsString("tex3Dlod")) 400 | { 401 | m_writer.WriteLine(0, "float4 %s(%s ts, float4 texCoord) {", m_tex3DLodFunction, m_textureSampler3DStruct); 402 | m_writer.WriteLine(1, "return ts.t.SampleLevel(ts.s, texCoord.xyz, texCoord.w);"); 403 | m_writer.WriteLine(0, "}"); 404 | } 405 | if (m_tree->GetContainsString("tex3Dbias")) 406 | { 407 | m_writer.WriteLine(0, "float4 %s(%s ts, float4 texCoord) {", m_tex3DBiasFunction, m_textureSampler3DStruct); 408 | m_writer.WriteLine(1, "return ts.t.SampleBias(ts.s, texCoord.xyz, texCoord.w);"); 409 | m_writer.WriteLine(0, "}"); 410 | } 411 | if (m_tree->GetContainsString("tex3Dsize")) 412 | { 413 | m_writer.WriteLine(0, "int3 %s(%s ts) {", m_tex3DSizeFunction, m_textureSampler3DStruct); 414 | m_writer.WriteLine(1, "int3 size; ts.t.GetDimensions(size.x, size.y, size.z); return size;"); 415 | m_writer.WriteLine(0, "}"); 416 | } 417 | if (m_tree->GetContainsString("texCUBE")) 418 | { 419 | m_writer.WriteLine(0, "float4 %s(%s ts, float3 texCoord) {", m_texCubeFunction, m_textureSamplerCubeStruct); 420 | m_writer.WriteLine(1, "return ts.t.Sample(ts.s, texCoord);"); 421 | m_writer.WriteLine(0, "}"); 422 | } 423 | if (m_tree->GetContainsString("texCUBElod")) 424 | { 425 | m_writer.WriteLine(0, "float4 %s(%s ts, float4 texCoord) {", m_texCubeLodFunction, m_textureSamplerCubeStruct); 426 | m_writer.WriteLine(1, "return ts.t.SampleLevel(ts.s, texCoord.xyz, texCoord.w);"); 427 | m_writer.WriteLine(0, "}"); 428 | } 429 | if (m_tree->GetContainsString("texCUBEbias")) 430 | { 431 | m_writer.WriteLine(0, "float4 %s(%s ts, float4 texCoord) {", m_texCubeBiasFunction, m_textureSamplerCubeStruct); 432 | m_writer.WriteLine(1, "return ts.t.SampleBias(ts.s, texCoord.xyz, texCoord.w);"); 433 | m_writer.WriteLine(0, "}"); 434 | } 435 | if (m_tree->GetContainsString("texCUBEsize")) 436 | { 437 | m_writer.WriteLine(0, "int %s(%s ts) {", m_texCubeSizeFunction, m_textureSamplerCubeStruct); 438 | m_writer.WriteLine(1, "int size; ts.t.GetDimensions(size); return size;"); // @@ Not tested, does this return a single value? 439 | m_writer.WriteLine(0, "}"); 440 | } 441 | } 442 | 443 | HLSLRoot* root = m_tree->GetRoot(); 444 | OutputStatements(0, root->statement); 445 | 446 | m_tree = NULL; 447 | return true; 448 | } 449 | 450 | const char* HLSLGenerator::GetResult() const 451 | { 452 | return m_writer.GetResult(); 453 | } 454 | 455 | void HLSLGenerator::OutputExpressionList(HLSLExpression* expression) 456 | { 457 | int numExpressions = 0; 458 | while (expression != NULL) 459 | { 460 | if (numExpressions > 0) 461 | { 462 | m_writer.Write(", "); 463 | } 464 | OutputExpression(expression); 465 | expression = expression->nextExpression; 466 | ++numExpressions; 467 | } 468 | } 469 | 470 | void HLSLGenerator::OutputExpression(HLSLExpression* expression) 471 | { 472 | if (expression->nodeType == HLSLNodeType_IdentifierExpression) 473 | { 474 | HLSLIdentifierExpression* identifierExpression = static_cast(expression); 475 | const char* name = identifierExpression->name; 476 | if (!m_legacy && IsSamplerType(identifierExpression->expressionType) && identifierExpression->global) 477 | { 478 | // @@ Handle generic sampler type. 479 | 480 | if (identifierExpression->expressionType.baseType == HLSLBaseType_Sampler2D) 481 | { 482 | m_writer.Write("%s(%s_texture, %s_sampler)", m_textureSampler2DCtor, name, name); 483 | } 484 | else if (identifierExpression->expressionType.baseType == HLSLBaseType_Sampler3D) 485 | { 486 | m_writer.Write("%s(%s_texture, %s_sampler)", m_textureSampler3DCtor, name, name); 487 | } 488 | else if (identifierExpression->expressionType.baseType == HLSLBaseType_SamplerCube) 489 | { 490 | m_writer.Write("%s(%s_texture, %s_sampler)", m_textureSamplerCubeCtor, name, name); 491 | } 492 | else if (identifierExpression->expressionType.baseType == HLSLBaseType_Sampler2DShadow) 493 | { 494 | m_writer.Write("%s(%s_texture, %s_sampler)", m_textureSampler2DShadowCtor, name, name); 495 | } 496 | else if (identifierExpression->expressionType.baseType == HLSLBaseType_Sampler2DMS) 497 | { 498 | m_writer.Write("%s", name); 499 | } 500 | } 501 | else 502 | { 503 | m_writer.Write("%s", name); 504 | } 505 | } 506 | else if (expression->nodeType == HLSLNodeType_CastingExpression) 507 | { 508 | HLSLCastingExpression* castingExpression = static_cast(expression); 509 | m_writer.Write("("); 510 | OutputDeclaration(castingExpression->type, ""); 511 | m_writer.Write(")("); 512 | OutputExpression(castingExpression->expression); 513 | m_writer.Write(")"); 514 | } 515 | else if (expression->nodeType == HLSLNodeType_ConstructorExpression) 516 | { 517 | HLSLConstructorExpression* constructorExpression = static_cast(expression); 518 | m_writer.Write("%s(", GetTypeName(constructorExpression->type)); 519 | OutputExpressionList(constructorExpression->argument); 520 | m_writer.Write(")"); 521 | } 522 | else if (expression->nodeType == HLSLNodeType_LiteralExpression) 523 | { 524 | HLSLLiteralExpression* literalExpression = static_cast(expression); 525 | switch (literalExpression->type) 526 | { 527 | case HLSLBaseType_Half: 528 | case HLSLBaseType_Float: 529 | { 530 | // Don't use printf directly so that we don't use the system locale. 531 | char buffer[64]; 532 | String_FormatFloat(buffer, sizeof(buffer), literalExpression->fValue); 533 | m_writer.Write("%s", buffer); 534 | } 535 | break; 536 | case HLSLBaseType_Int: 537 | m_writer.Write("%d", literalExpression->iValue); 538 | break; 539 | case HLSLBaseType_Bool: 540 | m_writer.Write("%s", literalExpression->bValue ? "true" : "false"); 541 | break; 542 | default: 543 | ASSERT(0); 544 | } 545 | } 546 | else if (expression->nodeType == HLSLNodeType_UnaryExpression) 547 | { 548 | HLSLUnaryExpression* unaryExpression = static_cast(expression); 549 | const char* op = "?"; 550 | bool pre = true; 551 | switch (unaryExpression->unaryOp) 552 | { 553 | case HLSLUnaryOp_Negative: op = "-"; break; 554 | case HLSLUnaryOp_Positive: op = "+"; break; 555 | case HLSLUnaryOp_Not: op = "!"; break; 556 | case HLSLUnaryOp_PreIncrement: op = "++"; break; 557 | case HLSLUnaryOp_PreDecrement: op = "--"; break; 558 | case HLSLUnaryOp_PostIncrement: op = "++"; pre = false; break; 559 | case HLSLUnaryOp_PostDecrement: op = "--"; pre = false; break; 560 | case HLSLUnaryOp_BitNot: op = "~"; break; 561 | } 562 | m_writer.Write("("); 563 | if (pre) 564 | { 565 | m_writer.Write("%s", op); 566 | OutputExpression(unaryExpression->expression); 567 | } 568 | else 569 | { 570 | OutputExpression(unaryExpression->expression); 571 | m_writer.Write("%s", op); 572 | } 573 | m_writer.Write(")"); 574 | } 575 | else if (expression->nodeType == HLSLNodeType_BinaryExpression) 576 | { 577 | HLSLBinaryExpression* binaryExpression = static_cast(expression); 578 | m_writer.Write("("); 579 | OutputExpression(binaryExpression->expression1); 580 | const char* op = "?"; 581 | switch (binaryExpression->binaryOp) 582 | { 583 | case HLSLBinaryOp_Add: op = " + "; break; 584 | case HLSLBinaryOp_Sub: op = " - "; break; 585 | case HLSLBinaryOp_Mul: op = " * "; break; 586 | case HLSLBinaryOp_Div: op = " / "; break; 587 | case HLSLBinaryOp_Less: op = " < "; break; 588 | case HLSLBinaryOp_Greater: op = " > "; break; 589 | case HLSLBinaryOp_LessEqual: op = " <= "; break; 590 | case HLSLBinaryOp_GreaterEqual: op = " >= "; break; 591 | case HLSLBinaryOp_Equal: op = " == "; break; 592 | case HLSLBinaryOp_NotEqual: op = " != "; break; 593 | case HLSLBinaryOp_Assign: op = " = "; break; 594 | case HLSLBinaryOp_AddAssign: op = " += "; break; 595 | case HLSLBinaryOp_SubAssign: op = " -= "; break; 596 | case HLSLBinaryOp_MulAssign: op = " *= "; break; 597 | case HLSLBinaryOp_DivAssign: op = " /= "; break; 598 | case HLSLBinaryOp_And: op = " && "; break; 599 | case HLSLBinaryOp_Or: op = " || "; break; 600 | case HLSLBinaryOp_BitAnd: op = " & "; break; 601 | case HLSLBinaryOp_BitOr: op = " | "; break; 602 | case HLSLBinaryOp_BitXor: op = " ^ "; break; 603 | default: 604 | ASSERT(0); 605 | } 606 | m_writer.Write("%s", op); 607 | OutputExpression(binaryExpression->expression2); 608 | m_writer.Write(")"); 609 | } 610 | else if (expression->nodeType == HLSLNodeType_ConditionalExpression) 611 | { 612 | HLSLConditionalExpression* conditionalExpression = static_cast(expression); 613 | m_writer.Write("(("); 614 | OutputExpression(conditionalExpression->condition); 615 | m_writer.Write(")?("); 616 | OutputExpression(conditionalExpression->trueExpression); 617 | m_writer.Write("):("); 618 | OutputExpression(conditionalExpression->falseExpression); 619 | m_writer.Write("))"); 620 | } 621 | else if (expression->nodeType == HLSLNodeType_MemberAccess) 622 | { 623 | HLSLMemberAccess* memberAccess = static_cast(expression); 624 | m_writer.Write("("); 625 | OutputExpression(memberAccess->object); 626 | m_writer.Write(").%s", memberAccess->field); 627 | } 628 | else if (expression->nodeType == HLSLNodeType_ArrayAccess) 629 | { 630 | HLSLArrayAccess* arrayAccess = static_cast(expression); 631 | OutputExpression(arrayAccess->array); 632 | m_writer.Write("["); 633 | OutputExpression(arrayAccess->index); 634 | m_writer.Write("]"); 635 | } 636 | else if (expression->nodeType == HLSLNodeType_FunctionCall) 637 | { 638 | HLSLFunctionCall* functionCall = static_cast(expression); 639 | const char* name = functionCall->function->name; 640 | if (!m_legacy) 641 | { 642 | if (String_Equal(name, "tex2D")) 643 | { 644 | name = m_tex2DFunction; 645 | } 646 | else if (String_Equal(name, "tex2Dproj")) 647 | { 648 | name = m_tex2DProjFunction; 649 | } 650 | else if (String_Equal(name, "tex2Dlod")) 651 | { 652 | name = m_tex2DLodFunction; 653 | } 654 | else if (String_Equal(name, "tex2Dbias")) 655 | { 656 | name = m_tex2DBiasFunction; 657 | } 658 | else if (String_Equal(name, "tex2Dgrad")) 659 | { 660 | name = m_tex2DGradFunction; 661 | } 662 | else if (String_Equal(name, "tex2Dgather")) 663 | { 664 | name = m_tex2DGatherFunction; 665 | } 666 | else if (String_Equal(name, "tex2Dsize")) 667 | { 668 | name = m_tex2DSizeFunction; 669 | } 670 | else if (String_Equal(name, "tex2Dfetch")) 671 | { 672 | name = m_tex2DFetchFunction; 673 | } 674 | else if (String_Equal(name, "tex2Dcmp")) 675 | { 676 | name = m_tex2DCmpFunction; 677 | } 678 | else if (String_Equal(name, "tex2DMSfetch")) 679 | { 680 | name = m_tex2DMSFetchFunction; 681 | } 682 | else if (String_Equal(name, "tex2DMSsize")) 683 | { 684 | name = m_tex2DMSSizeFunction; 685 | } 686 | else if (String_Equal(name, "tex3D")) 687 | { 688 | name = m_tex3DFunction; 689 | } 690 | else if (String_Equal(name, "tex3Dlod")) 691 | { 692 | name = m_tex3DLodFunction; 693 | } 694 | else if (String_Equal(name, "tex3Dbias")) 695 | { 696 | name = m_tex3DBiasFunction; 697 | } 698 | else if (String_Equal(name, "tex3Dsize")) 699 | { 700 | name = m_tex3DSizeFunction; 701 | } 702 | else if (String_Equal(name, "texCUBE")) 703 | { 704 | name = m_texCubeFunction; 705 | } 706 | else if (String_Equal(name, "texCUBElod")) 707 | { 708 | name = m_texCubeLodFunction; 709 | } 710 | else if (String_Equal(name, "texCUBEbias")) 711 | { 712 | name = m_texCubeBiasFunction; 713 | } 714 | else if (String_Equal(name, "texCUBEsize")) 715 | { 716 | name = m_texCubeSizeFunction; 717 | } 718 | } 719 | m_writer.Write("%s(", name); 720 | OutputExpressionList(functionCall->argument); 721 | m_writer.Write(")"); 722 | } 723 | else 724 | { 725 | m_writer.Write(""); 726 | } 727 | } 728 | 729 | void HLSLGenerator::OutputArguments(HLSLArgument* argument) 730 | { 731 | int numArgs = 0; 732 | while (argument != NULL) 733 | { 734 | if (numArgs > 0) 735 | { 736 | m_writer.Write(", "); 737 | } 738 | 739 | switch (argument->modifier) 740 | { 741 | case HLSLArgumentModifier_In: 742 | m_writer.Write("in "); 743 | break; 744 | case HLSLArgumentModifier_Out: 745 | m_writer.Write("out "); 746 | break; 747 | case HLSLArgumentModifier_Inout: 748 | m_writer.Write("inout "); 749 | break; 750 | case HLSLArgumentModifier_Uniform: 751 | m_writer.Write("uniform "); 752 | break; 753 | } 754 | 755 | const char * semantic = argument->sv_semantic ? argument->sv_semantic : argument->semantic; 756 | 757 | OutputDeclaration(argument->type, argument->name, semantic, /*registerName=*/NULL, argument->defaultValue); 758 | argument = argument->nextArgument; 759 | ++numArgs; 760 | } 761 | } 762 | 763 | static const char * GetAttributeName(HLSLAttributeType attributeType) 764 | { 765 | if (attributeType == HLSLAttributeType_Unroll) return "unroll"; 766 | if (attributeType == HLSLAttributeType_Branch) return "branch"; 767 | if (attributeType == HLSLAttributeType_Flatten) return "flatten"; 768 | return NULL; 769 | } 770 | 771 | void HLSLGenerator::OutputAttributes(int indent, HLSLAttribute* attribute) 772 | { 773 | while (attribute != NULL) 774 | { 775 | const char * attributeName = GetAttributeName(attribute->attributeType); 776 | 777 | if (attributeName != NULL) 778 | { 779 | m_writer.WriteLineTagged(indent, attribute->fileName, attribute->line, "[%s]", attributeName); 780 | } 781 | 782 | attribute = attribute->nextAttribute; 783 | } 784 | } 785 | 786 | void HLSLGenerator::OutputStatements(int indent, HLSLStatement* statement) 787 | { 788 | while (statement != NULL) 789 | { 790 | if (statement->hidden) 791 | { 792 | statement = statement->nextStatement; 793 | continue; 794 | } 795 | 796 | OutputAttributes(indent, statement->attributes); 797 | 798 | if (statement->nodeType == HLSLNodeType_Declaration) 799 | { 800 | HLSLDeclaration* declaration = static_cast(statement); 801 | m_writer.BeginLine(indent, declaration->fileName, declaration->line); 802 | OutputDeclaration(declaration); 803 | m_writer.EndLine(";"); 804 | } 805 | else if (statement->nodeType == HLSLNodeType_Struct) 806 | { 807 | HLSLStruct* structure = static_cast(statement); 808 | m_writer.WriteLineTagged(indent, structure->fileName, structure->line, "struct %s {", structure->name); 809 | HLSLStructField* field = structure->field; 810 | while (field != NULL) 811 | { 812 | if (!field->hidden) 813 | { 814 | m_writer.BeginLine(indent + 1, field->fileName, field->line); 815 | const char * semantic = field->sv_semantic ? field->sv_semantic : field->semantic; 816 | OutputDeclaration(field->type, field->name, semantic); 817 | m_writer.Write(";"); 818 | m_writer.EndLine(); 819 | } 820 | field = field->nextField; 821 | } 822 | m_writer.WriteLine(indent, "};"); 823 | } 824 | else if (statement->nodeType == HLSLNodeType_Buffer) 825 | { 826 | HLSLBuffer* buffer = static_cast(statement); 827 | HLSLDeclaration* field = buffer->field; 828 | 829 | if (!m_legacy) 830 | { 831 | m_writer.BeginLine(indent, buffer->fileName, buffer->line); 832 | m_writer.Write("cbuffer %s", buffer->name); 833 | if (buffer->registerName != NULL) 834 | { 835 | m_writer.Write(" : register(%s)", buffer->registerName); 836 | } 837 | m_writer.EndLine(" {"); 838 | } 839 | 840 | m_isInsideBuffer = true; 841 | 842 | while (field != NULL) 843 | { 844 | if (!field->hidden) 845 | { 846 | m_writer.BeginLine(indent + 1, field->fileName, field->line); 847 | OutputDeclaration(field->type, field->name, /*semantic=*/NULL, /*registerName*/field->registerName, field->assignment); 848 | m_writer.Write(";"); 849 | m_writer.EndLine(); 850 | } 851 | field = (HLSLDeclaration*)field->nextStatement; 852 | } 853 | 854 | m_isInsideBuffer = false; 855 | 856 | if (!m_legacy) 857 | { 858 | m_writer.WriteLine(indent, "};"); 859 | } 860 | } 861 | else if (statement->nodeType == HLSLNodeType_Function) 862 | { 863 | HLSLFunction* function = static_cast(statement); 864 | 865 | // Use an alternate name for the function which is supposed to be entry point 866 | // so that we can supply our own function which will be the actual entry point. 867 | const char* functionName = function->name; 868 | const char* returnTypeName = GetTypeName(function->returnType); 869 | 870 | m_writer.BeginLine(indent, function->fileName, function->line); 871 | m_writer.Write("%s %s(", returnTypeName, functionName); 872 | 873 | OutputArguments(function->argument); 874 | 875 | const char * semantic = function->sv_semantic ? function->sv_semantic : function->semantic; 876 | if (semantic != NULL) 877 | { 878 | m_writer.Write(") : %s {", semantic); 879 | } 880 | else 881 | { 882 | m_writer.Write(") {"); 883 | } 884 | 885 | m_writer.EndLine(); 886 | 887 | OutputStatements(indent + 1, function->statement); 888 | m_writer.WriteLine(indent, "};"); 889 | } 890 | else if (statement->nodeType == HLSLNodeType_ExpressionStatement) 891 | { 892 | HLSLExpressionStatement* expressionStatement = static_cast(statement); 893 | m_writer.BeginLine(indent, statement->fileName, statement->line); 894 | OutputExpression(expressionStatement->expression); 895 | m_writer.EndLine(";"); 896 | } 897 | else if (statement->nodeType == HLSLNodeType_ReturnStatement) 898 | { 899 | HLSLReturnStatement* returnStatement = static_cast(statement); 900 | if (returnStatement->expression != NULL) 901 | { 902 | m_writer.BeginLine(indent, returnStatement->fileName, returnStatement->line); 903 | m_writer.Write("return "); 904 | OutputExpression(returnStatement->expression); 905 | m_writer.EndLine(";"); 906 | } 907 | else 908 | { 909 | m_writer.WriteLineTagged(indent, returnStatement->fileName, returnStatement->line, "return;"); 910 | } 911 | } 912 | else if (statement->nodeType == HLSLNodeType_DiscardStatement) 913 | { 914 | HLSLDiscardStatement* discardStatement = static_cast(statement); 915 | m_writer.WriteLineTagged(indent, discardStatement->fileName, discardStatement->line, "discard;"); 916 | } 917 | else if (statement->nodeType == HLSLNodeType_BreakStatement) 918 | { 919 | HLSLBreakStatement* breakStatement = static_cast(statement); 920 | m_writer.WriteLineTagged(indent, breakStatement->fileName, breakStatement->line, "break;"); 921 | } 922 | else if (statement->nodeType == HLSLNodeType_ContinueStatement) 923 | { 924 | HLSLContinueStatement* continueStatement = static_cast(statement); 925 | m_writer.WriteLineTagged(indent, continueStatement->fileName, continueStatement->line, "continue;"); 926 | } 927 | else if (statement->nodeType == HLSLNodeType_IfStatement) 928 | { 929 | HLSLIfStatement* ifStatement = static_cast(statement); 930 | m_writer.BeginLine(indent, ifStatement->fileName, ifStatement->line); 931 | m_writer.Write("if ("); 932 | OutputExpression(ifStatement->condition); 933 | m_writer.Write(") {"); 934 | m_writer.EndLine(); 935 | OutputStatements(indent + 1, ifStatement->statement); 936 | m_writer.WriteLine(indent, "}"); 937 | if (ifStatement->elseStatement != NULL) 938 | { 939 | m_writer.WriteLine(indent, "else {"); 940 | OutputStatements(indent + 1, ifStatement->elseStatement); 941 | m_writer.WriteLine(indent, "}"); 942 | } 943 | } 944 | else if (statement->nodeType == HLSLNodeType_ForStatement) 945 | { 946 | HLSLForStatement* forStatement = static_cast(statement); 947 | m_writer.BeginLine(indent, forStatement->fileName, forStatement->line); 948 | m_writer.Write("for ("); 949 | OutputDeclaration(forStatement->initialization); 950 | m_writer.Write("; "); 951 | OutputExpression(forStatement->condition); 952 | m_writer.Write("; "); 953 | OutputExpression(forStatement->increment); 954 | m_writer.Write(") {"); 955 | m_writer.EndLine(); 956 | OutputStatements(indent + 1, forStatement->statement); 957 | m_writer.WriteLine(indent, "}"); 958 | } 959 | else if (statement->nodeType == HLSLNodeType_BlockStatement) 960 | { 961 | HLSLBlockStatement* blockStatement = static_cast(statement); 962 | m_writer.WriteLineTagged(indent, blockStatement->fileName, blockStatement->line, "{"); 963 | OutputStatements(indent + 1, blockStatement->statement); 964 | m_writer.WriteLine(indent, "}"); 965 | } 966 | else if (statement->nodeType == HLSLNodeType_Technique) 967 | { 968 | // Techniques are ignored. 969 | } 970 | else if (statement->nodeType == HLSLNodeType_Pipeline) 971 | { 972 | // Pipelines are ignored. 973 | } 974 | else 975 | { 976 | // Unhanded statement type. 977 | ASSERT(0); 978 | } 979 | 980 | statement = statement->nextStatement; 981 | } 982 | } 983 | 984 | void HLSLGenerator::OutputDeclaration(HLSLDeclaration* declaration) 985 | { 986 | bool isSamplerType = IsSamplerType(declaration->type); 987 | 988 | if (!m_legacy && isSamplerType) 989 | { 990 | int reg = -1; 991 | if (declaration->registerName != NULL) 992 | { 993 | sscanf(declaration->registerName, "s%d", ®); 994 | } 995 | 996 | const char* textureType = NULL; 997 | const char* samplerType = "SamplerState"; 998 | // @@ Handle generic sampler type. 999 | 1000 | if (declaration->type.baseType == HLSLBaseType_Sampler2D) 1001 | { 1002 | textureType = "Texture2D"; 1003 | } 1004 | else if (declaration->type.baseType == HLSLBaseType_Sampler3D) 1005 | { 1006 | textureType = "Texture3D"; 1007 | } 1008 | else if (declaration->type.baseType == HLSLBaseType_SamplerCube) 1009 | { 1010 | textureType = "TextureCube"; 1011 | } 1012 | else if (declaration->type.baseType == HLSLBaseType_Sampler2DShadow) 1013 | { 1014 | textureType = "Texture2D"; 1015 | samplerType = "SamplerComparisonState"; 1016 | } 1017 | else if (declaration->type.baseType == HLSLBaseType_Sampler2DMS) 1018 | { 1019 | textureType = "Texture2DMS"; // @@ Is template argument required? 1020 | samplerType = NULL; 1021 | } 1022 | 1023 | if (samplerType != NULL) 1024 | { 1025 | if (reg != -1) 1026 | { 1027 | m_writer.Write("%s %s_texture : register(t%d); %s %s_sampler : register(s%d)", textureType, declaration->name, reg, samplerType, declaration->name, reg); 1028 | } 1029 | else 1030 | { 1031 | m_writer.Write("%s %s_texture; %s %s_sampler", textureType, declaration->name, samplerType, declaration->name); 1032 | } 1033 | } 1034 | else 1035 | { 1036 | if (reg != -1) 1037 | { 1038 | m_writer.Write("%s %s : register(t%d)", textureType, declaration->name, reg); 1039 | } 1040 | else 1041 | { 1042 | m_writer.Write("%s %s", textureType, declaration->name); 1043 | } 1044 | } 1045 | return; 1046 | } 1047 | 1048 | OutputDeclarationType(declaration->type); 1049 | OutputDeclarationBody(declaration->type, declaration->name, declaration->semantic, declaration->registerName, declaration->assignment); 1050 | declaration = declaration->nextDeclaration; 1051 | 1052 | while(declaration != NULL) { 1053 | m_writer.Write(", "); 1054 | OutputDeclarationBody(declaration->type, declaration->name, declaration->semantic, declaration->registerName, declaration->assignment); 1055 | declaration = declaration->nextDeclaration; 1056 | }; 1057 | } 1058 | 1059 | void HLSLGenerator::OutputDeclarationType(const HLSLType& type) 1060 | { 1061 | const char* typeName = GetTypeName(type); 1062 | if (!m_legacy) 1063 | { 1064 | if (type.baseType == HLSLBaseType_Sampler2D) 1065 | { 1066 | typeName = m_textureSampler2DStruct; 1067 | } 1068 | else if (type.baseType == HLSLBaseType_Sampler3D) 1069 | { 1070 | typeName = m_textureSampler3DStruct; 1071 | } 1072 | else if (type.baseType == HLSLBaseType_SamplerCube) 1073 | { 1074 | typeName = m_textureSamplerCubeStruct; 1075 | } 1076 | else if (type.baseType == HLSLBaseType_Sampler2DShadow) 1077 | { 1078 | typeName = m_textureSampler2DShadowStruct; 1079 | } 1080 | else if (type.baseType == HLSLBaseType_Sampler2DMS) 1081 | { 1082 | typeName = "Texture2DMS"; 1083 | } 1084 | } 1085 | 1086 | if (type.flags & HLSLTypeFlag_Const) 1087 | { 1088 | m_writer.Write("const "); 1089 | } 1090 | if (type.flags & HLSLTypeFlag_Static) 1091 | { 1092 | m_writer.Write("static "); 1093 | } 1094 | 1095 | // Interpolation modifiers. 1096 | if (type.flags & HLSLTypeFlag_Centroid) 1097 | { 1098 | m_writer.Write("centroid "); 1099 | } 1100 | if (type.flags & HLSLTypeFlag_Linear) 1101 | { 1102 | m_writer.Write("linear "); 1103 | } 1104 | if (type.flags & HLSLTypeFlag_NoInterpolation) 1105 | { 1106 | m_writer.Write("nointerpolation "); 1107 | } 1108 | if (type.flags & HLSLTypeFlag_NoPerspective) 1109 | { 1110 | m_writer.Write("noperspective "); 1111 | } 1112 | if (type.flags & HLSLTypeFlag_Sample) // @@ Only in shader model >= 4.1 1113 | { 1114 | m_writer.Write("sample "); 1115 | } 1116 | 1117 | m_writer.Write("%s ", typeName); 1118 | } 1119 | 1120 | void HLSLGenerator::OutputDeclarationBody(const HLSLType& type, const char* name, const char* semantic/*=NULL*/, const char* registerName/*=NULL*/, HLSLExpression * assignment/*=NULL*/) 1121 | { 1122 | m_writer.Write("%s", name); 1123 | 1124 | if (type.array) 1125 | { 1126 | ASSERT(semantic == NULL); 1127 | m_writer.Write("["); 1128 | if (type.arraySize != NULL) 1129 | { 1130 | OutputExpression(type.arraySize); 1131 | } 1132 | m_writer.Write("]"); 1133 | } 1134 | 1135 | if (semantic != NULL) 1136 | { 1137 | m_writer.Write(" : %s", semantic); 1138 | } 1139 | 1140 | if (registerName != NULL) 1141 | { 1142 | if (m_isInsideBuffer) 1143 | { 1144 | m_writer.Write(" : packoffset(%s)", registerName); 1145 | } 1146 | else 1147 | { 1148 | m_writer.Write(" : register(%s)", registerName); 1149 | } 1150 | } 1151 | 1152 | if (assignment != NULL && !IsSamplerType(type)) 1153 | { 1154 | m_writer.Write(" = "); 1155 | if (type.array) 1156 | { 1157 | m_writer.Write("{ "); 1158 | OutputExpressionList(assignment); 1159 | m_writer.Write(" }"); 1160 | } 1161 | else 1162 | { 1163 | OutputExpression(assignment); 1164 | } 1165 | } 1166 | } 1167 | 1168 | void HLSLGenerator::OutputDeclaration(const HLSLType& type, const char* name, const char* semantic/*=NULL*/, const char* registerName/*=NULL*/, HLSLExpression * assignment/*=NULL*/) 1169 | { 1170 | OutputDeclarationType(type); 1171 | OutputDeclarationBody(type, name, semantic, registerName, assignment); 1172 | } 1173 | 1174 | bool HLSLGenerator::ChooseUniqueName(const char* base, char* dst, int dstLength) const 1175 | { 1176 | // IC: Try without suffix first. 1177 | String_Printf(dst, dstLength, "%s", base); 1178 | if (!m_tree->GetContainsString(base)) 1179 | { 1180 | return true; 1181 | } 1182 | 1183 | for (int i = 1; i < 1024; ++i) 1184 | { 1185 | String_Printf(dst, dstLength, "%s%d", base, i); 1186 | if (!m_tree->GetContainsString(dst)) 1187 | { 1188 | return true; 1189 | } 1190 | } 1191 | return false; 1192 | } 1193 | 1194 | } 1195 | -------------------------------------------------------------------------------- /src/HLSLTree.cpp: -------------------------------------------------------------------------------- 1 | //#include "Engine/Assert.h" 2 | #include "Engine.h" 3 | 4 | #include "HLSLTree.h" 5 | 6 | namespace M4 7 | { 8 | 9 | HLSLTree::HLSLTree(Allocator* allocator) : 10 | m_allocator(allocator), m_stringPool(allocator) 11 | { 12 | m_firstPage = m_allocator->New(); 13 | m_firstPage->next = NULL; 14 | 15 | m_currentPage = m_firstPage; 16 | m_currentPageOffset = 0; 17 | 18 | m_root = AddNode(NULL, 1); 19 | } 20 | 21 | HLSLTree::~HLSLTree() 22 | { 23 | NodePage* page = m_firstPage; 24 | while (page != NULL) 25 | { 26 | NodePage* next = page->next; 27 | m_allocator->Delete(page); 28 | page = next; 29 | } 30 | } 31 | 32 | void HLSLTree::AllocatePage() 33 | { 34 | NodePage* newPage = m_allocator->New(); 35 | newPage->next = NULL; 36 | m_currentPage->next = newPage; 37 | m_currentPageOffset = 0; 38 | m_currentPage = newPage; 39 | } 40 | 41 | const char* HLSLTree::AddString(const char* string) 42 | { 43 | return m_stringPool.AddString(string); 44 | } 45 | 46 | const char* HLSLTree::AddStringFormat(const char* format, ...) 47 | { 48 | va_list args; 49 | va_start(args, format); 50 | const char * string = m_stringPool.AddStringFormatList(format, args); 51 | va_end(args); 52 | return string; 53 | } 54 | 55 | bool HLSLTree::GetContainsString(const char* string) const 56 | { 57 | return m_stringPool.GetContainsString(string); 58 | } 59 | 60 | HLSLRoot* HLSLTree::GetRoot() const 61 | { 62 | return m_root; 63 | } 64 | 65 | void* HLSLTree::AllocateMemory(size_t size) 66 | { 67 | if (m_currentPageOffset + size > s_nodePageSize) 68 | { 69 | AllocatePage(); 70 | } 71 | void* buffer = m_currentPage->buffer + m_currentPageOffset; 72 | m_currentPageOffset += size; 73 | return buffer; 74 | } 75 | 76 | // @@ This doesn't do any parameter matching. Simply returns the first function with that name. 77 | HLSLFunction * HLSLTree::FindFunction(const char * name) 78 | { 79 | HLSLStatement * statement = m_root->statement; 80 | while (statement != NULL) 81 | { 82 | if (statement->nodeType == HLSLNodeType_Function) 83 | { 84 | HLSLFunction * function = (HLSLFunction *)statement; 85 | if (String_Equal(name, function->name)) 86 | { 87 | return function; 88 | } 89 | } 90 | 91 | statement = statement->nextStatement; 92 | } 93 | 94 | return NULL; 95 | } 96 | 97 | HLSLDeclaration * HLSLTree::FindGlobalDeclaration(const char * name, HLSLBuffer ** buffer_out/*=NULL*/) 98 | { 99 | HLSLStatement * statement = m_root->statement; 100 | while (statement != NULL) 101 | { 102 | if (statement->nodeType == HLSLNodeType_Declaration) 103 | { 104 | HLSLDeclaration * declaration = (HLSLDeclaration *)statement; 105 | if (String_Equal(name, declaration->name)) 106 | { 107 | if (buffer_out) *buffer_out = NULL; 108 | return declaration; 109 | } 110 | } 111 | else if (statement->nodeType == HLSLNodeType_Buffer) 112 | { 113 | HLSLBuffer* buffer = (HLSLBuffer*)statement; 114 | 115 | HLSLDeclaration* field = buffer->field; 116 | while (field != NULL) 117 | { 118 | ASSERT(field->nodeType == HLSLNodeType_Declaration); 119 | if (String_Equal(name, field->name)) 120 | { 121 | if (buffer_out) *buffer_out = buffer; 122 | return field; 123 | } 124 | field = (HLSLDeclaration*)field->nextStatement; 125 | } 126 | } 127 | 128 | statement = statement->nextStatement; 129 | } 130 | 131 | if (buffer_out) *buffer_out = NULL; 132 | return NULL; 133 | } 134 | 135 | HLSLStruct * HLSLTree::FindGlobalStruct(const char * name) 136 | { 137 | HLSLStatement * statement = m_root->statement; 138 | while (statement != NULL) 139 | { 140 | if (statement->nodeType == HLSLNodeType_Struct) 141 | { 142 | HLSLStruct * declaration = (HLSLStruct *)statement; 143 | if (String_Equal(name, declaration->name)) 144 | { 145 | return declaration; 146 | } 147 | } 148 | 149 | statement = statement->nextStatement; 150 | } 151 | 152 | return NULL; 153 | } 154 | 155 | HLSLTechnique * HLSLTree::FindTechnique(const char * name) 156 | { 157 | HLSLStatement * statement = m_root->statement; 158 | while (statement != NULL) 159 | { 160 | if (statement->nodeType == HLSLNodeType_Technique) 161 | { 162 | HLSLTechnique * technique = (HLSLTechnique *)statement; 163 | if (String_Equal(name, technique->name)) 164 | { 165 | return technique; 166 | } 167 | } 168 | 169 | statement = statement->nextStatement; 170 | } 171 | 172 | return NULL; 173 | } 174 | 175 | HLSLPipeline * HLSLTree::FindFirstPipeline() 176 | { 177 | return FindNextPipeline(NULL); 178 | } 179 | 180 | HLSLPipeline * HLSLTree::FindNextPipeline(HLSLPipeline * current) 181 | { 182 | HLSLStatement * statement = current ? current : m_root->statement; 183 | while (statement != NULL) 184 | { 185 | if (statement->nodeType == HLSLNodeType_Pipeline) 186 | { 187 | return (HLSLPipeline *)statement; 188 | } 189 | 190 | statement = statement->nextStatement; 191 | } 192 | 193 | return NULL; 194 | } 195 | 196 | HLSLPipeline * HLSLTree::FindPipeline(const char * name) 197 | { 198 | HLSLStatement * statement = m_root->statement; 199 | while (statement != NULL) 200 | { 201 | if (statement->nodeType == HLSLNodeType_Pipeline) 202 | { 203 | HLSLPipeline * pipeline = (HLSLPipeline *)statement; 204 | if (String_Equal(name, pipeline->name)) 205 | { 206 | return pipeline; 207 | } 208 | } 209 | 210 | statement = statement->nextStatement; 211 | } 212 | 213 | return NULL; 214 | } 215 | 216 | HLSLBuffer * HLSLTree::FindBuffer(const char * name) 217 | { 218 | HLSLStatement * statement = m_root->statement; 219 | while (statement != NULL) 220 | { 221 | if (statement->nodeType == HLSLNodeType_Buffer) 222 | { 223 | HLSLBuffer * buffer = (HLSLBuffer *)statement; 224 | if (String_Equal(name, buffer->name)) 225 | { 226 | return buffer; 227 | } 228 | } 229 | 230 | statement = statement->nextStatement; 231 | } 232 | 233 | return NULL; 234 | } 235 | 236 | 237 | 238 | bool HLSLTree::GetExpressionValue(HLSLExpression * expression, int & value) 239 | { 240 | ASSERT (expression != NULL); 241 | 242 | // Expression must be constant. 243 | if ((expression->expressionType.flags & HLSLTypeFlag_Const) == 0) 244 | { 245 | return false; 246 | } 247 | 248 | // We are expecting an integer scalar. @@ Add support for type conversion from other scalar types. 249 | if (expression->expressionType.baseType != HLSLBaseType_Int && 250 | expression->expressionType.baseType != HLSLBaseType_Bool) 251 | { 252 | return false; 253 | } 254 | 255 | if (expression->expressionType.array) 256 | { 257 | return false; 258 | } 259 | 260 | if (expression->nodeType == HLSLNodeType_BinaryExpression) 261 | { 262 | HLSLBinaryExpression * binaryExpression = (HLSLBinaryExpression *)expression; 263 | 264 | int value1, value2; 265 | if (!GetExpressionValue(binaryExpression->expression1, value1) || 266 | !GetExpressionValue(binaryExpression->expression2, value2)) 267 | { 268 | return false; 269 | } 270 | 271 | switch(binaryExpression->binaryOp) 272 | { 273 | case HLSLBinaryOp_And: 274 | value = value1 && value2; 275 | return true; 276 | case HLSLBinaryOp_Or: 277 | value = value1 || value2; 278 | return true; 279 | case HLSLBinaryOp_Add: 280 | value = value1 + value2; 281 | return true; 282 | case HLSLBinaryOp_Sub: 283 | value = value1 - value2; 284 | return true; 285 | case HLSLBinaryOp_Mul: 286 | value = value1 * value2; 287 | return true; 288 | case HLSLBinaryOp_Div: 289 | value = value1 / value2; 290 | return true; 291 | case HLSLBinaryOp_Less: 292 | value = value1 < value2; 293 | return true; 294 | case HLSLBinaryOp_Greater: 295 | value = value1 > value2; 296 | return true; 297 | case HLSLBinaryOp_LessEqual: 298 | value = value1 <= value2; 299 | return true; 300 | case HLSLBinaryOp_GreaterEqual: 301 | value = value1 >= value2; 302 | return true; 303 | case HLSLBinaryOp_Equal: 304 | value = value1 == value2; 305 | return true; 306 | case HLSLBinaryOp_NotEqual: 307 | value = value1 != value2; 308 | return true; 309 | case HLSLBinaryOp_BitAnd: 310 | value = value1 & value2; 311 | return true; 312 | case HLSLBinaryOp_BitOr: 313 | value = value1 | value2; 314 | return true; 315 | case HLSLBinaryOp_BitXor: 316 | value = value1 ^ value2; 317 | return true; 318 | case HLSLBinaryOp_Assign: 319 | case HLSLBinaryOp_AddAssign: 320 | case HLSLBinaryOp_SubAssign: 321 | case HLSLBinaryOp_MulAssign: 322 | case HLSLBinaryOp_DivAssign: 323 | // IC: These are not valid on non-constant expressions and should fail earlier when querying expression value. 324 | return false; 325 | } 326 | } 327 | else if (expression->nodeType == HLSLNodeType_UnaryExpression) 328 | { 329 | HLSLUnaryExpression * unaryExpression = (HLSLUnaryExpression *)expression; 330 | 331 | if (!GetExpressionValue(unaryExpression->expression, value)) 332 | { 333 | return false; 334 | } 335 | 336 | switch(unaryExpression->unaryOp) 337 | { 338 | case HLSLUnaryOp_Negative: 339 | value = -value; 340 | return true; 341 | case HLSLUnaryOp_Positive: 342 | // nop. 343 | return true; 344 | case HLSLUnaryOp_Not: 345 | value = !value; 346 | return true; 347 | case HLSLUnaryOp_BitNot: 348 | value = ~value; 349 | return true; 350 | case HLSLUnaryOp_PostDecrement: 351 | case HLSLUnaryOp_PostIncrement: 352 | case HLSLUnaryOp_PreDecrement: 353 | case HLSLUnaryOp_PreIncrement: 354 | // IC: These are not valid on non-constant expressions and should fail earlier when querying expression value. 355 | return false; 356 | } 357 | } 358 | else if (expression->nodeType == HLSLNodeType_IdentifierExpression) 359 | { 360 | HLSLIdentifierExpression * identifier = (HLSLIdentifierExpression *)expression; 361 | 362 | HLSLDeclaration * declaration = FindGlobalDeclaration(identifier->name); 363 | if (declaration == NULL) 364 | { 365 | return false; 366 | } 367 | if ((declaration->type.flags & HLSLTypeFlag_Const) == 0) 368 | { 369 | return false; 370 | } 371 | 372 | return GetExpressionValue(declaration->assignment, value); 373 | } 374 | else if (expression->nodeType == HLSLNodeType_LiteralExpression) 375 | { 376 | HLSLLiteralExpression * literal = (HLSLLiteralExpression *)expression; 377 | 378 | if (literal->expressionType.baseType == HLSLBaseType_Int) value = literal->iValue; 379 | else if (literal->expressionType.baseType == HLSLBaseType_Bool) value = (int)literal->bValue; 380 | else return false; 381 | 382 | return true; 383 | } 384 | 385 | return false; 386 | } 387 | 388 | bool HLSLTree::NeedsFunction(const char* name) 389 | { 390 | // Early out 391 | if (!GetContainsString(name)) 392 | return false; 393 | 394 | struct NeedsFunctionVisitor: HLSLTreeVisitor 395 | { 396 | const char* name; 397 | bool result; 398 | 399 | virtual void VisitTopLevelStatement(HLSLStatement * node) 400 | { 401 | if (!node->hidden) 402 | HLSLTreeVisitor::VisitTopLevelStatement(node); 403 | } 404 | 405 | virtual void VisitFunctionCall(HLSLFunctionCall * node) 406 | { 407 | result = result || String_Equal(name, node->function->name); 408 | 409 | HLSLTreeVisitor::VisitFunctionCall(node); 410 | } 411 | }; 412 | 413 | NeedsFunctionVisitor visitor; 414 | visitor.name = name; 415 | visitor.result = false; 416 | 417 | visitor.VisitRoot(m_root); 418 | 419 | return visitor.result; 420 | } 421 | 422 | int GetVectorDimension(HLSLType & type) 423 | { 424 | if (type.baseType >= HLSLBaseType_FirstNumeric && 425 | type.baseType <= HLSLBaseType_LastNumeric) 426 | { 427 | if (type.baseType == HLSLBaseType_Float || type.baseType == HLSLBaseType_Half) return 1; 428 | if (type.baseType == HLSLBaseType_Float2 || type.baseType == HLSLBaseType_Half2) return 2; 429 | if (type.baseType == HLSLBaseType_Float3 || type.baseType == HLSLBaseType_Half3) return 3; 430 | if (type.baseType == HLSLBaseType_Float4 || type.baseType == HLSLBaseType_Half4) return 4; 431 | 432 | } 433 | return 0; 434 | } 435 | 436 | // Returns dimension, 0 if invalid. 437 | int HLSLTree::GetExpressionValue(HLSLExpression * expression, float values[4]) 438 | { 439 | ASSERT (expression != NULL); 440 | 441 | // Expression must be constant. 442 | if ((expression->expressionType.flags & HLSLTypeFlag_Const) == 0) 443 | { 444 | return 0; 445 | } 446 | 447 | if (expression->expressionType.baseType == HLSLBaseType_Int || 448 | expression->expressionType.baseType == HLSLBaseType_Bool) 449 | { 450 | int int_value; 451 | if (GetExpressionValue(expression, int_value)) { 452 | for (int i = 0; i < 4; i++) values[i] = (float)int_value; // @@ Warn if conversion is not exact. 453 | return 1; 454 | } 455 | 456 | return 0; 457 | } 458 | if (expression->expressionType.baseType >= HLSLBaseType_FirstInteger && expression->expressionType.baseType <= HLSLBaseType_LastInteger) 459 | { 460 | // @@ Add support for uints? 461 | // @@ Add support for int vectors? 462 | return 0; 463 | } 464 | if (expression->expressionType.baseType > HLSLBaseType_LastNumeric) 465 | { 466 | return 0; 467 | } 468 | 469 | // @@ Not supported yet, but we may need it? 470 | if (expression->expressionType.array) 471 | { 472 | return false; 473 | } 474 | 475 | if (expression->nodeType == HLSLNodeType_BinaryExpression) 476 | { 477 | HLSLBinaryExpression * binaryExpression = (HLSLBinaryExpression *)expression; 478 | int dim = GetVectorDimension(binaryExpression->expressionType); 479 | 480 | float values1[4], values2[4]; 481 | int dim1 = GetExpressionValue(binaryExpression->expression1, values1); 482 | int dim2 = GetExpressionValue(binaryExpression->expression2, values2); 483 | 484 | if (dim1 == 0 || dim2 == 0) 485 | { 486 | return 0; 487 | } 488 | 489 | if (dim1 != dim2) 490 | { 491 | // Brodacast scalar to vector size. 492 | if (dim1 == 1) 493 | { 494 | for (int i = 1; i < dim2; i++) values1[i] = values1[0]; 495 | dim1 = dim2; 496 | } 497 | else if (dim2 == 1) 498 | { 499 | for (int i = 1; i < dim1; i++) values2[i] = values2[0]; 500 | dim2 = dim1; 501 | } 502 | else 503 | { 504 | return 0; 505 | } 506 | } 507 | ASSERT(dim == dim1); 508 | 509 | switch(binaryExpression->binaryOp) 510 | { 511 | case HLSLBinaryOp_Add: 512 | for (int i = 0; i < dim; i++) values[i] = values1[i] + values2[i]; 513 | return dim; 514 | case HLSLBinaryOp_Sub: 515 | for (int i = 0; i < dim; i++) values[i] = values1[i] - values2[i]; 516 | return dim; 517 | case HLSLBinaryOp_Mul: 518 | for (int i = 0; i < dim; i++) values[i] = values1[i] * values2[i]; 519 | return dim; 520 | case HLSLBinaryOp_Div: 521 | for (int i = 0; i < dim; i++) values[i] = values1[i] / values2[i]; 522 | return dim; 523 | default: 524 | return 0; 525 | } 526 | } 527 | else if (expression->nodeType == HLSLNodeType_UnaryExpression) 528 | { 529 | HLSLUnaryExpression * unaryExpression = (HLSLUnaryExpression *)expression; 530 | int dim = GetVectorDimension(unaryExpression->expressionType); 531 | 532 | int dim1 = GetExpressionValue(unaryExpression->expression, values); 533 | if (dim1 == 0) 534 | { 535 | return 0; 536 | } 537 | ASSERT(dim == dim1); 538 | 539 | switch(unaryExpression->unaryOp) 540 | { 541 | case HLSLUnaryOp_Negative: 542 | for (int i = 0; i < dim; i++) values[i] = -values[i]; 543 | return dim; 544 | case HLSLUnaryOp_Positive: 545 | // nop. 546 | return dim; 547 | default: 548 | return 0; 549 | } 550 | } 551 | else if (expression->nodeType == HLSLNodeType_ConstructorExpression) 552 | { 553 | HLSLConstructorExpression * constructor = (HLSLConstructorExpression *)expression; 554 | 555 | int dim = GetVectorDimension(constructor->expressionType); 556 | 557 | int idx = 0; 558 | HLSLExpression * arg = constructor->argument; 559 | while (arg != NULL) 560 | { 561 | float tmp[4]; 562 | int n = GetExpressionValue(arg, tmp); 563 | for (int i = 0; i < n; i++) values[idx + i] = tmp[i]; 564 | idx += n; 565 | 566 | arg = arg->nextExpression; 567 | } 568 | ASSERT(dim == idx); 569 | 570 | return dim; 571 | } 572 | else if (expression->nodeType == HLSLNodeType_IdentifierExpression) 573 | { 574 | HLSLIdentifierExpression * identifier = (HLSLIdentifierExpression *)expression; 575 | 576 | HLSLDeclaration * declaration = FindGlobalDeclaration(identifier->name); 577 | if (declaration == NULL) 578 | { 579 | return 0; 580 | } 581 | if ((declaration->type.flags & HLSLTypeFlag_Const) == 0) 582 | { 583 | return 0; 584 | } 585 | 586 | return GetExpressionValue(declaration->assignment, values); 587 | } 588 | else if (expression->nodeType == HLSLNodeType_LiteralExpression) 589 | { 590 | HLSLLiteralExpression * literal = (HLSLLiteralExpression *)expression; 591 | 592 | if (literal->expressionType.baseType == HLSLBaseType_Float) values[0] = literal->fValue; 593 | else if (literal->expressionType.baseType == HLSLBaseType_Half) values[0] = literal->fValue; 594 | else if (literal->expressionType.baseType == HLSLBaseType_Bool) values[0] = literal->bValue; 595 | else if (literal->expressionType.baseType == HLSLBaseType_Int) values[0] = (float)literal->iValue; // @@ Warn if conversion is not exact. 596 | else return 0; 597 | 598 | return 1; 599 | } 600 | 601 | return 0; 602 | } 603 | 604 | 605 | 606 | 607 | void HLSLTreeVisitor::VisitType(HLSLType & type) 608 | { 609 | } 610 | 611 | void HLSLTreeVisitor::VisitRoot(HLSLRoot * root) 612 | { 613 | HLSLStatement * statement = root->statement; 614 | while (statement != NULL) { 615 | VisitTopLevelStatement(statement); 616 | statement = statement->nextStatement; 617 | } 618 | } 619 | 620 | void HLSLTreeVisitor::VisitTopLevelStatement(HLSLStatement * node) 621 | { 622 | if (node->nodeType == HLSLNodeType_Declaration) { 623 | VisitDeclaration((HLSLDeclaration *)node); 624 | } 625 | else if (node->nodeType == HLSLNodeType_Struct) { 626 | VisitStruct((HLSLStruct *)node); 627 | } 628 | else if (node->nodeType == HLSLNodeType_Buffer) { 629 | VisitBuffer((HLSLBuffer *)node); 630 | } 631 | else if (node->nodeType == HLSLNodeType_Function) { 632 | VisitFunction((HLSLFunction *)node); 633 | } 634 | else if (node->nodeType == HLSLNodeType_Technique) { 635 | VisitTechnique((HLSLTechnique *)node); 636 | } 637 | else { 638 | ASSERT(0); 639 | } 640 | } 641 | 642 | void HLSLTreeVisitor::VisitStatements(HLSLStatement * statement) 643 | { 644 | while (statement != NULL) { 645 | VisitStatement(statement); 646 | statement = statement->nextStatement; 647 | } 648 | } 649 | 650 | void HLSLTreeVisitor::VisitStatement(HLSLStatement * node) 651 | { 652 | // Function statements 653 | if (node->nodeType == HLSLNodeType_Declaration) { 654 | VisitDeclaration((HLSLDeclaration *)node); 655 | } 656 | else if (node->nodeType == HLSLNodeType_ExpressionStatement) { 657 | VisitExpressionStatement((HLSLExpressionStatement *)node); 658 | } 659 | else if (node->nodeType == HLSLNodeType_ReturnStatement) { 660 | VisitReturnStatement((HLSLReturnStatement *)node); 661 | } 662 | else if (node->nodeType == HLSLNodeType_DiscardStatement) { 663 | VisitDiscardStatement((HLSLDiscardStatement *)node); 664 | } 665 | else if (node->nodeType == HLSLNodeType_BreakStatement) { 666 | VisitBreakStatement((HLSLBreakStatement *)node); 667 | } 668 | else if (node->nodeType == HLSLNodeType_ContinueStatement) { 669 | VisitContinueStatement((HLSLContinueStatement *)node); 670 | } 671 | else if (node->nodeType == HLSLNodeType_IfStatement) { 672 | VisitIfStatement((HLSLIfStatement *)node); 673 | } 674 | else if (node->nodeType == HLSLNodeType_ForStatement) { 675 | VisitForStatement((HLSLForStatement *)node); 676 | } 677 | else if (node->nodeType == HLSLNodeType_BlockStatement) { 678 | VisitBlockStatement((HLSLBlockStatement *)node); 679 | } 680 | else { 681 | ASSERT(0); 682 | } 683 | } 684 | 685 | void HLSLTreeVisitor::VisitDeclaration(HLSLDeclaration * node) 686 | { 687 | VisitType(node->type); 688 | /*do { 689 | VisitExpression(node->assignment); 690 | node = node->nextDeclaration; 691 | } while (node);*/ 692 | if (node->assignment != NULL) { 693 | VisitExpression(node->assignment); 694 | } 695 | if (node->nextDeclaration != NULL) { 696 | VisitDeclaration(node->nextDeclaration); 697 | } 698 | } 699 | 700 | void HLSLTreeVisitor::VisitStruct(HLSLStruct * node) 701 | { 702 | HLSLStructField * field = node->field; 703 | while (field != NULL) { 704 | VisitStructField(field); 705 | field = field->nextField; 706 | } 707 | } 708 | 709 | void HLSLTreeVisitor::VisitStructField(HLSLStructField * node) 710 | { 711 | VisitType(node->type); 712 | } 713 | 714 | void HLSLTreeVisitor::VisitBuffer(HLSLBuffer * node) 715 | { 716 | HLSLDeclaration * field = node->field; 717 | while (field != NULL) { 718 | ASSERT(field->nodeType == HLSLNodeType_Declaration); 719 | VisitDeclaration(field); 720 | ASSERT(field->nextDeclaration == NULL); 721 | field = (HLSLDeclaration *)field->nextStatement; 722 | } 723 | } 724 | 725 | /*void HLSLTreeVisitor::VisitBufferField(HLSLBufferField * node) 726 | { 727 | VisitType(node->type); 728 | }*/ 729 | 730 | void HLSLTreeVisitor::VisitFunction(HLSLFunction * node) 731 | { 732 | VisitType(node->returnType); 733 | 734 | HLSLArgument * argument = node->argument; 735 | while (argument != NULL) { 736 | VisitArgument(argument); 737 | argument = argument->nextArgument; 738 | } 739 | 740 | VisitStatements(node->statement); 741 | } 742 | 743 | void HLSLTreeVisitor::VisitArgument(HLSLArgument * node) 744 | { 745 | VisitType(node->type); 746 | if (node->defaultValue != NULL) { 747 | VisitExpression(node->defaultValue); 748 | } 749 | } 750 | 751 | void HLSLTreeVisitor::VisitExpressionStatement(HLSLExpressionStatement * node) 752 | { 753 | VisitExpression(node->expression); 754 | } 755 | 756 | void HLSLTreeVisitor::VisitExpression(HLSLExpression * node) 757 | { 758 | VisitType(node->expressionType); 759 | 760 | if (node->nodeType == HLSLNodeType_UnaryExpression) { 761 | VisitUnaryExpression((HLSLUnaryExpression *)node); 762 | } 763 | else if (node->nodeType == HLSLNodeType_BinaryExpression) { 764 | VisitBinaryExpression((HLSLBinaryExpression *)node); 765 | } 766 | else if (node->nodeType == HLSLNodeType_ConditionalExpression) { 767 | VisitConditionalExpression((HLSLConditionalExpression *)node); 768 | } 769 | else if (node->nodeType == HLSLNodeType_CastingExpression) { 770 | VisitCastingExpression((HLSLCastingExpression *)node); 771 | } 772 | else if (node->nodeType == HLSLNodeType_LiteralExpression) { 773 | VisitLiteralExpression((HLSLLiteralExpression *)node); 774 | } 775 | else if (node->nodeType == HLSLNodeType_IdentifierExpression) { 776 | VisitIdentifierExpression((HLSLIdentifierExpression *)node); 777 | } 778 | else if (node->nodeType == HLSLNodeType_ConstructorExpression) { 779 | VisitConstructorExpression((HLSLConstructorExpression *)node); 780 | } 781 | else if (node->nodeType == HLSLNodeType_MemberAccess) { 782 | VisitMemberAccess((HLSLMemberAccess *)node); 783 | } 784 | else if (node->nodeType == HLSLNodeType_ArrayAccess) { 785 | VisitArrayAccess((HLSLArrayAccess *)node); 786 | } 787 | else if (node->nodeType == HLSLNodeType_FunctionCall) { 788 | VisitFunctionCall((HLSLFunctionCall *)node); 789 | } 790 | // Acoget-TODO: This was missing. Did adding it break anything? 791 | else if (node->nodeType == HLSLNodeType_SamplerState) { 792 | VisitSamplerState((HLSLSamplerState *)node); 793 | } 794 | else { 795 | ASSERT(0); 796 | } 797 | } 798 | 799 | void HLSLTreeVisitor::VisitReturnStatement(HLSLReturnStatement * node) 800 | { 801 | VisitExpression(node->expression); 802 | } 803 | 804 | void HLSLTreeVisitor::VisitDiscardStatement(HLSLDiscardStatement * node) {} 805 | void HLSLTreeVisitor::VisitBreakStatement(HLSLBreakStatement * node) {} 806 | void HLSLTreeVisitor::VisitContinueStatement(HLSLContinueStatement * node) {} 807 | 808 | void HLSLTreeVisitor::VisitIfStatement(HLSLIfStatement * node) 809 | { 810 | VisitExpression(node->condition); 811 | VisitStatements(node->statement); 812 | if (node->elseStatement) { 813 | VisitStatements(node->elseStatement); 814 | } 815 | } 816 | 817 | void HLSLTreeVisitor::VisitForStatement(HLSLForStatement * node) 818 | { 819 | if (node->initialization) { 820 | VisitDeclaration(node->initialization); 821 | } 822 | if (node->condition) { 823 | VisitExpression(node->condition); 824 | } 825 | if (node->increment) { 826 | VisitExpression(node->increment); 827 | } 828 | VisitStatements(node->statement); 829 | } 830 | 831 | void HLSLTreeVisitor::VisitBlockStatement(HLSLBlockStatement * node) 832 | { 833 | VisitStatements(node->statement); 834 | } 835 | 836 | void HLSLTreeVisitor::VisitUnaryExpression(HLSLUnaryExpression * node) 837 | { 838 | VisitExpression(node->expression); 839 | } 840 | 841 | void HLSLTreeVisitor::VisitBinaryExpression(HLSLBinaryExpression * node) 842 | { 843 | VisitExpression(node->expression1); 844 | VisitExpression(node->expression2); 845 | } 846 | 847 | void HLSLTreeVisitor::VisitConditionalExpression(HLSLConditionalExpression * node) 848 | { 849 | VisitExpression(node->condition); 850 | VisitExpression(node->falseExpression); 851 | VisitExpression(node->trueExpression); 852 | } 853 | 854 | void HLSLTreeVisitor::VisitCastingExpression(HLSLCastingExpression * node) 855 | { 856 | VisitType(node->type); 857 | VisitExpression(node->expression); 858 | } 859 | 860 | void HLSLTreeVisitor::VisitLiteralExpression(HLSLLiteralExpression * node) {} 861 | void HLSLTreeVisitor::VisitIdentifierExpression(HLSLIdentifierExpression * node) {} 862 | 863 | void HLSLTreeVisitor::VisitConstructorExpression(HLSLConstructorExpression * node) 864 | { 865 | HLSLExpression * argument = node->argument; 866 | while (argument != NULL) { 867 | VisitExpression(argument); 868 | argument = argument->nextExpression; 869 | } 870 | } 871 | 872 | void HLSLTreeVisitor::VisitMemberAccess(HLSLMemberAccess * node) 873 | { 874 | VisitExpression(node->object); 875 | } 876 | 877 | void HLSLTreeVisitor::VisitArrayAccess(HLSLArrayAccess * node) 878 | { 879 | VisitExpression(node->array); 880 | VisitExpression(node->index); 881 | } 882 | 883 | void HLSLTreeVisitor::VisitFunctionCall(HLSLFunctionCall * node) 884 | { 885 | HLSLExpression * argument = node->argument; 886 | while (argument != NULL) { 887 | VisitExpression(argument); 888 | argument = argument->nextExpression; 889 | } 890 | } 891 | 892 | void HLSLTreeVisitor::VisitStateAssignment(HLSLStateAssignment * node) {} 893 | 894 | void HLSLTreeVisitor::VisitSamplerState(HLSLSamplerState * node) 895 | { 896 | HLSLStateAssignment * stateAssignment = node->stateAssignments; 897 | while (stateAssignment != NULL) { 898 | VisitStateAssignment(stateAssignment); 899 | stateAssignment = stateAssignment->nextStateAssignment; 900 | } 901 | } 902 | 903 | void HLSLTreeVisitor::VisitPass(HLSLPass * node) 904 | { 905 | HLSLStateAssignment * stateAssignment = node->stateAssignments; 906 | while (stateAssignment != NULL) { 907 | VisitStateAssignment(stateAssignment); 908 | stateAssignment = stateAssignment->nextStateAssignment; 909 | } 910 | } 911 | 912 | void HLSLTreeVisitor::VisitTechnique(HLSLTechnique * node) 913 | { 914 | HLSLPass * pass = node->passes; 915 | while (pass != NULL) { 916 | VisitPass(pass); 917 | pass = pass->nextPass; 918 | } 919 | } 920 | 921 | void HLSLTreeVisitor::VisitFunctions(HLSLRoot * root) 922 | { 923 | HLSLStatement * statement = root->statement; 924 | while (statement != NULL) { 925 | if (statement->nodeType == HLSLNodeType_Function) { 926 | VisitFunction((HLSLFunction *)statement); 927 | } 928 | 929 | statement = statement->nextStatement; 930 | } 931 | } 932 | 933 | void HLSLTreeVisitor::VisitParameters(HLSLRoot * root) 934 | { 935 | HLSLStatement * statement = root->statement; 936 | while (statement != NULL) { 937 | if (statement->nodeType == HLSLNodeType_Declaration) { 938 | VisitDeclaration((HLSLDeclaration *)statement); 939 | } 940 | 941 | statement = statement->nextStatement; 942 | } 943 | } 944 | 945 | 946 | class ResetHiddenFlagVisitor : public HLSLTreeVisitor 947 | { 948 | public: 949 | virtual void VisitTopLevelStatement(HLSLStatement * statement) 950 | { 951 | statement->hidden = true; 952 | 953 | if (statement->nodeType == HLSLNodeType_Buffer) 954 | { 955 | VisitBuffer((HLSLBuffer*)statement); 956 | } 957 | } 958 | 959 | // Hide buffer fields. 960 | virtual void VisitDeclaration(HLSLDeclaration * node) 961 | { 962 | node->hidden = true; 963 | } 964 | 965 | virtual void VisitArgument(HLSLArgument * node) 966 | { 967 | node->hidden = false; // Arguments are visible by default. 968 | } 969 | }; 970 | 971 | class MarkVisibleStatementsVisitor : public HLSLTreeVisitor 972 | { 973 | public: 974 | HLSLTree * tree; 975 | MarkVisibleStatementsVisitor(HLSLTree * tree) : tree(tree) {} 976 | 977 | virtual void VisitFunction(HLSLFunction * node) 978 | { 979 | node->hidden = false; 980 | HLSLTreeVisitor::VisitFunction(node); 981 | 982 | if (node->forward) 983 | VisitFunction(node->forward); 984 | } 985 | 986 | virtual void VisitFunctionCall(HLSLFunctionCall * node) 987 | { 988 | HLSLTreeVisitor::VisitFunctionCall(node); 989 | 990 | if (node->function->hidden) 991 | { 992 | VisitFunction(const_cast(node->function)); 993 | } 994 | } 995 | 996 | virtual void VisitIdentifierExpression(HLSLIdentifierExpression * node) 997 | { 998 | HLSLTreeVisitor::VisitIdentifierExpression(node); 999 | 1000 | if (node->global) 1001 | { 1002 | HLSLDeclaration * declaration = tree->FindGlobalDeclaration(node->name); 1003 | if (declaration != NULL && declaration->hidden) 1004 | { 1005 | declaration->hidden = false; 1006 | VisitDeclaration(declaration); 1007 | } 1008 | } 1009 | } 1010 | 1011 | virtual void VisitType(HLSLType & type) 1012 | { 1013 | if (type.baseType == HLSLBaseType_UserDefined) 1014 | { 1015 | HLSLStruct * globalStruct = tree->FindGlobalStruct(type.typeName); 1016 | if (globalStruct != NULL) 1017 | { 1018 | globalStruct->hidden = false; 1019 | VisitStruct(globalStruct); 1020 | } 1021 | } 1022 | } 1023 | 1024 | }; 1025 | 1026 | 1027 | void PruneTree(HLSLTree* tree, const char* entryName0, const char* entryName1/*=NULL*/) 1028 | { 1029 | HLSLRoot* root = tree->GetRoot(); 1030 | 1031 | // Reset all flags. 1032 | ResetHiddenFlagVisitor reset; 1033 | reset.VisitRoot(root); 1034 | 1035 | // Mark all the statements necessary for these entrypoints. 1036 | HLSLFunction* entry = tree->FindFunction(entryName0); 1037 | if (entry != NULL) 1038 | { 1039 | MarkVisibleStatementsVisitor mark(tree); 1040 | mark.VisitFunction(entry); 1041 | } 1042 | 1043 | if (entryName1 != NULL) 1044 | { 1045 | entry = tree->FindFunction(entryName1); 1046 | if (entry != NULL) 1047 | { 1048 | MarkVisibleStatementsVisitor mark(tree); 1049 | mark.VisitFunction(entry); 1050 | } 1051 | } 1052 | 1053 | // Mark buffers visible, if any of their fields is visible. 1054 | HLSLStatement * statement = root->statement; 1055 | while (statement != NULL) 1056 | { 1057 | if (statement->nodeType == HLSLNodeType_Buffer) 1058 | { 1059 | HLSLBuffer* buffer = (HLSLBuffer*)statement; 1060 | 1061 | HLSLDeclaration* field = buffer->field; 1062 | while (field != NULL) 1063 | { 1064 | ASSERT(field->nodeType == HLSLNodeType_Declaration); 1065 | if (!field->hidden) 1066 | { 1067 | buffer->hidden = false; 1068 | break; 1069 | } 1070 | field = (HLSLDeclaration*)field->nextStatement; 1071 | } 1072 | } 1073 | 1074 | statement = statement->nextStatement; 1075 | } 1076 | } 1077 | 1078 | 1079 | void SortTree(HLSLTree * tree) 1080 | { 1081 | // Stable sort so that statements are in this order: 1082 | // structs, declarations, functions, techniques. 1083 | // but their relative order is preserved. 1084 | 1085 | HLSLRoot* root = tree->GetRoot(); 1086 | 1087 | HLSLStatement* structs = NULL; 1088 | HLSLStatement* lastStruct = NULL; 1089 | HLSLStatement* constDeclarations = NULL; 1090 | HLSLStatement* lastConstDeclaration = NULL; 1091 | HLSLStatement* declarations = NULL; 1092 | HLSLStatement* lastDeclaration = NULL; 1093 | HLSLStatement* functions = NULL; 1094 | HLSLStatement* lastFunction = NULL; 1095 | HLSLStatement* other = NULL; 1096 | HLSLStatement* lastOther = NULL; 1097 | 1098 | HLSLStatement* statement = root->statement; 1099 | while (statement != NULL) { 1100 | HLSLStatement* nextStatement = statement->nextStatement; 1101 | statement->nextStatement = NULL; 1102 | 1103 | if (statement->nodeType == HLSLNodeType_Struct) { 1104 | if (structs == NULL) structs = statement; 1105 | if (lastStruct != NULL) lastStruct->nextStatement = statement; 1106 | lastStruct = statement; 1107 | } 1108 | else if (statement->nodeType == HLSLNodeType_Declaration || statement->nodeType == HLSLNodeType_Buffer) { 1109 | if (statement->nodeType == HLSLNodeType_Declaration && (((HLSLDeclaration *)statement)->type.flags & HLSLTypeFlag_Const)) { 1110 | if (constDeclarations == NULL) constDeclarations = statement; 1111 | if (lastConstDeclaration != NULL) lastConstDeclaration->nextStatement = statement; 1112 | lastConstDeclaration = statement; 1113 | } 1114 | else { 1115 | if (declarations == NULL) declarations = statement; 1116 | if (lastDeclaration != NULL) lastDeclaration->nextStatement = statement; 1117 | lastDeclaration = statement; 1118 | } 1119 | } 1120 | else if (statement->nodeType == HLSLNodeType_Function) { 1121 | if (functions == NULL) functions = statement; 1122 | if (lastFunction != NULL) lastFunction->nextStatement = statement; 1123 | lastFunction = statement; 1124 | } 1125 | else { 1126 | if (other == NULL) other = statement; 1127 | if (lastOther != NULL) lastOther->nextStatement = statement; 1128 | lastOther = statement; 1129 | } 1130 | 1131 | statement = nextStatement; 1132 | } 1133 | 1134 | // Chain all the statements in the order that we want. 1135 | HLSLStatement * firstStatement = structs; 1136 | HLSLStatement * lastStatement = lastStruct; 1137 | 1138 | if (constDeclarations != NULL) { 1139 | if (firstStatement == NULL) firstStatement = constDeclarations; 1140 | else lastStatement->nextStatement = constDeclarations; 1141 | lastStatement = lastConstDeclaration; 1142 | } 1143 | 1144 | if (declarations != NULL) { 1145 | if (firstStatement == NULL) firstStatement = declarations; 1146 | else lastStatement->nextStatement = declarations; 1147 | lastStatement = lastDeclaration; 1148 | } 1149 | 1150 | if (functions != NULL) { 1151 | if (firstStatement == NULL) firstStatement = functions; 1152 | else lastStatement->nextStatement = functions; 1153 | lastStatement = lastFunction; 1154 | } 1155 | 1156 | if (other != NULL) { 1157 | if (firstStatement == NULL) firstStatement = other; 1158 | else lastStatement->nextStatement = other; 1159 | lastStatement = lastOther; 1160 | } 1161 | 1162 | root->statement = firstStatement; 1163 | } 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | // First and last can be the same. 1170 | void AddStatements(HLSLRoot * root, HLSLStatement * before, HLSLStatement * first, HLSLStatement * last) 1171 | { 1172 | if (before == NULL) { 1173 | last->nextStatement = root->statement; 1174 | root->statement = first; 1175 | } 1176 | else { 1177 | last->nextStatement = before->nextStatement; 1178 | before->nextStatement = first; 1179 | } 1180 | } 1181 | 1182 | void AddSingleStatement(HLSLRoot * root, HLSLStatement * before, HLSLStatement * statement) 1183 | { 1184 | AddStatements(root, before, statement, statement); 1185 | } 1186 | 1187 | 1188 | 1189 | // @@ This is very game-specific. Should be moved to pipeline_parser or somewhere else. 1190 | void GroupParameters(HLSLTree * tree) 1191 | { 1192 | // Sort parameters based on semantic and group them in cbuffers. 1193 | 1194 | HLSLRoot* root = tree->GetRoot(); 1195 | 1196 | HLSLDeclaration * firstPerItemDeclaration = NULL; 1197 | HLSLDeclaration * lastPerItemDeclaration = NULL; 1198 | 1199 | HLSLDeclaration * instanceDataDeclaration = NULL; 1200 | 1201 | HLSLDeclaration * firstPerPassDeclaration = NULL; 1202 | HLSLDeclaration * lastPerPassDeclaration = NULL; 1203 | 1204 | HLSLDeclaration * firstPerItemSampler = NULL; 1205 | HLSLDeclaration * lastPerItemSampler = NULL; 1206 | 1207 | HLSLDeclaration * firstPerPassSampler = NULL; 1208 | HLSLDeclaration * lastPerPassSampler = NULL; 1209 | 1210 | HLSLStatement * statementBeforeBuffers = NULL; 1211 | 1212 | HLSLStatement* previousStatement = NULL; 1213 | HLSLStatement* statement = root->statement; 1214 | while (statement != NULL) 1215 | { 1216 | HLSLStatement* nextStatement = statement->nextStatement; 1217 | 1218 | if (statement->nodeType == HLSLNodeType_Struct) // Do not remove this, or it will mess the else clause below. 1219 | { 1220 | statementBeforeBuffers = statement; 1221 | } 1222 | else if (statement->nodeType == HLSLNodeType_Declaration) 1223 | { 1224 | HLSLDeclaration* declaration = (HLSLDeclaration*)statement; 1225 | 1226 | // We insert buffers after the last const declaration. 1227 | if ((declaration->type.flags & HLSLTypeFlag_Const) != 0) 1228 | { 1229 | statementBeforeBuffers = statement; 1230 | } 1231 | 1232 | // Do not move samplers or static/const parameters. 1233 | if ((declaration->type.flags & (HLSLTypeFlag_Static|HLSLTypeFlag_Const)) == 0) 1234 | { 1235 | // Unlink statement. 1236 | statement->nextStatement = NULL; 1237 | if (previousStatement != NULL) previousStatement->nextStatement = nextStatement; 1238 | else root->statement = nextStatement; 1239 | 1240 | while(declaration != NULL) 1241 | { 1242 | HLSLDeclaration* nextDeclaration = declaration->nextDeclaration; 1243 | 1244 | if (declaration->semantic != NULL && String_EqualNoCase(declaration->semantic, "PER_INSTANCED_ITEM")) 1245 | { 1246 | ASSERT(instanceDataDeclaration == NULL); 1247 | instanceDataDeclaration = declaration; 1248 | } 1249 | else 1250 | { 1251 | // Select group based on type and semantic. 1252 | HLSLDeclaration ** first, ** last; 1253 | if (declaration->semantic == NULL || String_EqualNoCase(declaration->semantic, "PER_ITEM") || String_EqualNoCase(declaration->semantic, "PER_MATERIAL")) 1254 | { 1255 | if (IsSamplerType(declaration->type)) 1256 | { 1257 | first = &firstPerItemSampler; 1258 | last = &lastPerItemSampler; 1259 | } 1260 | else 1261 | { 1262 | first = &firstPerItemDeclaration; 1263 | last = &lastPerItemDeclaration; 1264 | } 1265 | } 1266 | else 1267 | { 1268 | if (IsSamplerType(declaration->type)) 1269 | { 1270 | first = &firstPerPassSampler; 1271 | last = &lastPerPassSampler; 1272 | } 1273 | else 1274 | { 1275 | first = &firstPerPassDeclaration; 1276 | last = &lastPerPassDeclaration; 1277 | } 1278 | } 1279 | 1280 | // Add declaration to new list. 1281 | if (*first == NULL) *first = declaration; 1282 | else (*last)->nextStatement = declaration; 1283 | *last = declaration; 1284 | } 1285 | 1286 | // Unlink from declaration list. 1287 | declaration->nextDeclaration = NULL; 1288 | 1289 | // Reset attributes. 1290 | declaration->registerName = NULL; 1291 | //declaration->semantic = NULL; // @@ Don't do this! 1292 | 1293 | declaration = nextDeclaration; 1294 | } 1295 | } 1296 | } 1297 | /*else 1298 | { 1299 | if (statementBeforeBuffers == NULL) { 1300 | // This is the location where we will insert our buffers. 1301 | statementBeforeBuffers = previousStatement; 1302 | } 1303 | }*/ 1304 | 1305 | if (statement->nextStatement == nextStatement) { 1306 | previousStatement = statement; 1307 | } 1308 | statement = nextStatement; 1309 | } 1310 | 1311 | 1312 | // Add instance data declaration at the end of the per_item buffer. 1313 | if (instanceDataDeclaration != NULL) 1314 | { 1315 | if (firstPerItemDeclaration == NULL) firstPerItemDeclaration = instanceDataDeclaration; 1316 | else lastPerItemDeclaration->nextStatement = instanceDataDeclaration; 1317 | } 1318 | 1319 | 1320 | // Add samplers. 1321 | if (firstPerItemSampler != NULL) { 1322 | AddStatements(root, statementBeforeBuffers, firstPerItemSampler, lastPerItemSampler); 1323 | statementBeforeBuffers = lastPerItemSampler; 1324 | } 1325 | if (firstPerPassSampler != NULL) { 1326 | AddStatements(root, statementBeforeBuffers, firstPerPassSampler, lastPerPassSampler); 1327 | statementBeforeBuffers = lastPerPassSampler; 1328 | } 1329 | 1330 | 1331 | // @@ We are assuming per_item and per_pass buffers don't already exist. @@ We should assert on that. 1332 | 1333 | if (firstPerItemDeclaration != NULL) 1334 | { 1335 | // Create buffer statement. 1336 | HLSLBuffer * perItemBuffer = tree->AddNode(firstPerItemDeclaration->fileName, firstPerItemDeclaration->line-1); 1337 | perItemBuffer->name = tree->AddString("per_item"); 1338 | perItemBuffer->registerName = tree->AddString("b0"); 1339 | perItemBuffer->field = firstPerItemDeclaration; 1340 | 1341 | // Set declaration buffer pointers. 1342 | HLSLDeclaration * field = perItemBuffer->field; 1343 | while (field != NULL) 1344 | { 1345 | field->buffer = perItemBuffer; 1346 | field = (HLSLDeclaration *)field->nextStatement; 1347 | } 1348 | 1349 | // Add buffer to statements. 1350 | AddSingleStatement(root, statementBeforeBuffers, perItemBuffer); 1351 | statementBeforeBuffers = perItemBuffer; 1352 | } 1353 | 1354 | if (firstPerPassDeclaration != NULL) 1355 | { 1356 | // Create buffer statement. 1357 | HLSLBuffer * perPassBuffer = tree->AddNode(firstPerPassDeclaration->fileName, firstPerPassDeclaration->line-1); 1358 | perPassBuffer->name = tree->AddString("per_pass"); 1359 | perPassBuffer->registerName = tree->AddString("b1"); 1360 | perPassBuffer->field = firstPerPassDeclaration; 1361 | 1362 | // Set declaration buffer pointers. 1363 | HLSLDeclaration * field = perPassBuffer->field; 1364 | while (field != NULL) 1365 | { 1366 | field->buffer = perPassBuffer; 1367 | field = (HLSLDeclaration *)field->nextStatement; 1368 | } 1369 | 1370 | // Add buffer to statements. 1371 | AddSingleStatement(root, statementBeforeBuffers, perPassBuffer); 1372 | } 1373 | } 1374 | 1375 | 1376 | class FindArgumentVisitor : public HLSLTreeVisitor 1377 | { 1378 | public: 1379 | bool found; 1380 | const char * name; 1381 | 1382 | FindArgumentVisitor() 1383 | { 1384 | found = false; 1385 | name = NULL; 1386 | } 1387 | 1388 | bool FindArgument(const char * name, HLSLFunction * function) 1389 | { 1390 | this->found = false; 1391 | this->name = name; 1392 | VisitStatements(function->statement); 1393 | return found; 1394 | } 1395 | 1396 | virtual void VisitStatements(HLSLStatement * statement) override 1397 | { 1398 | while (statement != NULL && !found) 1399 | { 1400 | VisitStatement(statement); 1401 | statement = statement->nextStatement; 1402 | } 1403 | } 1404 | 1405 | virtual void VisitIdentifierExpression(HLSLIdentifierExpression * node) override 1406 | { 1407 | if (node->name == name) 1408 | { 1409 | found = true; 1410 | } 1411 | } 1412 | }; 1413 | 1414 | 1415 | void HideUnusedArguments(HLSLFunction * function) 1416 | { 1417 | FindArgumentVisitor visitor; 1418 | 1419 | // For each argument. 1420 | HLSLArgument * arg = function->argument; 1421 | while (arg != NULL) 1422 | { 1423 | if (!visitor.FindArgument(arg->name, function)) 1424 | { 1425 | arg->hidden = true; 1426 | } 1427 | 1428 | arg = arg->nextArgument; 1429 | } 1430 | } 1431 | 1432 | bool EmulateAlphaTest(HLSLTree* tree, const char* entryName, float alphaRef/*=0.5*/) 1433 | { 1434 | // Find all return statements of this entry point. 1435 | HLSLFunction* entry = tree->FindFunction(entryName); 1436 | if (entry != NULL) 1437 | { 1438 | HLSLStatement ** ptr = &entry->statement; 1439 | HLSLStatement * statement = entry->statement; 1440 | while (statement != NULL) 1441 | { 1442 | if (statement->nodeType == HLSLNodeType_ReturnStatement) 1443 | { 1444 | HLSLReturnStatement * returnStatement = (HLSLReturnStatement *)statement; 1445 | HLSLBaseType returnType = returnStatement->expression->expressionType.baseType; 1446 | 1447 | // Build statement: "if (%s.a < 0.5) discard;" 1448 | 1449 | HLSLDiscardStatement * discard = tree->AddNode(statement->fileName, statement->line); 1450 | 1451 | HLSLExpression * alpha = NULL; 1452 | if (returnType == HLSLBaseType_Float4 || returnType == HLSLBaseType_Half4) 1453 | { 1454 | // @@ If return expression is a constructor, grab 4th argument. 1455 | // That's not as easy, since we support 'float4(float3, float)' or 'float4(float, float3)', extracting 1456 | // the latter is not that easy. 1457 | /*if (returnStatement->expression->nodeType == HLSLNodeType_ConstructorExpression) { 1458 | HLSLConstructorExpression * constructor = (HLSLConstructorExpression *)returnStatement->expression; 1459 | //constructor-> 1460 | } 1461 | */ 1462 | 1463 | if (alpha == NULL) { 1464 | HLSLMemberAccess * access = tree->AddNode(statement->fileName, statement->line); 1465 | access->expressionType = HLSLType(HLSLBaseType_Float); 1466 | access->object = returnStatement->expression; // @@ Is reference OK? Or should we clone expression? 1467 | access->field = tree->AddString("a"); 1468 | access->swizzle = true; 1469 | 1470 | alpha = access; 1471 | } 1472 | } 1473 | else if (returnType == HLSLBaseType_Float || returnType == HLSLBaseType_Half) 1474 | { 1475 | alpha = returnStatement->expression; // @@ Is reference OK? Or should we clone expression? 1476 | } 1477 | else { 1478 | return false; 1479 | } 1480 | 1481 | HLSLLiteralExpression * threshold = tree->AddNode(statement->fileName, statement->line); 1482 | threshold->expressionType = HLSLType(HLSLBaseType_Float); 1483 | threshold->fValue = alphaRef; 1484 | threshold->type = HLSLBaseType_Float; 1485 | 1486 | HLSLBinaryExpression * condition = tree->AddNode(statement->fileName, statement->line); 1487 | condition->expressionType = HLSLType(HLSLBaseType_Bool); 1488 | condition->binaryOp = HLSLBinaryOp_Less; 1489 | condition->expression1 = alpha; 1490 | condition->expression2 = threshold; 1491 | 1492 | // Insert statement. 1493 | HLSLIfStatement * st = tree->AddNode(statement->fileName, statement->line); 1494 | st->condition = condition; 1495 | st->statement = discard; 1496 | st->nextStatement = statement; 1497 | *ptr = st; 1498 | } 1499 | 1500 | ptr = &statement->nextStatement; 1501 | statement = statement->nextStatement; 1502 | } 1503 | } 1504 | 1505 | return true; 1506 | } 1507 | 1508 | } // M4 1509 | 1510 | --------------------------------------------------------------------------------