├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── hlslparser.sln ├── hlslparser.vcxproj ├── hlslparser.vcxproj.filters ├── premake4.lua └── src ├── CodeWriter.cpp ├── CodeWriter.h ├── Engine.cpp ├── Engine.h ├── GLSLGenerator.cpp ├── GLSLGenerator.h ├── HLSLGenerator.cpp ├── HLSLGenerator.h ├── HLSLParser.cpp ├── HLSLParser.h ├── HLSLTokenizer.cpp ├── HLSLTokenizer.h ├── HLSLTree.cpp ├── HLSLTree.h ├── MSLGenerator.cpp ├── MSLGenerator.h └── Main.cpp /.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 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - linux 3 | - osx 4 | sudo: required 5 | dist: trusty 6 | language: cpp 7 | script: make 8 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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" } -------------------------------------------------------------------------------- /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/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 -------------------------------------------------------------------------------- /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/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 | #define assert(...) 24 | 25 | namespace M4 { 26 | 27 | 28 | // Engine/Allocator.h 29 | 30 | class Allocator { 31 | public: 32 | template T * New() { 33 | return (T *)malloc(sizeof(T)); 34 | } 35 | template T * New(size_t count) { 36 | return (T *)malloc(sizeof(T) * count); 37 | } 38 | template void Delete(T * ptr) { 39 | free((void *)ptr); 40 | } 41 | template T * Realloc(T * ptr, size_t count) { 42 | return (T *)realloc(ptr, sizeof(T) * count); 43 | } 44 | }; 45 | 46 | 47 | // Engine/String.h 48 | 49 | int String_Printf(char * buffer, int size, const char * format, ...); 50 | int String_PrintfArgList(char * buffer, int size, const char * format, va_list args); 51 | int String_FormatFloat(char * buffer, int size, float value); 52 | bool String_Equal(const char * a, const char * b); 53 | bool String_EqualNoCase(const char * a, const char * b); 54 | double String_ToDouble(const char * str, char ** end); 55 | int String_ToInteger(const char * str, char ** end); 56 | 57 | 58 | // Engine/Log.h 59 | 60 | void Log_Error(const char * format, ...); 61 | void Log_ErrorArgList(const char * format, va_list args); 62 | 63 | 64 | // Engine/Array.h 65 | 66 | template 67 | void ConstructRange(T * buffer, int new_size, int old_size) { 68 | for (int i = old_size; i < new_size; i++) { 69 | new(buffer+i) T; // placement new 70 | } 71 | } 72 | 73 | template 74 | void ConstructRange(T * buffer, int new_size, int old_size, const T & val) { 75 | for (int i = old_size; i < new_size; i++) { 76 | new(buffer+i) T(val); // placement new 77 | } 78 | } 79 | 80 | template 81 | void DestroyRange(T * buffer, int new_size, int old_size) { 82 | for (int i = new_size; i < old_size; i++) { 83 | (buffer+i)->~T(); // Explicit call to the destructor 84 | } 85 | } 86 | 87 | 88 | template 89 | class Array { 90 | public: 91 | Array(Allocator * allocator) : allocator(allocator), buffer(NULL), size(0), capacity(0) {} 92 | 93 | void PushBack(const T & val) { 94 | ASSERT(&val < buffer || &val >= buffer+size); 95 | 96 | int old_size = size; 97 | int new_size = size + 1; 98 | 99 | SetSize(new_size); 100 | 101 | ConstructRange(buffer, new_size, old_size, val); 102 | } 103 | T & PushBackNew() { 104 | int old_size = size; 105 | int new_size = size + 1; 106 | 107 | SetSize(new_size); 108 | 109 | ConstructRange(buffer, new_size, old_size); 110 | 111 | return buffer[old_size]; 112 | } 113 | void Resize(int new_size) { 114 | int old_size = size; 115 | 116 | DestroyRange(buffer, new_size, old_size); 117 | 118 | SetSize(new_size); 119 | 120 | ConstructRange(buffer, new_size, old_size); 121 | } 122 | 123 | int GetSize() const { return size; } 124 | const T & operator[](int i) const { ASSERT(i < size); return buffer[i]; } 125 | T & operator[](int i) { ASSERT(i < size); return buffer[i]; } 126 | 127 | private: 128 | 129 | // Change array size. 130 | void SetSize(int new_size) { 131 | size = new_size; 132 | 133 | if (new_size > capacity) { 134 | int new_buffer_size; 135 | if (capacity == 0) { 136 | // first allocation is exact 137 | new_buffer_size = new_size; 138 | } 139 | else { 140 | // following allocations grow array by 25% 141 | new_buffer_size = new_size + (new_size >> 2); 142 | } 143 | 144 | SetCapacity(new_buffer_size); 145 | } 146 | } 147 | 148 | // Change array capacity. 149 | void SetCapacity(int new_capacity) { 150 | ASSERT(new_capacity >= size); 151 | 152 | if (new_capacity == 0) { 153 | // free the buffer. 154 | if (buffer != NULL) { 155 | allocator->Delete(buffer); 156 | buffer = NULL; 157 | } 158 | } 159 | else { 160 | // realloc the buffer 161 | buffer = allocator->Realloc(buffer, new_capacity); 162 | } 163 | 164 | capacity = new_capacity; 165 | } 166 | 167 | 168 | private: 169 | Allocator * allocator; // @@ Do we really have to keep a pointer to this? 170 | T * buffer; 171 | int size; 172 | int capacity; 173 | }; 174 | 175 | 176 | // Engine/StringPool.h 177 | 178 | // @@ Implement this with a hash table! 179 | struct StringPool { 180 | StringPool(Allocator * allocator); 181 | ~StringPool(); 182 | 183 | const char * AddString(const char * string); 184 | const char * AddStringFormat(const char * fmt, ...); 185 | const char * AddStringFormatList(const char * fmt, va_list args); 186 | bool GetContainsString(const char * string) const; 187 | 188 | Array stringArray; 189 | }; 190 | 191 | 192 | } // M4 namespace 193 | 194 | #endif // ENGINE_H 195 | -------------------------------------------------------------------------------- /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/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 "float"; 36 | case HLSLBaseType_Half2: return "float2"; 37 | case HLSLBaseType_Half3: return "float3"; 38 | case HLSLBaseType_Half4: return "float4"; 39 | case HLSLBaseType_Half2x2: return "float2x2"; 40 | case HLSLBaseType_Half3x3: return "float3x3"; 41 | case HLSLBaseType_Half4x4: return "float4x4"; 42 | case HLSLBaseType_Half4x3: return "float4x3"; 43 | case HLSLBaseType_Half4x2: return "float4x2"; 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 | default: 754 | break; 755 | } 756 | 757 | const char * semantic = argument->sv_semantic ? argument->sv_semantic : argument->semantic; 758 | 759 | OutputDeclaration(argument->type, argument->name, semantic, /*registerName=*/NULL, argument->defaultValue); 760 | argument = argument->nextArgument; 761 | ++numArgs; 762 | } 763 | } 764 | 765 | static const char * GetAttributeName(HLSLAttributeType attributeType) 766 | { 767 | if (attributeType == HLSLAttributeType_Unroll) return "unroll"; 768 | if (attributeType == HLSLAttributeType_Branch) return "branch"; 769 | if (attributeType == HLSLAttributeType_Flatten) return "flatten"; 770 | return NULL; 771 | } 772 | 773 | void HLSLGenerator::OutputAttributes(int indent, HLSLAttribute* attribute) 774 | { 775 | while (attribute != NULL) 776 | { 777 | const char * attributeName = GetAttributeName(attribute->attributeType); 778 | 779 | if (attributeName != NULL) 780 | { 781 | m_writer.WriteLineTagged(indent, attribute->fileName, attribute->line, "[%s]", attributeName); 782 | } 783 | 784 | attribute = attribute->nextAttribute; 785 | } 786 | } 787 | 788 | void HLSLGenerator::OutputStatements(int indent, HLSLStatement* statement) 789 | { 790 | while (statement != NULL) 791 | { 792 | if (statement->hidden) 793 | { 794 | statement = statement->nextStatement; 795 | continue; 796 | } 797 | 798 | OutputAttributes(indent, statement->attributes); 799 | 800 | if (statement->nodeType == HLSLNodeType_Declaration) 801 | { 802 | HLSLDeclaration* declaration = static_cast(statement); 803 | m_writer.BeginLine(indent, declaration->fileName, declaration->line); 804 | OutputDeclaration(declaration); 805 | m_writer.EndLine(";"); 806 | } 807 | else if (statement->nodeType == HLSLNodeType_Struct) 808 | { 809 | HLSLStruct* structure = static_cast(statement); 810 | m_writer.WriteLineTagged(indent, structure->fileName, structure->line, "struct %s {", structure->name); 811 | HLSLStructField* field = structure->field; 812 | while (field != NULL) 813 | { 814 | if (!field->hidden) 815 | { 816 | m_writer.BeginLine(indent + 1, field->fileName, field->line); 817 | const char * semantic = field->sv_semantic ? field->sv_semantic : field->semantic; 818 | OutputDeclaration(field->type, field->name, semantic); 819 | m_writer.Write(";"); 820 | m_writer.EndLine(); 821 | } 822 | field = field->nextField; 823 | } 824 | m_writer.WriteLine(indent, "};"); 825 | } 826 | else if (statement->nodeType == HLSLNodeType_Buffer) 827 | { 828 | HLSLBuffer* buffer = static_cast(statement); 829 | HLSLDeclaration* field = buffer->field; 830 | 831 | if (!m_legacy) 832 | { 833 | m_writer.BeginLine(indent, buffer->fileName, buffer->line); 834 | m_writer.Write("cbuffer %s", buffer->name); 835 | if (buffer->registerName != NULL) 836 | { 837 | m_writer.Write(" : register(%s)", buffer->registerName); 838 | } 839 | m_writer.EndLine(" {"); 840 | } 841 | 842 | m_isInsideBuffer = true; 843 | 844 | while (field != NULL) 845 | { 846 | if (!field->hidden) 847 | { 848 | m_writer.BeginLine(indent + 1, field->fileName, field->line); 849 | OutputDeclaration(field->type, field->name, /*semantic=*/NULL, /*registerName*/field->registerName, field->assignment); 850 | m_writer.Write(";"); 851 | m_writer.EndLine(); 852 | } 853 | field = (HLSLDeclaration*)field->nextStatement; 854 | } 855 | 856 | m_isInsideBuffer = false; 857 | 858 | if (!m_legacy) 859 | { 860 | m_writer.WriteLine(indent, "};"); 861 | } 862 | } 863 | else if (statement->nodeType == HLSLNodeType_Function) 864 | { 865 | HLSLFunction* function = static_cast(statement); 866 | 867 | // Use an alternate name for the function which is supposed to be entry point 868 | // so that we can supply our own function which will be the actual entry point. 869 | const char* functionName = function->name; 870 | const char* returnTypeName = GetTypeName(function->returnType); 871 | 872 | m_writer.BeginLine(indent, function->fileName, function->line); 873 | m_writer.Write("%s %s(", returnTypeName, functionName); 874 | 875 | OutputArguments(function->argument); 876 | 877 | const char * semantic = function->sv_semantic ? function->sv_semantic : function->semantic; 878 | if (semantic != NULL) 879 | { 880 | m_writer.Write(") : %s {", semantic); 881 | } 882 | else 883 | { 884 | m_writer.Write(") {"); 885 | } 886 | 887 | m_writer.EndLine(); 888 | 889 | OutputStatements(indent + 1, function->statement); 890 | m_writer.WriteLine(indent, "};"); 891 | } 892 | else if (statement->nodeType == HLSLNodeType_ExpressionStatement) 893 | { 894 | HLSLExpressionStatement* expressionStatement = static_cast(statement); 895 | m_writer.BeginLine(indent, statement->fileName, statement->line); 896 | OutputExpression(expressionStatement->expression); 897 | m_writer.EndLine(";"); 898 | } 899 | else if (statement->nodeType == HLSLNodeType_ReturnStatement) 900 | { 901 | HLSLReturnStatement* returnStatement = static_cast(statement); 902 | if (returnStatement->expression != NULL) 903 | { 904 | m_writer.BeginLine(indent, returnStatement->fileName, returnStatement->line); 905 | m_writer.Write("return "); 906 | OutputExpression(returnStatement->expression); 907 | m_writer.EndLine(";"); 908 | } 909 | else 910 | { 911 | m_writer.WriteLineTagged(indent, returnStatement->fileName, returnStatement->line, "return;"); 912 | } 913 | } 914 | else if (statement->nodeType == HLSLNodeType_DiscardStatement) 915 | { 916 | HLSLDiscardStatement* discardStatement = static_cast(statement); 917 | m_writer.WriteLineTagged(indent, discardStatement->fileName, discardStatement->line, "discard;"); 918 | } 919 | else if (statement->nodeType == HLSLNodeType_BreakStatement) 920 | { 921 | HLSLBreakStatement* breakStatement = static_cast(statement); 922 | m_writer.WriteLineTagged(indent, breakStatement->fileName, breakStatement->line, "break;"); 923 | } 924 | else if (statement->nodeType == HLSLNodeType_ContinueStatement) 925 | { 926 | HLSLContinueStatement* continueStatement = static_cast(statement); 927 | m_writer.WriteLineTagged(indent, continueStatement->fileName, continueStatement->line, "continue;"); 928 | } 929 | else if (statement->nodeType == HLSLNodeType_IfStatement) 930 | { 931 | HLSLIfStatement* ifStatement = static_cast(statement); 932 | m_writer.BeginLine(indent, ifStatement->fileName, ifStatement->line); 933 | m_writer.Write("if ("); 934 | OutputExpression(ifStatement->condition); 935 | m_writer.Write(") {"); 936 | m_writer.EndLine(); 937 | OutputStatements(indent + 1, ifStatement->statement); 938 | m_writer.WriteLine(indent, "}"); 939 | if (ifStatement->elseStatement != NULL) 940 | { 941 | m_writer.WriteLine(indent, "else {"); 942 | OutputStatements(indent + 1, ifStatement->elseStatement); 943 | m_writer.WriteLine(indent, "}"); 944 | } 945 | } 946 | else if (statement->nodeType == HLSLNodeType_ForStatement) 947 | { 948 | HLSLForStatement* forStatement = static_cast(statement); 949 | m_writer.BeginLine(indent, forStatement->fileName, forStatement->line); 950 | m_writer.Write("for ("); 951 | OutputDeclaration(forStatement->initialization); 952 | m_writer.Write("; "); 953 | OutputExpression(forStatement->condition); 954 | m_writer.Write("; "); 955 | OutputExpression(forStatement->increment); 956 | m_writer.Write(") {"); 957 | m_writer.EndLine(); 958 | OutputStatements(indent + 1, forStatement->statement); 959 | m_writer.WriteLine(indent, "}"); 960 | } 961 | else if (statement->nodeType == HLSLNodeType_BlockStatement) 962 | { 963 | HLSLBlockStatement* blockStatement = static_cast(statement); 964 | m_writer.WriteLineTagged(indent, blockStatement->fileName, blockStatement->line, "{"); 965 | OutputStatements(indent + 1, blockStatement->statement); 966 | m_writer.WriteLine(indent, "}"); 967 | } 968 | else if (statement->nodeType == HLSLNodeType_Technique) 969 | { 970 | // Techniques are ignored. 971 | } 972 | else if (statement->nodeType == HLSLNodeType_Pipeline) 973 | { 974 | // Pipelines are ignored. 975 | } 976 | else 977 | { 978 | // Unhanded statement type. 979 | ASSERT(0); 980 | } 981 | 982 | statement = statement->nextStatement; 983 | } 984 | } 985 | 986 | void HLSLGenerator::OutputDeclaration(HLSLDeclaration* declaration) 987 | { 988 | bool isSamplerType = IsSamplerType(declaration->type); 989 | 990 | if (!m_legacy && isSamplerType) 991 | { 992 | int reg = -1; 993 | if (declaration->registerName != NULL) 994 | { 995 | sscanf(declaration->registerName, "s%d", ®); 996 | } 997 | 998 | const char* textureType = NULL; 999 | const char* samplerType = "SamplerState"; 1000 | // @@ Handle generic sampler type. 1001 | 1002 | if (declaration->type.baseType == HLSLBaseType_Sampler2D) 1003 | { 1004 | textureType = "Texture2D"; 1005 | } 1006 | else if (declaration->type.baseType == HLSLBaseType_Sampler3D) 1007 | { 1008 | textureType = "Texture3D"; 1009 | } 1010 | else if (declaration->type.baseType == HLSLBaseType_SamplerCube) 1011 | { 1012 | textureType = "TextureCube"; 1013 | } 1014 | else if (declaration->type.baseType == HLSLBaseType_Sampler2DShadow) 1015 | { 1016 | textureType = "Texture2D"; 1017 | samplerType = "SamplerComparisonState"; 1018 | } 1019 | else if (declaration->type.baseType == HLSLBaseType_Sampler2DMS) 1020 | { 1021 | textureType = "Texture2DMS"; // @@ Is template argument required? 1022 | samplerType = NULL; 1023 | } 1024 | 1025 | if (samplerType != NULL) 1026 | { 1027 | if (reg != -1) 1028 | { 1029 | m_writer.Write("%s %s_texture : register(t%d); %s %s_sampler : register(s%d)", textureType, declaration->name, reg, samplerType, declaration->name, reg); 1030 | } 1031 | else 1032 | { 1033 | m_writer.Write("%s %s_texture; %s %s_sampler", textureType, declaration->name, samplerType, declaration->name); 1034 | } 1035 | } 1036 | else 1037 | { 1038 | if (reg != -1) 1039 | { 1040 | m_writer.Write("%s %s : register(t%d)", textureType, declaration->name, reg); 1041 | } 1042 | else 1043 | { 1044 | m_writer.Write("%s %s", textureType, declaration->name); 1045 | } 1046 | } 1047 | return; 1048 | } 1049 | 1050 | OutputDeclarationType(declaration->type); 1051 | OutputDeclarationBody(declaration->type, declaration->name, declaration->semantic, declaration->registerName, declaration->assignment); 1052 | declaration = declaration->nextDeclaration; 1053 | 1054 | while(declaration != NULL) { 1055 | m_writer.Write(", "); 1056 | OutputDeclarationBody(declaration->type, declaration->name, declaration->semantic, declaration->registerName, declaration->assignment); 1057 | declaration = declaration->nextDeclaration; 1058 | }; 1059 | } 1060 | 1061 | void HLSLGenerator::OutputDeclarationType(const HLSLType& type) 1062 | { 1063 | const char* typeName = GetTypeName(type); 1064 | if (!m_legacy) 1065 | { 1066 | if (type.baseType == HLSLBaseType_Sampler2D) 1067 | { 1068 | typeName = m_textureSampler2DStruct; 1069 | } 1070 | else if (type.baseType == HLSLBaseType_Sampler3D) 1071 | { 1072 | typeName = m_textureSampler3DStruct; 1073 | } 1074 | else if (type.baseType == HLSLBaseType_SamplerCube) 1075 | { 1076 | typeName = m_textureSamplerCubeStruct; 1077 | } 1078 | else if (type.baseType == HLSLBaseType_Sampler2DShadow) 1079 | { 1080 | typeName = m_textureSampler2DShadowStruct; 1081 | } 1082 | else if (type.baseType == HLSLBaseType_Sampler2DMS) 1083 | { 1084 | typeName = "Texture2DMS"; 1085 | } 1086 | } 1087 | 1088 | if (type.flags & HLSLTypeFlag_Const) 1089 | { 1090 | m_writer.Write("const "); 1091 | } 1092 | if (type.flags & HLSLTypeFlag_Static) 1093 | { 1094 | m_writer.Write("static "); 1095 | } 1096 | 1097 | // Interpolation modifiers. 1098 | if (type.flags & HLSLTypeFlag_Centroid) 1099 | { 1100 | m_writer.Write("centroid "); 1101 | } 1102 | if (type.flags & HLSLTypeFlag_Linear) 1103 | { 1104 | m_writer.Write("linear "); 1105 | } 1106 | if (type.flags & HLSLTypeFlag_NoInterpolation) 1107 | { 1108 | m_writer.Write("nointerpolation "); 1109 | } 1110 | if (type.flags & HLSLTypeFlag_NoPerspective) 1111 | { 1112 | m_writer.Write("noperspective "); 1113 | } 1114 | if (type.flags & HLSLTypeFlag_Sample) // @@ Only in shader model >= 4.1 1115 | { 1116 | m_writer.Write("sample "); 1117 | } 1118 | 1119 | m_writer.Write("%s ", typeName); 1120 | } 1121 | 1122 | void HLSLGenerator::OutputDeclarationBody(const HLSLType& type, const char* name, const char* semantic/*=NULL*/, const char* registerName/*=NULL*/, HLSLExpression * assignment/*=NULL*/) 1123 | { 1124 | m_writer.Write("%s", name); 1125 | 1126 | if (type.array) 1127 | { 1128 | ASSERT(semantic == NULL); 1129 | m_writer.Write("["); 1130 | if (type.arraySize != NULL) 1131 | { 1132 | OutputExpression(type.arraySize); 1133 | } 1134 | m_writer.Write("]"); 1135 | } 1136 | 1137 | if (semantic != NULL) 1138 | { 1139 | m_writer.Write(" : %s", semantic); 1140 | } 1141 | 1142 | if (registerName != NULL) 1143 | { 1144 | if (m_isInsideBuffer) 1145 | { 1146 | m_writer.Write(" : packoffset(%s)", registerName); 1147 | } 1148 | else 1149 | { 1150 | m_writer.Write(" : register(%s)", registerName); 1151 | } 1152 | } 1153 | 1154 | if (assignment != NULL && !IsSamplerType(type)) 1155 | { 1156 | m_writer.Write(" = "); 1157 | if (type.array) 1158 | { 1159 | m_writer.Write("{ "); 1160 | OutputExpressionList(assignment); 1161 | m_writer.Write(" }"); 1162 | } 1163 | else 1164 | { 1165 | OutputExpression(assignment); 1166 | } 1167 | } 1168 | } 1169 | 1170 | void HLSLGenerator::OutputDeclaration(const HLSLType& type, const char* name, const char* semantic/*=NULL*/, const char* registerName/*=NULL*/, HLSLExpression * assignment/*=NULL*/) 1171 | { 1172 | OutputDeclarationType(type); 1173 | OutputDeclarationBody(type, name, semantic, registerName, assignment); 1174 | } 1175 | 1176 | bool HLSLGenerator::ChooseUniqueName(const char* base, char* dst, int dstLength) const 1177 | { 1178 | // IC: Try without suffix first. 1179 | String_Printf(dst, dstLength, "%s", base); 1180 | if (!m_tree->GetContainsString(base)) 1181 | { 1182 | return true; 1183 | } 1184 | 1185 | for (int i = 1; i < 1024; ++i) 1186 | { 1187 | String_Printf(dst, dstLength, "%s%d", base, i); 1188 | if (!m_tree->GetContainsString(dst)) 1189 | { 1190 | return true; 1191 | } 1192 | } 1193 | return false; 1194 | } 1195 | 1196 | } 1197 | -------------------------------------------------------------------------------- /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/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, HLSLType& type); 53 | bool ExpectType(bool allowVoid, HLSLType& type); 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, bool scoped = true); 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, int& numOutputArguments); 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 | bool m_allowUndeclaredIdentifiers = false; 140 | bool m_disableSemanticValidation = false; 141 | }; 142 | 143 | } 144 | 145 | #endif 146 | -------------------------------------------------------------------------------- /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 | case '@': 103 | return true; 104 | } 105 | return false; 106 | } 107 | 108 | /** Returns true if the character is a valid token separator at the end of a number type token */ 109 | static bool GetIsNumberSeparator(char c) 110 | { 111 | return c == 0 || isspace(c) || GetIsSymbol(c); 112 | } 113 | 114 | HLSLTokenizer::HLSLTokenizer(const char* fileName, const char* buffer, size_t length) 115 | { 116 | m_buffer = buffer; 117 | m_bufferEnd = buffer + length; 118 | m_fileName = fileName; 119 | m_lineNumber = 1; 120 | m_tokenLineNumber = 1; 121 | m_error = false; 122 | Next(); 123 | } 124 | 125 | void HLSLTokenizer::Next() 126 | { 127 | 128 | while( SkipWhitespace() || SkipComment() || ScanLineDirective() || SkipPragmaDirective() ) 129 | { 130 | } 131 | 132 | if (m_error) 133 | { 134 | m_token = HLSLToken_EndOfStream; 135 | return; 136 | } 137 | 138 | m_tokenLineNumber = m_lineNumber; 139 | 140 | if (m_buffer >= m_bufferEnd || *m_buffer == '\0') 141 | { 142 | m_token = HLSLToken_EndOfStream; 143 | return; 144 | } 145 | 146 | const char* start = m_buffer; 147 | 148 | // +=, -=, *=, /=, ==, <=, >= 149 | if (m_buffer[0] == '+' && m_buffer[1] == '=') 150 | { 151 | m_token = HLSLToken_PlusEqual; 152 | m_buffer += 2; 153 | return; 154 | } 155 | else if (m_buffer[0] == '-' && m_buffer[1] == '=') 156 | { 157 | m_token = HLSLToken_MinusEqual; 158 | m_buffer += 2; 159 | return; 160 | } 161 | else if (m_buffer[0] == '*' && m_buffer[1] == '=') 162 | { 163 | m_token = HLSLToken_TimesEqual; 164 | m_buffer += 2; 165 | return; 166 | } 167 | else if (m_buffer[0] == '/' && m_buffer[1] == '=') 168 | { 169 | m_token = HLSLToken_DivideEqual; 170 | m_buffer += 2; 171 | return; 172 | } 173 | else if (m_buffer[0] == '=' && m_buffer[1] == '=') 174 | { 175 | m_token = HLSLToken_EqualEqual; 176 | m_buffer += 2; 177 | return; 178 | } 179 | else if (m_buffer[0] == '!' && m_buffer[1] == '=') 180 | { 181 | m_token = HLSLToken_NotEqual; 182 | m_buffer += 2; 183 | return; 184 | } 185 | else if (m_buffer[0] == '<' && m_buffer[1] == '=') 186 | { 187 | m_token = HLSLToken_LessEqual; 188 | m_buffer += 2; 189 | return; 190 | } 191 | else if (m_buffer[0] == '>' && m_buffer[1] == '=') 192 | { 193 | m_token = HLSLToken_GreaterEqual; 194 | m_buffer += 2; 195 | return; 196 | } 197 | else if (m_buffer[0] == '&' && m_buffer[1] == '&') 198 | { 199 | m_token = HLSLToken_AndAnd; 200 | m_buffer += 2; 201 | return; 202 | } 203 | else if (m_buffer[0] == '|' && m_buffer[1] == '|') 204 | { 205 | m_token = HLSLToken_BarBar; 206 | m_buffer += 2; 207 | return; 208 | } 209 | 210 | // ++, -- 211 | if ((m_buffer[0] == '-' || m_buffer[0] == '+') && (m_buffer[1] == m_buffer[0])) 212 | { 213 | m_token = (m_buffer[0] == '+') ? HLSLToken_PlusPlus : HLSLToken_MinusMinus; 214 | m_buffer += 2; 215 | return; 216 | } 217 | 218 | // Check for the start of a number. 219 | if (ScanNumber()) 220 | { 221 | return; 222 | } 223 | 224 | if (GetIsSymbol(m_buffer[0])) 225 | { 226 | m_token = static_cast(m_buffer[0]); 227 | ++m_buffer; 228 | return; 229 | } 230 | 231 | // Must be an identifier or a reserved word. 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/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 173 | -------------------------------------------------------------------------------- /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 HLSLTypeDimension 51 | { 52 | HLSLTypeDimension_None, 53 | HLSLTypeDimension_Scalar, 54 | HLSLTypeDimension_Vector2, 55 | HLSLTypeDimension_Vector3, 56 | HLSLTypeDimension_Vector4, 57 | HLSLTypeDimension_Matrix2x2, 58 | HLSLTypeDimension_Matrix3x3, 59 | HLSLTypeDimension_Matrix4x4, 60 | HLSLTypeDimension_Matrix4x3, 61 | HLSLTypeDimension_Matrix4x2 62 | }; 63 | 64 | enum HLSLBaseType 65 | { 66 | HLSLBaseType_Unknown, 67 | HLSLBaseType_Void, 68 | HLSLBaseType_Float, 69 | HLSLBaseType_FirstNumeric = HLSLBaseType_Float, 70 | HLSLBaseType_Float2, 71 | HLSLBaseType_Float3, 72 | HLSLBaseType_Float4, 73 | HLSLBaseType_Float2x2, 74 | HLSLBaseType_Float3x3, 75 | HLSLBaseType_Float4x4, 76 | HLSLBaseType_Float4x3, 77 | HLSLBaseType_Float4x2, 78 | HLSLBaseType_Half, 79 | HLSLBaseType_Half2, 80 | HLSLBaseType_Half3, 81 | HLSLBaseType_Half4, 82 | HLSLBaseType_Half2x2, 83 | HLSLBaseType_Half3x3, 84 | HLSLBaseType_Half4x4, 85 | HLSLBaseType_Half4x3, 86 | HLSLBaseType_Half4x2, 87 | HLSLBaseType_Bool, 88 | HLSLBaseType_FirstInteger = HLSLBaseType_Bool, 89 | HLSLBaseType_Bool2, 90 | HLSLBaseType_Bool3, 91 | HLSLBaseType_Bool4, 92 | HLSLBaseType_Int, 93 | HLSLBaseType_Int2, 94 | HLSLBaseType_Int3, 95 | HLSLBaseType_Int4, 96 | HLSLBaseType_Uint, 97 | HLSLBaseType_Uint2, 98 | HLSLBaseType_Uint3, 99 | HLSLBaseType_Uint4, 100 | /*HLSLBaseType_Short, // @@ Separate dimension from Base type, this is getting out of control. 101 | HLSLBaseType_Short2, 102 | HLSLBaseType_Short3, 103 | HLSLBaseType_Short4, 104 | HLSLBaseType_Ushort, 105 | HLSLBaseType_Ushort2, 106 | HLSLBaseType_Ushort3, 107 | HLSLBaseType_Ushort4,*/ 108 | HLSLBaseType_LastInteger = HLSLBaseType_Uint4, 109 | HLSLBaseType_LastNumeric = HLSLBaseType_Uint4, 110 | HLSLBaseType_Texture, 111 | HLSLBaseType_Sampler, // @@ use type inference to determine sampler type. 112 | HLSLBaseType_Sampler2D, 113 | HLSLBaseType_Sampler3D, 114 | HLSLBaseType_SamplerCube, 115 | HLSLBaseType_Sampler2DShadow, 116 | HLSLBaseType_Sampler2DMS, 117 | HLSLBaseType_Sampler2DArray, 118 | HLSLBaseType_UserDefined, // struct 119 | HLSLBaseType_Expression, // type argument for defined() sizeof() and typeof(). 120 | HLSLBaseType_Auto, 121 | 122 | HLSLBaseType_Count, 123 | HLSLBaseType_NumericCount = HLSLBaseType_LastNumeric - HLSLBaseType_FirstNumeric + 1 124 | }; 125 | 126 | extern const HLSLTypeDimension BaseTypeDimension[HLSLBaseType_Count]; 127 | extern const HLSLBaseType ScalarBaseType[HLSLBaseType_Count]; 128 | 129 | inline bool IsSamplerType(HLSLBaseType baseType) 130 | { 131 | return baseType == HLSLBaseType_Sampler || 132 | baseType == HLSLBaseType_Sampler2D || 133 | baseType == HLSLBaseType_Sampler3D || 134 | baseType == HLSLBaseType_SamplerCube || 135 | baseType == HLSLBaseType_Sampler2DShadow || 136 | baseType == HLSLBaseType_Sampler2DMS || 137 | baseType == HLSLBaseType_Sampler2DArray; 138 | } 139 | 140 | inline bool IsMatrixType(HLSLBaseType baseType) 141 | { 142 | return baseType == HLSLBaseType_Float3x3 || baseType == HLSLBaseType_Float4x4 || baseType == HLSLBaseType_Float4x3 || baseType == HLSLBaseType_Float4x2 || 143 | baseType == HLSLBaseType_Half3x3 || baseType == HLSLBaseType_Half4x4 || baseType == HLSLBaseType_Half4x3 || baseType == HLSLBaseType_Half4x2; 144 | } 145 | 146 | inline bool IsScalarType( HLSLBaseType baseType ) 147 | { 148 | return baseType == HLSLBaseType_Float || 149 | baseType == HLSLBaseType_Half || 150 | baseType == HLSLBaseType_Bool || 151 | baseType == HLSLBaseType_Int || 152 | baseType == HLSLBaseType_Uint; 153 | } 154 | 155 | inline bool IsVectorType( HLSLBaseType baseType ) 156 | { 157 | return baseType == HLSLBaseType_Float2 || 158 | baseType == HLSLBaseType_Float3 || 159 | baseType == HLSLBaseType_Float4 || 160 | baseType == HLSLBaseType_Half2 || 161 | baseType == HLSLBaseType_Half3 || 162 | baseType == HLSLBaseType_Half4 || 163 | baseType == HLSLBaseType_Bool2 || 164 | baseType == HLSLBaseType_Bool3 || 165 | baseType == HLSLBaseType_Bool4 || 166 | baseType == HLSLBaseType_Int2 || 167 | baseType == HLSLBaseType_Int3 || 168 | baseType == HLSLBaseType_Int4 || 169 | baseType == HLSLBaseType_Uint2 || 170 | baseType == HLSLBaseType_Uint3 || 171 | baseType == HLSLBaseType_Uint4; 172 | } 173 | 174 | 175 | enum HLSLBinaryOp 176 | { 177 | HLSLBinaryOp_And, 178 | HLSLBinaryOp_Or, 179 | HLSLBinaryOp_Add, 180 | HLSLBinaryOp_Sub, 181 | HLSLBinaryOp_Mul, 182 | HLSLBinaryOp_Div, 183 | HLSLBinaryOp_Less, 184 | HLSLBinaryOp_Greater, 185 | HLSLBinaryOp_LessEqual, 186 | HLSLBinaryOp_GreaterEqual, 187 | HLSLBinaryOp_Equal, 188 | HLSLBinaryOp_NotEqual, 189 | HLSLBinaryOp_BitAnd, 190 | HLSLBinaryOp_BitOr, 191 | HLSLBinaryOp_BitXor, 192 | HLSLBinaryOp_Assign, 193 | HLSLBinaryOp_AddAssign, 194 | HLSLBinaryOp_SubAssign, 195 | HLSLBinaryOp_MulAssign, 196 | HLSLBinaryOp_DivAssign, 197 | }; 198 | 199 | inline bool IsCompareOp( HLSLBinaryOp op ) 200 | { 201 | return op == HLSLBinaryOp_Less || 202 | op == HLSLBinaryOp_Greater || 203 | op == HLSLBinaryOp_LessEqual || 204 | op == HLSLBinaryOp_GreaterEqual || 205 | op == HLSLBinaryOp_Equal || 206 | op == HLSLBinaryOp_NotEqual; 207 | } 208 | 209 | inline bool IsArithmeticOp( HLSLBinaryOp op ) 210 | { 211 | return op == HLSLBinaryOp_Add || 212 | op == HLSLBinaryOp_Sub || 213 | op == HLSLBinaryOp_Mul || 214 | op == HLSLBinaryOp_Div; 215 | } 216 | 217 | inline bool IsLogicOp( HLSLBinaryOp op ) 218 | { 219 | return op == HLSLBinaryOp_And || 220 | op == HLSLBinaryOp_Or; 221 | } 222 | 223 | inline bool IsAssignOp( HLSLBinaryOp op ) 224 | { 225 | return op == HLSLBinaryOp_Assign || 226 | op == HLSLBinaryOp_AddAssign || 227 | op == HLSLBinaryOp_SubAssign || 228 | op == HLSLBinaryOp_MulAssign || 229 | op == HLSLBinaryOp_DivAssign; 230 | } 231 | 232 | 233 | enum HLSLUnaryOp 234 | { 235 | HLSLUnaryOp_Negative, // -x 236 | HLSLUnaryOp_Positive, // +x 237 | HLSLUnaryOp_Not, // !x 238 | HLSLUnaryOp_PreIncrement, // ++x 239 | HLSLUnaryOp_PreDecrement, // --x 240 | HLSLUnaryOp_PostIncrement, // x++ 241 | HLSLUnaryOp_PostDecrement, // x++ 242 | HLSLUnaryOp_BitNot, // ~x 243 | }; 244 | 245 | enum HLSLArgumentModifier 246 | { 247 | HLSLArgumentModifier_None, 248 | HLSLArgumentModifier_In, 249 | HLSLArgumentModifier_Out, 250 | HLSLArgumentModifier_Inout, 251 | HLSLArgumentModifier_Uniform, 252 | HLSLArgumentModifier_Const, 253 | }; 254 | 255 | enum HLSLTypeFlags 256 | { 257 | HLSLTypeFlag_None = 0, 258 | HLSLTypeFlag_Const = 0x01, 259 | HLSLTypeFlag_Static = 0x02, 260 | //HLSLTypeFlag_Uniform = 0x04, 261 | //HLSLTypeFlag_Extern = 0x10, 262 | //HLSLTypeFlag_Volatile = 0x20, 263 | //HLSLTypeFlag_Shared = 0x40, 264 | //HLSLTypeFlag_Precise = 0x80, 265 | 266 | HLSLTypeFlag_Input = 0x100, 267 | HLSLTypeFlag_Output = 0x200, 268 | 269 | // Interpolation modifiers. 270 | HLSLTypeFlag_Linear = 0x10000, 271 | HLSLTypeFlag_Centroid = 0x20000, 272 | HLSLTypeFlag_NoInterpolation = 0x40000, 273 | HLSLTypeFlag_NoPerspective = 0x80000, 274 | HLSLTypeFlag_Sample = 0x100000, 275 | 276 | // Misc. 277 | HLSLTypeFlag_NoPromote = 0x200000, 278 | }; 279 | 280 | enum HLSLAttributeType 281 | { 282 | HLSLAttributeType_Unknown, 283 | HLSLAttributeType_Unroll, 284 | HLSLAttributeType_Branch, 285 | HLSLAttributeType_Flatten, 286 | HLSLAttributeType_NoFastMath, 287 | }; 288 | 289 | enum HLSLAddressSpace 290 | { 291 | HLSLAddressSpace_Undefined, 292 | HLSLAddressSpace_Constant, 293 | HLSLAddressSpace_Device, 294 | HLSLAddressSpace_Thread, 295 | HLSLAddressSpace_Shared, 296 | }; 297 | 298 | 299 | struct HLSLNode; 300 | struct HLSLRoot; 301 | struct HLSLStatement; 302 | struct HLSLAttribute; 303 | struct HLSLDeclaration; 304 | struct HLSLStruct; 305 | struct HLSLStructField; 306 | struct HLSLBuffer; 307 | struct HLSLFunction; 308 | struct HLSLArgument; 309 | struct HLSLExpressionStatement; 310 | struct HLSLExpression; 311 | struct HLSLBinaryExpression; 312 | struct HLSLLiteralExpression; 313 | struct HLSLIdentifierExpression; 314 | struct HLSLConstructorExpression; 315 | struct HLSLFunctionCall; 316 | struct HLSLArrayAccess; 317 | struct HLSLAttribute; 318 | 319 | struct HLSLType 320 | { 321 | explicit HLSLType(HLSLBaseType _baseType = HLSLBaseType_Unknown) 322 | { 323 | baseType = _baseType; 324 | samplerType = HLSLBaseType_Float; 325 | typeName = NULL; 326 | array = false; 327 | arraySize = NULL; 328 | flags = 0; 329 | addressSpace = HLSLAddressSpace_Undefined; 330 | } 331 | HLSLBaseType baseType; 332 | HLSLBaseType samplerType; // Half or Float 333 | const char* typeName; // For user defined types. 334 | bool array; 335 | HLSLExpression* arraySize; 336 | int flags; 337 | HLSLAddressSpace addressSpace; 338 | }; 339 | 340 | inline bool IsSamplerType(const HLSLType & type) 341 | { 342 | return IsSamplerType(type.baseType); 343 | } 344 | 345 | inline bool IsScalarType(const HLSLType & type) 346 | { 347 | return IsScalarType(type.baseType); 348 | } 349 | 350 | inline bool IsVectorType(const HLSLType & type) 351 | { 352 | return IsVectorType(type.baseType); 353 | } 354 | 355 | 356 | /** Base class for all nodes in the HLSL AST */ 357 | struct HLSLNode 358 | { 359 | HLSLNodeType nodeType; 360 | const char* fileName; 361 | int line; 362 | }; 363 | 364 | struct HLSLRoot : public HLSLNode 365 | { 366 | static const HLSLNodeType s_type = HLSLNodeType_Root; 367 | HLSLRoot() { statement = NULL; } 368 | HLSLStatement* statement; // First statement. 369 | }; 370 | 371 | struct HLSLStatement : public HLSLNode 372 | { 373 | HLSLStatement() 374 | { 375 | nextStatement = NULL; 376 | attributes = NULL; 377 | hidden = false; 378 | } 379 | HLSLStatement* nextStatement; // Next statement in the block. 380 | HLSLAttribute* attributes; 381 | mutable bool hidden; 382 | }; 383 | 384 | struct HLSLAttribute : public HLSLNode 385 | { 386 | static const HLSLNodeType s_type = HLSLNodeType_Attribute; 387 | HLSLAttribute() 388 | { 389 | attributeType = HLSLAttributeType_Unknown; 390 | argument = NULL; 391 | nextAttribute = NULL; 392 | } 393 | HLSLAttributeType attributeType; 394 | HLSLExpression* argument; 395 | HLSLAttribute* nextAttribute; 396 | }; 397 | 398 | struct HLSLDeclaration : public HLSLStatement 399 | { 400 | static const HLSLNodeType s_type = HLSLNodeType_Declaration; 401 | HLSLDeclaration() 402 | { 403 | name = NULL; 404 | registerName = NULL; 405 | semantic = NULL; 406 | nextDeclaration = NULL; 407 | assignment = NULL; 408 | buffer = NULL; 409 | } 410 | const char* name; 411 | HLSLType type; 412 | const char* registerName; // @@ Store register index? 413 | const char* semantic; 414 | HLSLDeclaration* nextDeclaration; // If multiple variables declared on a line. 415 | HLSLExpression* assignment; 416 | HLSLBuffer* buffer; 417 | }; 418 | 419 | struct HLSLStruct : public HLSLStatement 420 | { 421 | static const HLSLNodeType s_type = HLSLNodeType_Struct; 422 | HLSLStruct() 423 | { 424 | name = NULL; 425 | field = NULL; 426 | } 427 | const char* name; 428 | HLSLStructField* field; // First field in the structure. 429 | }; 430 | 431 | struct HLSLStructField : public HLSLNode 432 | { 433 | static const HLSLNodeType s_type = HLSLNodeType_StructField; 434 | HLSLStructField() 435 | { 436 | name = NULL; 437 | semantic = NULL; 438 | sv_semantic = NULL; 439 | nextField = NULL; 440 | hidden = false; 441 | } 442 | const char* name; 443 | HLSLType type; 444 | const char* semantic; 445 | const char* sv_semantic; 446 | HLSLStructField* nextField; // Next field in the structure. 447 | bool hidden; 448 | }; 449 | 450 | /** A cbuffer or tbuffer declaration. */ 451 | struct HLSLBuffer : public HLSLStatement 452 | { 453 | static const HLSLNodeType s_type = HLSLNodeType_Buffer; 454 | HLSLBuffer() 455 | { 456 | name = NULL; 457 | registerName = NULL; 458 | field = NULL; 459 | } 460 | const char* name; 461 | const char* registerName; 462 | HLSLDeclaration* field; 463 | }; 464 | 465 | 466 | /** Function declaration */ 467 | struct HLSLFunction : public HLSLStatement 468 | { 469 | static const HLSLNodeType s_type = HLSLNodeType_Function; 470 | HLSLFunction() 471 | { 472 | name = NULL; 473 | semantic = NULL; 474 | sv_semantic = NULL; 475 | statement = NULL; 476 | argument = NULL; 477 | numArguments = 0; 478 | numOutputArguments = 0; 479 | forward = NULL; 480 | } 481 | const char* name; 482 | HLSLType returnType; 483 | const char* semantic; 484 | const char* sv_semantic; 485 | int numArguments; 486 | int numOutputArguments; // Includes out and inout arguments. 487 | HLSLArgument* argument; 488 | HLSLStatement* statement; 489 | HLSLFunction* forward; // Which HLSLFunction this one forward-declares 490 | }; 491 | 492 | /** Declaration of an argument to a function. */ 493 | struct HLSLArgument : public HLSLNode 494 | { 495 | static const HLSLNodeType s_type = HLSLNodeType_Argument; 496 | HLSLArgument() 497 | { 498 | name = NULL; 499 | modifier = HLSLArgumentModifier_None; 500 | semantic = NULL; 501 | sv_semantic = NULL; 502 | defaultValue = NULL; 503 | nextArgument = NULL; 504 | hidden = false; 505 | } 506 | const char* name; 507 | HLSLArgumentModifier modifier; 508 | HLSLType type; 509 | const char* semantic; 510 | const char* sv_semantic; 511 | HLSLExpression* defaultValue; 512 | HLSLArgument* nextArgument; 513 | bool hidden; 514 | }; 515 | 516 | /** A expression which forms a complete statement. */ 517 | struct HLSLExpressionStatement : public HLSLStatement 518 | { 519 | static const HLSLNodeType s_type = HLSLNodeType_ExpressionStatement; 520 | HLSLExpressionStatement() 521 | { 522 | expression = NULL; 523 | } 524 | HLSLExpression* expression; 525 | }; 526 | 527 | struct HLSLReturnStatement : public HLSLStatement 528 | { 529 | static const HLSLNodeType s_type = HLSLNodeType_ReturnStatement; 530 | HLSLReturnStatement() 531 | { 532 | expression = NULL; 533 | } 534 | HLSLExpression* expression; 535 | }; 536 | 537 | struct HLSLDiscardStatement : public HLSLStatement 538 | { 539 | static const HLSLNodeType s_type = HLSLNodeType_DiscardStatement; 540 | }; 541 | 542 | struct HLSLBreakStatement : public HLSLStatement 543 | { 544 | static const HLSLNodeType s_type = HLSLNodeType_BreakStatement; 545 | }; 546 | 547 | struct HLSLContinueStatement : public HLSLStatement 548 | { 549 | static const HLSLNodeType s_type = HLSLNodeType_ContinueStatement; 550 | }; 551 | 552 | struct HLSLIfStatement : public HLSLStatement 553 | { 554 | static const HLSLNodeType s_type = HLSLNodeType_IfStatement; 555 | HLSLIfStatement() 556 | { 557 | condition = NULL; 558 | statement = NULL; 559 | elseStatement = NULL; 560 | isStatic = false; 561 | } 562 | HLSLExpression* condition; 563 | HLSLStatement* statement; 564 | HLSLStatement* elseStatement; 565 | bool isStatic; 566 | }; 567 | 568 | struct HLSLForStatement : public HLSLStatement 569 | { 570 | static const HLSLNodeType s_type = HLSLNodeType_ForStatement; 571 | HLSLForStatement() 572 | { 573 | initialization = NULL; 574 | condition = NULL; 575 | increment = NULL; 576 | statement = NULL; 577 | } 578 | HLSLDeclaration* initialization; 579 | HLSLExpression* condition; 580 | HLSLExpression* increment; 581 | HLSLStatement* statement; 582 | }; 583 | 584 | struct HLSLBlockStatement : public HLSLStatement 585 | { 586 | static const HLSLNodeType s_type = HLSLNodeType_BlockStatement; 587 | HLSLBlockStatement() 588 | { 589 | statement = NULL; 590 | } 591 | HLSLStatement* statement; 592 | }; 593 | 594 | 595 | /** Base type for all types of expressions. */ 596 | struct HLSLExpression : public HLSLNode 597 | { 598 | static const HLSLNodeType s_type = HLSLNodeType_Expression; 599 | HLSLExpression() 600 | { 601 | nextExpression = NULL; 602 | } 603 | HLSLType expressionType; 604 | HLSLExpression* nextExpression; // Used when the expression is part of a list, like in a function call. 605 | }; 606 | 607 | struct HLSLUnaryExpression : public HLSLExpression 608 | { 609 | static const HLSLNodeType s_type = HLSLNodeType_UnaryExpression; 610 | HLSLUnaryExpression() 611 | { 612 | expression = NULL; 613 | } 614 | HLSLUnaryOp unaryOp; 615 | HLSLExpression* expression; 616 | }; 617 | 618 | struct HLSLBinaryExpression : public HLSLExpression 619 | { 620 | static const HLSLNodeType s_type = HLSLNodeType_BinaryExpression; 621 | HLSLBinaryExpression() 622 | { 623 | expression1 = NULL; 624 | expression2 = NULL; 625 | } 626 | HLSLBinaryOp binaryOp; 627 | HLSLExpression* expression1; 628 | HLSLExpression* expression2; 629 | }; 630 | 631 | /** ? : construct */ 632 | struct HLSLConditionalExpression : public HLSLExpression 633 | { 634 | static const HLSLNodeType s_type = HLSLNodeType_ConditionalExpression; 635 | HLSLConditionalExpression() 636 | { 637 | condition = NULL; 638 | trueExpression = NULL; 639 | falseExpression = NULL; 640 | } 641 | HLSLExpression* condition; 642 | HLSLExpression* trueExpression; 643 | HLSLExpression* falseExpression; 644 | }; 645 | 646 | struct HLSLCastingExpression : public HLSLExpression 647 | { 648 | static const HLSLNodeType s_type = HLSLNodeType_CastingExpression; 649 | HLSLCastingExpression() 650 | { 651 | expression = NULL; 652 | } 653 | HLSLType type; 654 | HLSLExpression* expression; 655 | }; 656 | 657 | /** Float, integer, boolean, etc. literal constant. */ 658 | struct HLSLLiteralExpression : public HLSLExpression 659 | { 660 | static const HLSLNodeType s_type = HLSLNodeType_LiteralExpression; 661 | HLSLBaseType type; // Note, not all types can be literals. 662 | union 663 | { 664 | bool bValue; 665 | float fValue; 666 | int iValue; 667 | }; 668 | }; 669 | 670 | /** An identifier, typically a variable name or structure field name. */ 671 | struct HLSLIdentifierExpression : public HLSLExpression 672 | { 673 | static const HLSLNodeType s_type = HLSLNodeType_IdentifierExpression; 674 | HLSLIdentifierExpression() 675 | { 676 | name = NULL; 677 | global = false; 678 | } 679 | const char* name; 680 | bool global; // This is a global variable. 681 | }; 682 | 683 | /** float2(1, 2) */ 684 | struct HLSLConstructorExpression : public HLSLExpression 685 | { 686 | static const HLSLNodeType s_type = HLSLNodeType_ConstructorExpression; 687 | HLSLConstructorExpression() 688 | { 689 | argument = NULL; 690 | } 691 | HLSLType type; 692 | HLSLExpression* argument; 693 | }; 694 | 695 | /** object.member **/ 696 | struct HLSLMemberAccess : public HLSLExpression 697 | { 698 | static const HLSLNodeType s_type = HLSLNodeType_MemberAccess; 699 | HLSLMemberAccess() 700 | { 701 | object = NULL; 702 | field = NULL; 703 | swizzle = false; 704 | } 705 | HLSLExpression* object; 706 | const char* field; 707 | bool swizzle; 708 | }; 709 | 710 | /** array[index] **/ 711 | struct HLSLArrayAccess : public HLSLExpression 712 | { 713 | static const HLSLNodeType s_type = HLSLNodeType_ArrayAccess; 714 | HLSLArrayAccess() 715 | { 716 | array = NULL; 717 | index = NULL; 718 | } 719 | HLSLExpression* array; 720 | HLSLExpression* index; 721 | }; 722 | 723 | struct HLSLFunctionCall : public HLSLExpression 724 | { 725 | static const HLSLNodeType s_type = HLSLNodeType_FunctionCall; 726 | HLSLFunctionCall() 727 | { 728 | function = NULL; 729 | argument = NULL; 730 | numArguments = 0; 731 | } 732 | const HLSLFunction* function; 733 | HLSLExpression* argument; 734 | int numArguments; 735 | }; 736 | 737 | struct HLSLStateAssignment : public HLSLNode 738 | { 739 | static const HLSLNodeType s_type = HLSLNodeType_StateAssignment; 740 | HLSLStateAssignment() 741 | { 742 | stateName = NULL; 743 | sValue = NULL; 744 | nextStateAssignment = NULL; 745 | } 746 | 747 | const char* stateName; 748 | int d3dRenderState; 749 | union { 750 | int iValue; 751 | float fValue; 752 | const char * sValue; 753 | }; 754 | HLSLStateAssignment* nextStateAssignment; 755 | }; 756 | 757 | struct HLSLSamplerState : public HLSLExpression // @@ Does this need to be an expression? Does it have a type? I guess type is useful. 758 | { 759 | static const HLSLNodeType s_type = HLSLNodeType_SamplerState; 760 | HLSLSamplerState() 761 | { 762 | numStateAssignments = 0; 763 | stateAssignments = NULL; 764 | } 765 | 766 | int numStateAssignments; 767 | HLSLStateAssignment* stateAssignments; 768 | }; 769 | 770 | struct HLSLPass : public HLSLNode 771 | { 772 | static const HLSLNodeType s_type = HLSLNodeType_Pass; 773 | HLSLPass() 774 | { 775 | name = NULL; 776 | numStateAssignments = 0; 777 | stateAssignments = NULL; 778 | nextPass = NULL; 779 | } 780 | 781 | const char* name; 782 | int numStateAssignments; 783 | HLSLStateAssignment* stateAssignments; 784 | HLSLPass* nextPass; 785 | }; 786 | 787 | struct HLSLTechnique : public HLSLStatement 788 | { 789 | static const HLSLNodeType s_type = HLSLNodeType_Technique; 790 | HLSLTechnique() 791 | { 792 | name = NULL; 793 | numPasses = 0; 794 | passes = NULL; 795 | } 796 | 797 | const char* name; 798 | int numPasses; 799 | HLSLPass* passes; 800 | }; 801 | 802 | struct HLSLPipeline : public HLSLStatement 803 | { 804 | static const HLSLNodeType s_type = HLSLNodeType_Pipeline; 805 | HLSLPipeline() 806 | { 807 | name = NULL; 808 | numStateAssignments = 0; 809 | stateAssignments = NULL; 810 | } 811 | 812 | const char* name; 813 | int numStateAssignments; 814 | HLSLStateAssignment* stateAssignments; 815 | }; 816 | 817 | struct HLSLStage : public HLSLStatement 818 | { 819 | static const HLSLNodeType s_type = HLSLNodeType_Stage; 820 | HLSLStage() 821 | { 822 | name = NULL; 823 | statement = NULL; 824 | inputs = NULL; 825 | outputs = NULL; 826 | } 827 | 828 | const char* name; 829 | HLSLStatement* statement; 830 | HLSLDeclaration* inputs; 831 | HLSLDeclaration* outputs; 832 | }; 833 | 834 | 835 | /** 836 | * Abstract syntax tree for parsed HLSL code. 837 | */ 838 | class HLSLTree 839 | { 840 | 841 | public: 842 | 843 | explicit HLSLTree(Allocator* allocator); 844 | ~HLSLTree(); 845 | 846 | /** Adds a string to the string pool used by the tree. */ 847 | const char* AddString(const char* string); 848 | const char* AddStringFormat(const char* string, ...); 849 | 850 | /** Returns true if the string is contained within the tree. */ 851 | bool GetContainsString(const char* string) const; 852 | 853 | /** Returns the root block in the tree */ 854 | HLSLRoot* GetRoot() const; 855 | 856 | /** Adds a new node to the tree with the specified type. */ 857 | template 858 | T* AddNode(const char* fileName, int line) 859 | { 860 | HLSLNode* node = new (AllocateMemory(sizeof(T))) T(); 861 | node->nodeType = T::s_type; 862 | node->fileName = fileName; 863 | node->line = line; 864 | return static_cast(node); 865 | } 866 | 867 | HLSLFunction * FindFunction(const char * name); 868 | HLSLDeclaration * FindGlobalDeclaration(const char * name, HLSLBuffer ** buffer_out = NULL); 869 | HLSLStruct * FindGlobalStruct(const char * name); 870 | HLSLTechnique * FindTechnique(const char * name); 871 | HLSLPipeline * FindFirstPipeline(); 872 | HLSLPipeline * FindNextPipeline(HLSLPipeline * current); 873 | HLSLPipeline * FindPipeline(const char * name); 874 | HLSLBuffer * FindBuffer(const char * name); 875 | 876 | bool GetExpressionValue(HLSLExpression * expression, int & value); 877 | int GetExpressionValue(HLSLExpression * expression, float values[4]); 878 | 879 | bool NeedsFunction(const char * name); 880 | 881 | private: 882 | 883 | void* AllocateMemory(size_t size); 884 | void AllocatePage(); 885 | 886 | private: 887 | 888 | static const size_t s_nodePageSize = 1024 * 4; 889 | 890 | struct NodePage 891 | { 892 | NodePage* next; 893 | char buffer[s_nodePageSize]; 894 | }; 895 | 896 | Allocator* m_allocator; 897 | StringPool m_stringPool; 898 | HLSLRoot* m_root; 899 | 900 | NodePage* m_firstPage; 901 | NodePage* m_currentPage; 902 | size_t m_currentPageOffset; 903 | 904 | }; 905 | 906 | 907 | 908 | class HLSLTreeVisitor 909 | { 910 | public: 911 | virtual void VisitType(HLSLType & type); 912 | 913 | virtual void VisitRoot(HLSLRoot * node); 914 | virtual void VisitTopLevelStatement(HLSLStatement * node); 915 | virtual void VisitStatements(HLSLStatement * statement); 916 | virtual void VisitStatement(HLSLStatement * node); 917 | virtual void VisitDeclaration(HLSLDeclaration * node); 918 | virtual void VisitStruct(HLSLStruct * node); 919 | virtual void VisitStructField(HLSLStructField * node); 920 | virtual void VisitBuffer(HLSLBuffer * node); 921 | //virtual void VisitBufferField(HLSLBufferField * node); 922 | virtual void VisitFunction(HLSLFunction * node); 923 | virtual void VisitArgument(HLSLArgument * node); 924 | virtual void VisitExpressionStatement(HLSLExpressionStatement * node); 925 | virtual void VisitExpression(HLSLExpression * node); 926 | virtual void VisitReturnStatement(HLSLReturnStatement * node); 927 | virtual void VisitDiscardStatement(HLSLDiscardStatement * node); 928 | virtual void VisitBreakStatement(HLSLBreakStatement * node); 929 | virtual void VisitContinueStatement(HLSLContinueStatement * node); 930 | virtual void VisitIfStatement(HLSLIfStatement * node); 931 | virtual void VisitForStatement(HLSLForStatement * node); 932 | virtual void VisitBlockStatement(HLSLBlockStatement * node); 933 | virtual void VisitUnaryExpression(HLSLUnaryExpression * node); 934 | virtual void VisitBinaryExpression(HLSLBinaryExpression * node); 935 | virtual void VisitConditionalExpression(HLSLConditionalExpression * node); 936 | virtual void VisitCastingExpression(HLSLCastingExpression * node); 937 | virtual void VisitLiteralExpression(HLSLLiteralExpression * node); 938 | virtual void VisitIdentifierExpression(HLSLIdentifierExpression * node); 939 | virtual void VisitConstructorExpression(HLSLConstructorExpression * node); 940 | virtual void VisitMemberAccess(HLSLMemberAccess * node); 941 | virtual void VisitArrayAccess(HLSLArrayAccess * node); 942 | virtual void VisitFunctionCall(HLSLFunctionCall * node); 943 | virtual void VisitStateAssignment(HLSLStateAssignment * node); 944 | virtual void VisitSamplerState(HLSLSamplerState * node); 945 | virtual void VisitPass(HLSLPass * node); 946 | virtual void VisitTechnique(HLSLTechnique * node); 947 | virtual void VisitPipeline(HLSLPipeline * node); 948 | 949 | 950 | virtual void VisitFunctions(HLSLRoot * root); 951 | virtual void VisitParameters(HLSLRoot * root); 952 | 953 | HLSLFunction * FindFunction(HLSLRoot * root, const char * name); 954 | HLSLDeclaration * FindGlobalDeclaration(HLSLRoot * root, const char * name); 955 | HLSLStruct * FindGlobalStruct(HLSLRoot * root, const char * name); 956 | }; 957 | 958 | 959 | // Tree transformations: 960 | extern void PruneTree(HLSLTree* tree, const char* entryName0, const char* entryName1 = NULL); 961 | extern void SortTree(HLSLTree* tree); 962 | extern void GroupParameters(HLSLTree* tree); 963 | extern void HideUnusedArguments(HLSLFunction * function); 964 | extern bool EmulateAlphaTest(HLSLTree* tree, const char* entryName, float alphaRef = 0.5f); 965 | extern void FlattenExpressions(HLSLTree* tree); 966 | 967 | } // M4 968 | 969 | #endif 970 | -------------------------------------------------------------------------------- /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 | bool treatHalfAsFloat; 39 | bool forceHalfPrecision; // Not implemented. 40 | bool usePreciseFma; 41 | bool use16BitIntegers; 42 | 43 | Options() 44 | { 45 | flags = 0; 46 | bufferRegisterOffset = 0; 47 | attributeCallback = NULL; 48 | treatHalfAsFloat = true; 49 | forceHalfPrecision = false; 50 | usePreciseFma = false; 51 | use16BitIntegers = false; 52 | } 53 | }; 54 | 55 | MSLGenerator(); 56 | 57 | bool Generate(HLSLTree* tree, Target target, const char* entryName, const Options& options = Options()); 58 | const char* GetResult() const; 59 | 60 | private: 61 | 62 | // @@ Rename class argument. Add buffers & textures. 63 | struct ClassArgument 64 | { 65 | const char* name; 66 | HLSLType type; 67 | //const char* typeName; // @@ Do we need more than the type name? 68 | const char* registerName; 69 | 70 | ClassArgument * nextArg; 71 | 72 | ClassArgument(const char* name, HLSLType type, const char * registerName) : 73 | name(name), type(type), registerName(registerName) 74 | { 75 | nextArg = NULL; 76 | } 77 | }; 78 | 79 | void AddClassArgument(ClassArgument * arg); 80 | 81 | void Prepass(HLSLTree* tree, Target target, HLSLFunction* entryFunction); 82 | void CleanPrepass(); 83 | 84 | void PrependDeclarations(); 85 | 86 | void OutputStaticDeclarations(int indent, HLSLStatement* statement); 87 | void OutputStatements(int indent, HLSLStatement* statement); 88 | void OutputAttributes(int indent, HLSLAttribute* attribute); 89 | void OutputDeclaration(HLSLDeclaration* declaration); 90 | void OutputStruct(int indent, HLSLStruct* structure); 91 | void OutputBuffer(int indent, HLSLBuffer* buffer); 92 | void OutputFunction(int indent, HLSLFunction* function); 93 | void OutputExpression(HLSLExpression* expression, HLSLExpression* parentExpression); 94 | void OutputTypedExpression(const HLSLType& type, HLSLExpression* expression, HLSLExpression* parentExpression); 95 | bool NeedsCast(const HLSLType & target, const HLSLType & source); 96 | void OutputCast(const HLSLType& type); 97 | 98 | void OutputArguments(HLSLArgument* argument); 99 | void OutputDeclaration(const HLSLType& type, const char* name, HLSLExpression* assignment, bool isRef = false, bool isConst = false, int alignment = 0); 100 | void OutputDeclarationType(const HLSLType& type, bool isConst = false, bool isRef = false, int alignment = 0, bool isTypeCast = false); 101 | void OutputDeclarationBody(const HLSLType& type, const char* name, HLSLExpression* assignment, bool isRef = false); 102 | void OutputExpressionList(HLSLExpression* expression); 103 | void OutputExpressionList(const HLSLType& type, HLSLExpression* expression); 104 | void OutputExpressionList(HLSLArgument* argument, HLSLExpression* expression); 105 | 106 | void OutputFunctionCallStatement(int indent, HLSLFunctionCall* functionCall, HLSLDeclaration* assingmentExpression); 107 | void OutputFunctionCall(HLSLFunctionCall* functionCall, HLSLExpression * parentExpression); 108 | 109 | const char* TranslateInputSemantic(const char* semantic); 110 | const char* TranslateOutputSemantic(const char* semantic); 111 | 112 | const char* GetTypeName(const HLSLType& type, bool exactType); 113 | 114 | void Error(const char* format, ...); 115 | 116 | private: 117 | 118 | CodeWriter m_writer; 119 | 120 | HLSLTree* m_tree; 121 | const char* m_entryName; 122 | Target m_target; 123 | Options m_options; 124 | 125 | bool m_error; 126 | 127 | ClassArgument * m_firstClassArgument; 128 | ClassArgument * m_lastClassArgument; 129 | 130 | HLSLFunction * m_currentFunction; 131 | }; 132 | 133 | } // M4 134 | 135 | #endif 136 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------