├── .github └── workflows │ └── build.yml ├── .gitignore ├── CMakeLists.txt ├── GNUmakefile ├── LICENSE ├── README.md ├── cmake └── tsl-config.cmake.in ├── gallery └── tsl_sample.jpg ├── make.bat ├── scripts ├── get_dependencies.py └── verify_builds.py └── src ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── include ├── tsl_args.h ├── tsl_define.h ├── tsl_system.h └── tsl_version.h.in ├── llvm_test ├── CMakeLists.txt ├── llvm_test.cpp └── main.cpp ├── thirdparty └── gtest │ ├── gtest-all.cc │ ├── gtest-config.cmake │ └── gtest.h ├── tsl_lib ├── CMakeLists.txt ├── compiler │ ├── ast.cpp │ ├── ast.h │ ├── ast_memory_janitor.cpp │ ├── ast_memory_janitor.h │ ├── compile_context.cpp │ ├── compile_context.h │ ├── compiler.cpp │ ├── compiler.h │ ├── global_module.cpp │ ├── global_module.h │ ├── grammar.y │ ├── internal_define.h │ ├── lex.l │ ├── llvm_util.h │ ├── str_helper.cpp │ ├── str_helper.h │ └── types.h └── system │ ├── callback.cpp │ ├── impl.h │ ├── shading_context.cpp │ └── shading_system.cpp ├── tsl_sample ├── CMakeLists.txt ├── main.cpp ├── rt_bxdf.cpp ├── rt_bxdf.h ├── rt_common.h ├── rt_core.cpp ├── rt_tsl.cpp ├── rt_tsl.h └── stb_image │ └── stb_image.h └── tsl_test ├── CMakeLists.txt ├── main.cpp └── test ├── array.cpp ├── basic.cpp ├── callback.cpp ├── closures.cpp ├── comments.cpp ├── empty.cpp ├── expression.cpp ├── functions.cpp ├── global_value.cpp ├── logic.cpp ├── math.cpp ├── multi_thread.cpp ├── numbers.cpp ├── output.cpp ├── real_algorithms.cpp ├── shader_group.cpp ├── shader_resource.cpp ├── struct.cpp ├── system.cpp ├── test_common.cpp ├── test_common.h └── variables.cpp /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build TSL 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | Windows: 7 | runs-on: windows-latest 8 | steps: 9 | - name: Checking Out Source Code 10 | uses: actions/checkout@v1 11 | - name: Setup MSBuild.exe 12 | uses: microsoft/setup-msbuild@v1.0.2 13 | - name: Setup Python 14 | uses: actions/setup-python@v2 15 | with: 16 | python-version: '3.x' 17 | architecture: 'x64' 18 | - name: Get Cache Directory 19 | id: cache-dir 20 | run: | 21 | echo ::set-output name=dir::%CD% 22 | shell: cmd 23 | - name: Load Dependencies from Cache 24 | uses: actions/cache@v1 25 | id: cache-dep 26 | with: 27 | path: ${{ steps.cache-dir.outputs.dir }}/dependencies 28 | key: Windows-dep-ver-7 29 | - name: Install Dependencies 30 | if: steps.cache-dep.outputs.cache-hit != 'true' 31 | run: make update_dep 32 | shell: cmd 33 | - name: Build Release Version 34 | run: make 35 | shell: cmd 36 | - name: Build Debug Version 37 | run: make debug 38 | shell: cmd 39 | - name: Unit test 40 | run: make test 41 | shell: cmd 42 | MacOs_Intel: 43 | runs-on: macOS-latest 44 | steps: 45 | - name: Checking Out Source Code 46 | uses: actions/checkout@v1 47 | - name: Configure Environment 48 | run: | 49 | brew install flex 50 | brew install bison 51 | - name: Setup Python 52 | uses: actions/setup-python@v2 53 | with: 54 | python-version: '3.x' 55 | architecture: 'x64' 56 | - name: Get Cache Directory 57 | id: cache-dir 58 | run: | 59 | echo "::set-output name=dir::$(pwd)" 60 | - name: Load Dependencies from Cache 61 | uses: actions/cache@v1 62 | id: cache-dep 63 | with: 64 | path: ${{ steps.cache-dir.outputs.dir }}/dependencies 65 | key: MacOS-Intel-dep-ver-8 66 | - name: Install Dependencies 67 | if: steps.cache-dep.outputs.cache-hit != 'true' 68 | run: make update_dep ARCH=x86_64 69 | - name: Build Release Version 70 | run: | 71 | echo 'export PATH="/usr/local/opt/bison/bin:$PATH"' >> ~/.bash_profile 72 | source ~/.bash_profile 73 | bison -V 74 | make ARCH=x86_64 75 | - name: Build Debug Version 76 | run: | 77 | echo 'export PATH="/usr/local/opt/bison/bin:$PATH"' >> ~/.bash_profile 78 | source ~/.bash_profile 79 | bison -V 80 | make debug ARCH=x86_64 81 | - name: Verify Build 82 | run: | 83 | make verify_builds 84 | - name: Unit test 85 | run: make test 86 | MacOs_Apple_Silicon: 87 | runs-on: macOS-latest 88 | steps: 89 | - name: Checking Out Source Code 90 | uses: actions/checkout@v1 91 | - name: Configure Environment 92 | run: | 93 | brew install flex 94 | brew install bison 95 | - name: Setup Python 96 | uses: actions/setup-python@v2 97 | with: 98 | python-version: '3.x' 99 | architecture: 'x64' 100 | - name: Get Cache Directory 101 | id: cache-dir 102 | run: | 103 | echo "::set-output name=dir::$(pwd)" 104 | - name: Load Dependencies from Cache 105 | uses: actions/cache@v1 106 | id: cache-dep 107 | with: 108 | path: ${{ steps.cache-dir.outputs.dir }}/dependencies 109 | key: MacOS-Apple-Silicon-dep-ver-8 110 | - name: Install Dependencies 111 | if: steps.cache-dep.outputs.cache-hit != 'true' 112 | run: make update_dep ARCH=arm64 113 | - name: Build Release Version 114 | run: | 115 | echo 'export PATH="/usr/local/opt/bison/bin:$PATH"' >> ~/.bash_profile 116 | source ~/.bash_profile 117 | bison -V 118 | make ARCH=arm64 119 | - name: Build Debug Version 120 | run: | 121 | echo 'export PATH="/usr/local/opt/bison/bin:$PATH"' >> ~/.bash_profile 122 | source ~/.bash_profile 123 | bison -V 124 | make debug ARCH=arm64 125 | - name: Verify Build 126 | run: | 127 | make verify_builds 128 | Ubuntu_20_04: 129 | runs-on: ubuntu-20.04 130 | steps: 131 | - name: Checking Out Source Code 132 | uses: actions/checkout@v1 133 | - name: Configure Environment 134 | run: | 135 | sudo apt-get install flex 136 | sudo apt-get install bison 137 | - name: Setup Python 138 | uses: actions/setup-python@v2 139 | with: 140 | python-version: '3.x' 141 | architecture: 'x64' 142 | - name: Get Cache Directory 143 | id: cache-dir 144 | run: | 145 | echo "::set-output name=dir::$(pwd)" 146 | - name: Load Dependencies from Cache 147 | uses: actions/cache@v1 148 | id: cache-dep 149 | with: 150 | path: ${{ steps.cache-dir.outputs.dir }}/dependencies 151 | key: Ubuntu-Focal-dep-ver-7 152 | - name: Install Dependencies 153 | if: steps.cache-dep.outputs.cache-hit != 'true' 154 | run: make update_dep 155 | - name: Build Release Version 156 | run: make 157 | - name: Build Debug Version 158 | run: make debug 159 | - name: Verify Build 160 | run: | 161 | make verify_builds 162 | - name: Unit test 163 | run: make test 164 | Ubuntu_18_04: 165 | runs-on: ubuntu-18.04 166 | steps: 167 | - name: Checking Out Source Code 168 | uses: actions/checkout@v1 169 | - name: Configure Environment 170 | run: | 171 | sudo apt-get install flex 172 | sudo apt-get install bison 173 | - name: Setup Python 174 | uses: actions/setup-python@v2 175 | with: 176 | python-version: '3.x' 177 | architecture: 'x64' 178 | - name: Get Cache Directory 179 | id: cache-dir 180 | run: | 181 | echo "::set-output name=dir::$(pwd)" 182 | - name: Load Dependencies from Cache 183 | uses: actions/cache@v1 184 | id: cache-dep 185 | with: 186 | path: ${{ steps.cache-dir.outputs.dir }}/dependencies 187 | key: Ubuntu-Binoic-dep-ver-7 188 | - name: Install Dependencies 189 | if: steps.cache-dep.outputs.cache-hit != 'true' 190 | run: make update_dep 191 | - name: Build Release Version 192 | run: make 193 | - name: Build Debug Version 194 | run: make debug 195 | - name: Verify Build 196 | run: | 197 | make verify_builds 198 | - name: Unit test 199 | run: make test 200 | Ubuntu_16_04: 201 | runs-on: ubuntu-16.04 202 | steps: 203 | - name: Checking Out Source Code 204 | uses: actions/checkout@v1 205 | - name: Configure Environment 206 | run: | 207 | sudo apt-get install flex 208 | sudo apt-get install bison 209 | sudo apt-get install -y software-properties-common 210 | sudo add-apt-repository ppa:ubuntu-toolchain-r/test 211 | sudo apt update 212 | sudo apt install g++-7 -y 213 | sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 60 --slave /usr/bin/g++ g++ /usr/bin/g++-7 214 | sudo update-alternatives --config gcc 215 | gcc --version 216 | g++ --version 217 | - name: Setup Python 218 | uses: actions/setup-python@v2 219 | with: 220 | python-version: '3.x' 221 | architecture: 'x64' 222 | - name: Get Cache Directory 223 | id: cache-dir 224 | run: | 225 | echo "::set-output name=dir::$(pwd)" 226 | - name: Load Dependencies from Cache 227 | uses: actions/cache@v1 228 | id: cache-dep 229 | with: 230 | path: ${{ steps.cache-dir.outputs.dir }}/dependencies 231 | key: Ubuntu-Xenial-dep-ver-7 232 | - name: Install Dependencies 233 | if: steps.cache-dep.outputs.cache-hit != 'true' 234 | run: make update_dep 235 | - name: Build Release Version 236 | run: make 237 | - name: Build Debug Version 238 | run: make debug 239 | - name: Verify Build 240 | run: | 241 | make verify_builds 242 | - name: Unit test 243 | run: make test 244 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | dependencies/ 3 | _out/ 4 | proj_release/ 5 | proj_debug/ 6 | generated_src/ 7 | *.DS_Store 8 | src/include/tsl_version.h 9 | tsl/ 10 | cmake/tsl-config.cmake -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | # platform programming shading language. 4 | # 5 | # Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | # 7 | # TSL is a free software written for educational purpose. Anyone can distribute 8 | # or modify it under the the terms of the GNU General Public License Version 3 as 9 | # published by the Free Software Foundation. However, there is NO warranty that 10 | # all components are functional in a perfect manner. Without even the implied 11 | # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License along with 15 | # this program. If not, see . 16 | # 17 | 18 | cmake_minimum_required (VERSION 3.8) 19 | 20 | # somehow using the default policy of 3.7 will crash the unit tests, I have no time looking into it for now 21 | cmake_policy(VERSION 3.1) 22 | 23 | set(CMAKE_CXX_STANDARD 17) 24 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 25 | set(CMAKE_CXX_EXTENSIONS OFF) 26 | 27 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 28 | 29 | SET( LLVM_DEBUG "NO" CACHE BOOL "Compile with debug version llvm." ) 30 | 31 | # this will avoid generate ZERO_CHECK project 32 | # set(CMAKE_SUPPRESS_REGENERATION true) 33 | 34 | # disallow generation of the unit test projects 35 | OPTION(BUILD_TSL_INSTALL "Only generate TSL library" OFF) 36 | 37 | # define platform 38 | if (WIN32) 39 | set(TSL_PLATFORM_WIN true) 40 | set(TSL_PLATFORM_MAC false) 41 | set(TSL_PLATFORM_LINUX false) 42 | set(TSL_PLATFORM_NAME "Windows" ) 43 | elseif(APPLE) 44 | set(TSL_PLATFORM_WIN false) 45 | set(TSL_PLATFORM_MAC true) 46 | set(TSL_PLATFORM_LINUX false) 47 | set(TSL_PLATFORM_NAME "Mac OS" ) 48 | elseif(UNIX) 49 | set(TSL_PLATFORM_WIN false) 50 | set(TSL_PLATFORM_MAC false) 51 | set(TSL_PLATFORM_LINUX true) 52 | set(TSL_PLATFORM_NAME "Linux" ) 53 | endif() 54 | 55 | set (PROJ_NAME ${PROJECT_NAME}) 56 | set (TSL_LIBRARY_VERSION_MAJOR 1) 57 | set (TSL_LIBRARY_VERSION_MINOR 0) 58 | set (TSL_LIBRARY_VERSION_PATCH 1) 59 | 60 | # if we are building on MacOS, indicate which version Mac it is building on 61 | if (TSL_PLATFORM_MAC) 62 | if (CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64") 63 | message( "Building on Intel Mac") 64 | else() 65 | message( "Building on Apple Silicon Mac") 66 | endif() 67 | endif(TSL_PLATFORM_MAC) 68 | 69 | # create TSL solution 70 | project (TSL) 71 | 72 | # generate tsl header file based on tsl version 73 | set (versionfile tsl_version.h) 74 | message (STATUS "Create ${versionfile} from ${versionfile}.in") 75 | configure_file (${TSL_SOURCE_DIR}/src/include/${versionfile}.in "${TSL_SOURCE_DIR}/src/include/${versionfile}" @ONLY) 76 | list (APPEND version_head "${TSL_SOURCE_DIR}/src/include/${versionfile}") 77 | 78 | # loading llvm library, this is mandatory for compiling tsl, make sure it looks for a local llvm library 79 | set(LLVM_DIR ${TSL_SOURCE_DIR}/dependencies/llvm/lib/cmake/llvm) 80 | 81 | # make sure this new policy is enabled to surpress an unnecessary warning 82 | if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12.0") 83 | cmake_policy(SET CMP0074 NEW) 84 | endif() 85 | 86 | # find llvm librar${TSL_SOURCE_DIR}/thirdparty/gtesty 87 | find_package(LLVM REQUIRED CONFIG) 88 | # output some information to make sure llvm is correctly located 89 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 90 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 91 | 92 | # google test is packed with tsl source code 93 | set(GTEST_DIR ${TSL_SOURCE_DIR}/src/thirdparty/gtest) 94 | MARK_AS_ADVANCED(GTEST_DIR) 95 | # find google test library 96 | find_package(GTEST REQUIRED CONFIG) 97 | 98 | # this is all include files of TSL core library 99 | file(GLOB_RECURSE tsl_include src/include/*.h) 100 | 101 | # make sure there is a seperate macro for debug build 102 | set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DTSL_DEBUG") 103 | 104 | set( CMAKE_CXX_FLAGS "${GTEST_HAS_TR1_TUPLE} -DGTEST_HAS_TR1_TUPLE=0" ) 105 | 106 | add_subdirectory( src/tsl_lib ) 107 | add_subdirectory( src/tsl_test ) 108 | 109 | # only generate the two projects if this macro is not defined 110 | if (NOT ${BUILD_TSL_INSTALL}) 111 | add_subdirectory( src/llvm_test ) 112 | add_subdirectory( src/tsl_sample ) 113 | endif() 114 | 115 | # hide the llvm generated project 116 | set_target_properties (intrinsics_gen PROPERTIES FOLDER LLVM_Generated) -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | # 2 | # This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | # platform programming shading language. 4 | # 5 | # Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | # 7 | # TSL is a free software written for educational purpose. Anyone can distribute 8 | # or modify it under the the terms of the GNU General Public License Version 3 as 9 | # published by the Free Software Foundation. However, there is NO warranty that 10 | # all components are functional in a perfect manner. Without even the implied 11 | # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License along with 15 | # this program. If not, see . 16 | # 17 | 18 | MAKEFLAGS += --silent 19 | 20 | YELLOW=`tput setaf 3` 21 | NOCOLOR=`tput sgr0` 22 | 23 | # detect the current arch, by default it is what the current platform is. 24 | # this can be overwritten like this so that we can do cross compiling 25 | # make release ARCH=arm64 26 | ARCH ?= $(shell uname -m) 27 | 28 | all: 29 | make release 30 | 31 | full: 32 | make update 33 | make clean 34 | make 35 | make test 36 | 37 | clean: 38 | echo ${YELLOW}Cleaning all temporary file${NOCOLOR} 39 | rm -rf bin generated_src 40 | 41 | update: 42 | echo ${YELLOW}Sycning latest code${NOCOLOR} 43 | git pull 44 | 45 | generate_src: 46 | echo ${YELLOW}Generating flex and bison source code${NOCOLOR} 47 | rm -rf generated_src 48 | mkdir generated_src 49 | 50 | bison -d src/tsl_lib/compiler/grammar.y -o generated_src/compiled_grammar.cpp 51 | flex src/tsl_lib/compiler/lex.l 52 | 53 | release: 54 | echo ${YELLOW}Building release${NOCOLOR} 55 | make update_dep 56 | rm -rf proj_release;mkdir proj_release;cd proj_release;cmake -DCMAKE_OSX_ARCHITECTURES=${ARCH} -DCMAKE_BUILD_TYPE=Release ..;make -j 4;cd ..; 57 | 58 | debug: 59 | echo ${YELLOW}Building debug${NOCOLOR} 60 | make update_dep 61 | rm -rf proj_debug;mkdir proj_debug;cd proj_debug;cmake -DCMAKE_OSX_ARCHITECTURES=${ARCH} -DCMAKE_BUILD_TYPE=Debug ..;make -j 4;cd ..; 62 | 63 | test: 64 | echo ${YELLOW}Running unit tests${NOCOLOR} 65 | ./bin/tsl_test_r 66 | ./bin/llvm_test_r 67 | 68 | update_dep: 69 | echo ${YELLOW}Downloading dependencies ${NOCOLOR} 70 | python3 ./scripts/get_dependencies.py FALSE ${ARCH} 71 | 72 | force_update_dep: 73 | echo ${YELLOW}Downloading dependencies ${NOCOLOR} 74 | python3 ./scripts/get_dependencies.py TRUE ${ARCH} 75 | 76 | verify_builds: 77 | echo ${YELLOW}Verifying builds ${NOCOLOR} 78 | python3 ./scripts/verify_builds.py 79 | 80 | INSTALL_PATH ?= "./tsl" 81 | install: 82 | echo ${YELLOW}Build and install TSL${NOCOLOR} 83 | echo "Install path:" $(INSTALL_PATH) 84 | make release 85 | cmake -DCMAKE_OSX_ARCHITECTURES=${ARCH} -DCMAKE_INSTALL_PREFIX=$(INSTALL_PATH) -P ./proj_release/cmake_install.cmake 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tiny-Shading-Language 2 | [![Build TSL](https://github.com/JiayinCao/Tiny-Shading-Language/workflows/Build%20TSL/badge.svg)](https://actions-badge.atrox.dev/Jiayincao/Tiny-Shading-Language/goto) 3 | [![License](https://img.shields.io/badge/License-GPL3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0.en.html) 4 | 5 | TSL ( Tiny Shading Language ) is my own shading language designed for my offline renderer [SORT](http://sort-renderer.com/). 6 | 7 | The goal of TSL is to provide shader programming ability to open source ray tracer projects. 8 | Though, it is specifically designed for my own renderer. 9 | This programming language can totally be used in any other CPU based ray tracing project. 10 | 11 | Following is the image generated in the sample ray tracing program with TSL integrated in this project 12 | ![](https://github.com/JiayinCao/Tiny-Shading-Language/blob/master/gallery/tsl_sample.jpg?raw=true) 13 | 14 | # Note 15 | 16 | TSL is functional enough to replace all of the OSL features used in SORT at this point. 17 | However, due to crunching features in TSL, lots of code is terribly designed. 18 | I'm refactoring this library now to make it a bit more robust and friendly. 19 | -------------------------------------------------------------------------------- /cmake/tsl-config.cmake.in: -------------------------------------------------------------------------------- 1 | # 2 | # This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | # platform programming shading language. 4 | # 5 | # Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | # 7 | # TSL is a free software written for educational purpose. Anyone can distribute 8 | # or modify it under the the terms of the GNU General Public License Version 3 as 9 | # published by the Free Software Foundation. However, there is NO warranty that 10 | # all components are functional in a perfect manner. Without even the implied 11 | # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License along with 15 | # this program. If not, see . 16 | # 17 | 18 | # get the current directory 19 | get_filename_component(TSL_INSTALL_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) 20 | 21 | # tsl version 22 | set( TSL_LIBRARY_VERSION_MAJOR @TSL_LIBRARY_VERSION_MAJOR@ ) 23 | set( TSL_LIBRARY_VERSION_MINOR @TSL_LIBRARY_VERSION_MINOR@ ) 24 | set( TSL_LIBRARY_VERSION_PATCH @TSL_LIBRARY_VERSION_PATCH@ ) 25 | set( TSL_VERSION "@TSL_LIBRARY_VERSION_MAJOR@.@TSL_LIBRARY_VERSION_MINOR@.@TSL_LIBRARY_VERSION_PATCH@" ) 26 | 27 | # useful macros for tsl library 28 | set( TSL_INCLUDE_DIR ${TSL_INSTALL_PREFIX}/include ) 29 | set( TSL_LIBRARY_DIR ${TSL_INSTALL_PREFIX}/lib ) 30 | set( TSL_RUNTIME_DIR ${TSL_INSTALL_PREFIX}/bin ) 31 | set( TSL_LIBS @TSL_LIB_NAME@ ) 32 | 33 | # helper function to copy dll to destination folder, this is needed on Windows to copy tsl dll 34 | function( tsl_runtime_copy dest_dir ) 35 | file(GLOB tsl_runtime "${TSL_INSTALL_PREFIX}/bin/tsl_r.*") 36 | file(COPY ${tsl_runtime} DESTINATION ${dest_dir}) 37 | endfunction() -------------------------------------------------------------------------------- /gallery/tsl_sample.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiayinCao/Tiny-Shading-Language/6e07155c3ab0958f98a25dc2b72f813b9d82bdbf/gallery/tsl_sample.jpg -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | :: 2 | :: This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | :: platform programming shading language. 4 | :: 5 | :: Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | :: 7 | :: TSL is a free software written for educational purpose. Anyone can distribute 8 | :: or modify it under the the terms of the GNU General Public License Version 3 as 9 | :: published by the Free Software Foundation. However, there is NO warranty that 10 | :: all components are functional in a perfect manner. Without even the implied 11 | :: warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | :: General Public License for more details. 13 | :: 14 | :: You should have received a copy of the GNU General Public License along with 15 | :: this program. If not, see . 16 | :: 17 | 18 | @echo off 19 | set TSL_DIR=%~dp0 20 | 21 | rem reset all variables first 22 | set CLEAN= 23 | set BUILD_RELEASE= 24 | set BUILD_DEBUG= 25 | set GENERATE_PROJ= 26 | set UPDATE_DEP= 27 | set FORCE_UPDATE_DEP= 28 | set CLEAN_DEP= 29 | set UPDATE= 30 | set GENERATE_SRC= 31 | set UNIT_TEST= 32 | set FULL= 33 | set INSTALL= 34 | set VERIFY_BUILDS= 35 | set RESOLVED_INSTALL_PATH="./tsl" 36 | 37 | rem parse arguments 38 | :argv_loop 39 | if NOT "%1" == "" ( 40 | if "%1" == "clean" ( 41 | set CLEAN=1 42 | goto EOF 43 | )else if "%1" == "update" ( 44 | set UPDATE=1 45 | goto EOF 46 | )else if "%1" == "clean_dep" ( 47 | set CLEAN_DEP=1 48 | goto EOF 49 | )else if "%1" == "update_dep" ( 50 | set UPDATE_DEP=1 51 | goto EOF 52 | )else if "%1" == "force_update_dep" ( 53 | set FORCE_UPDATE_DEP=1 54 | goto EOF 55 | )else if "%1" == "generate_src" ( 56 | set GENERATE_SRC=1 57 | goto EOF 58 | )else if "%1" == "generate_proj" ( 59 | set GENERATE_PROJ=1 60 | goto EOF 61 | )else if "%1" == "release" ( 62 | set BUILD_RELEASE=1 63 | goto EOF 64 | )else if "%1" == "debug" ( 65 | set BUILD_DEBUG=1 66 | goto EOF 67 | )else if "%1" == "test" ( 68 | set UNIT_TEST=1 69 | goto EOF 70 | )else if "%1" == "full" ( 71 | set FULL=1 72 | goto EOF 73 | )else if "%1" == "install" ( 74 | set INSTALL=1 75 | if "%2" == "INSTALL_PATH" ( 76 | set RESOLVED_INSTALL_PATH=%3 77 | ) 78 | goto EOF 79 | )else if "%1" == "verify_builds" ( 80 | set VERIFY_BUILDS=1 81 | goto EOF 82 | )else ( 83 | echo Unrecognized Command 84 | goto EOF 85 | ) 86 | )else if "%1" == "" ( 87 | set BUILD_RELEASE=1 88 | goto EOF 89 | ) 90 | 91 | :EOF 92 | 93 | if "%CLEAN%" == "1" ( 94 | echo Cleaning all temporary file 95 | powershell Remove-Item -path ./bin -recurse -ErrorAction Ignore 96 | powershell Remove-Item -path ./generated_src -recurse -ErrorAction Ignore 97 | powershell Remove-Item -path ./proj_release -recurse -ErrorAction Ignore 98 | powershell Remove-Item -path ./proj_debug -recurse -ErrorAction Ignore 99 | powershell Remove-Item -path ./_out -recurse -ErrorAction Ignore 100 | goto EOF 101 | ) 102 | 103 | if "%CLEAN_DEP%" == "1" ( 104 | echo Cleaning all dependencies file 105 | powershell Remove-Item -path ./dependencies -recurse -ErrorAction Ignore 106 | goto EOF 107 | ) 108 | 109 | if "%UPDATE_DEP%" == "1" ( 110 | echo Downloading dependencies 111 | py .\scripts\get_dependencies.py 112 | goto EOF 113 | ) 114 | 115 | if "%FORCE_UPDATE_DEP%" == "1" ( 116 | echo Downloading dependencies 117 | py .\scripts\get_dependencies.py TRUE 118 | goto EOF 119 | ) 120 | 121 | if "%UPDATE%" == "1" ( 122 | echo Sycning latest code 123 | git pull 124 | goto EOF 125 | ) 126 | 127 | if "%BUILD_RELEASE%" == "1" ( 128 | echo Building release 129 | 130 | py .\scripts\get_dependencies.py 131 | 132 | powershell New-Item -Force -ItemType directory -Path proj_release 133 | cd proj_release 134 | cmake -A x64 .. 135 | msbuild /p:Configuration=Release TSL.sln 136 | 137 | :: catch msbuild error 138 | if ERRORLEVEL 1 ( 139 | goto BUILD_ERR 140 | ) 141 | 142 | cd .. 143 | ) 144 | 145 | if "%BUILD_DEBUG%" == "1" ( 146 | echo Building debug 147 | 148 | py .\scripts\get_dependencies.py 149 | 150 | powershell New-Item -Force -ItemType directory -Path proj_debug 151 | cd proj_debug 152 | cmake -A x64 .. 153 | msbuild /p:Configuration=Debug TSL.sln 154 | 155 | :: catch msbuild error 156 | if ERRORLEVEL 1 ( 157 | goto BUILD_ERR 158 | ) 159 | 160 | cd .. 161 | ) 162 | 163 | if "%GENERATE_PROJ%" == "1" ( 164 | echo Generating Visual Studio Project 165 | 166 | powershell New-Item -Force -ItemType directory -Path _out 167 | cd _out 168 | cmake -A x64 .. 169 | cd .. 170 | ) 171 | 172 | if "%GENERATE_SRC%" == "1" ( 173 | echo Generating flex and bison source code 174 | 175 | powershell Remove-Item -path ./generated_src -recurse -ErrorAction Ignore 176 | mkdir generated_src 177 | 178 | .\dependencies\flex_bison\win_bison.exe -d .\src\tsl_lib\compiler\grammar.y -o .\generated_src\compiled_grammar.cpp 179 | .\dependencies\flex_bison\win_flex.exe .\src\tsl_lib\compiler\lex.l 180 | ) 181 | 182 | if "%UNIT_TEST%" == "1" ( 183 | echo Running unit tests 184 | .\bin\tsl_test_r.exe 185 | .\bin\llvm_test_r.exe 186 | ) 187 | 188 | if "%FULL%" == "1" ( 189 | make update 190 | make clean 191 | make 192 | make test 193 | ) 194 | 195 | if "%INSTALL%" == "1" ( 196 | echo Build and install TSL 197 | echo Install Path: %RESOLVED_INSTALL_PATH% 198 | make 199 | cmake -DCMAKE_INSTALL_PREFIX=%RESOLVED_INSTALL_PATH% -P ./proj_release/cmake_install.cmake 200 | ) 201 | 202 | if "%VERIFY_BUILDS%" == "1" ( 203 | echo Verifying builds 204 | py .\scripts\verify_builds.py 205 | ) 206 | 207 | :EOF 208 | exit /b 0 209 | :BUILD_ERR 210 | exit /b 1 -------------------------------------------------------------------------------- /scripts/get_dependencies.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | # platform programming shading language. 4 | # 5 | # Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | # 7 | # TSL is a free software written for educational purpose. Anyone can distribute 8 | # or modify it under the the terms of the GNU General Public License Version 3 as 9 | # published by the Free Software Foundation. However, there is NO warranty that 10 | # all components are functional in a perfect manner. Without even the implied 11 | # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License along with 15 | # this program. If not, see . 16 | # 17 | 18 | # This is a helper script to get dependencies 19 | 20 | import os 21 | import urllib.request 22 | import zipfile 23 | import shutil 24 | import sys 25 | import subprocess 26 | 27 | # whether to force syncing 28 | forcing_sync = False 29 | arch = 'x86_64' 30 | 31 | if len(sys.argv) > 1: 32 | # output a message indicating this is a force syncing 33 | print( 'Force syncing dependencies.' ) 34 | 35 | if sys.argv[1] == 'TRUE': 36 | forcing_sync = sys.argv[1] 37 | 38 | if len(sys.argv) > 2: 39 | if sys.argv[2] == 'arm64': 40 | arch = sys.argv[2] 41 | 42 | # dependencies folder 43 | dep_dir = 'dependencies' 44 | 45 | # whether to sync dependencies 46 | sync_dep = False 47 | 48 | # if forcing syncing is enabled, delete the dependencies even if it exists 49 | if forcing_sync: 50 | # check if the folder already exists, if it does, remove it 51 | if os.path.isdir(dep_dir): 52 | # output a warning 53 | print('The dependencies are purged.') 54 | 55 | # remove the folder 56 | shutil.rmtree(dep_dir) 57 | 58 | # re-create the folder again 59 | os.makedirs(dep_dir) 60 | 61 | sync_dep = True 62 | else: 63 | # this might not be very robust since it just check the folder 64 | # if there is a broken dependencies folder, it will fail to build 65 | if os.path.isdir(dep_dir) is False: 66 | sync_dep = True 67 | else: 68 | print('Dependencies are up to date, no need to sync.') 69 | 70 | # sync a dependency from server 71 | def sync_dep_utility( name, url, target ): 72 | print( 'Syncing ' + name ) 73 | 74 | # sync file 75 | dummy_folder = 'dummy/' 76 | 77 | # check if the folder already exists, if it does, remove it 78 | if os.path.isdir(dummy_folder): 79 | shutil.rmtree(dummy_folder) 80 | # make the dir 81 | os.makedirs(dummy_folder) 82 | 83 | # sync the file 84 | index_file_name = dummy_folder + 'index.txt' 85 | urllib.request.urlretrieve(url + 'files.txt', index_file_name) 86 | 87 | # Using readlines() 88 | index_file = open(index_file_name, 'r') 89 | Lines = index_file.readlines() 90 | 91 | # sync all files down 92 | for index, line in enumerate(Lines, start=1): 93 | zip_file_name = line.rstrip() 94 | file_name = dummy_folder + zip_file_name 95 | print( "zip file: " + file_name ) 96 | urllib.request.urlretrieve(url + zip_file_name, file_name) 97 | 98 | # uncompress the zip file and make sure it is in the Dependencies folder 99 | for line in Lines: 100 | zip_file_name = dummy_folder + line.rstrip() 101 | with zipfile.ZipFile(zip_file_name,"r") as zip_ref: 102 | print( "extracing file: " + zip_file_name) 103 | zip_ref.extractall(target) 104 | 105 | # close the file 106 | index_file.close() 107 | 108 | # delete the temporary file 109 | shutil.rmtree(dummy_folder) 110 | 111 | # sync dependencies if needed 112 | if sync_dep: 113 | # flex and bison is only needed on Windows 114 | if sys.platform == 'win32': 115 | #sync flex and bison 116 | sync_dep_utility('flex and bison', 'https://raw.githubusercontent.com/JiayinCao/Tiny-Shading-Language/dependencies/flex_bison/win/x86_64/', dep_dir + '/flex_bison') 117 | 118 | # sync llvm 119 | if sys.platform == 'win32': 120 | sync_dep_utility('llvm', 'https://raw.githubusercontent.com/JiayinCao/Tiny-Shading-Language/dependencies/llvm_10_0_0/win/x86_64/', dep_dir) 121 | elif sys.platform == "linux" or sys.platform == "linux2": 122 | sync_dep_utility('llvm', 'https://raw.githubusercontent.com/JiayinCao/Tiny-Shading-Language/dependencies/llvm_10_0_0/linux/x86_64/', dep_dir) 123 | elif sys.platform == 'darwin': 124 | if arch == 'arm64': 125 | print('Sycning arm version llvm...') 126 | sync_dep_utility('llvm', 'https://raw.githubusercontent.com/JiayinCao/Tiny-Shading-Language/dependencies/llvm_10_0_0/mac/arm64/', dep_dir) 127 | elif arch == 'x86_64': 128 | print('Syncing x86_64 version llvm...') 129 | sync_dep_utility('llvm', 'https://raw.githubusercontent.com/JiayinCao/Tiny-Shading-Language/dependencies/llvm_10_0_0/mac/x86_64/', dep_dir) 130 | else: 131 | print('Error, unknown archtecture!') 132 | -------------------------------------------------------------------------------- /scripts/verify_builds.py: -------------------------------------------------------------------------------- 1 | # 2 | # This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | # platform programming shading language. 4 | # 5 | # Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | # 7 | # TSL is a free software written for educational purpose. Anyone can distribute 8 | # or modify it under the the terms of the GNU General Public License Version 3 as 9 | # published by the Free Software Foundation. However, there is NO warranty that 10 | # all components are functional in a perfect manner. Without even the implied 11 | # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License along with 15 | # this program. If not, see . 16 | # 17 | 18 | import sys 19 | import os 20 | 21 | files_to_verify = ("./bin/tsl_test_r", "./bin/tsl_test_d", "./bin/llvm_test_r", 22 | "./bin/llvm_test_d", "./bin/tsl_sample_r", "./bin/tsl_sample_d") 23 | 24 | if sys.platform == 'win32': 25 | files_to_verify = ("./bin/tsl_test_r.exe", "./bin/tsl_test_d.exe", "./bin/llvm_test_r.exe", 26 | "./bin/llvm_test_d.exe", "./bin/tsl_sample_r.exe", "./bin/tsl_sample_d.exe") 27 | 28 | def main(): 29 | missing_build = False 30 | 31 | for file in files_to_verify: 32 | if os.path.exists(file) is False: 33 | missing_build = True 34 | print('Missing build ' + file) 35 | else: 36 | os.system('file ' + file) 37 | 38 | if missing_build: 39 | sys.exit(1) 40 | 41 | if __name__=="__main__": 42 | main() -------------------------------------------------------------------------------- /src/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.0.1", 3 | "configurations": [ 4 | { 5 | "name": "Run Release", 6 | "type": "cppdbg", 7 | "request": "launch", 8 | "preLaunchTask": "Build (Release)", 9 | "program": "${workspaceFolder}/../bin/tsl_test_r", 10 | "args": [""], 11 | "stopAtEntry": false, 12 | "cwd": "${workspaceFolder}/../bin", 13 | "environment": [], 14 | "externalConsole": true, 15 | "osx":{ 16 | "MIMode": "lldb" 17 | }, 18 | "linux":{ 19 | "MIMode":"gdb" 20 | }, 21 | "windows":{ 22 | "type": "cppvsdbg", 23 | "program": "${workspaceFolder}/../bin/tsl_test_r.exe" 24 | } 25 | }, 26 | { 27 | "name": "Run Debug", 28 | "type": "cppdbg", 29 | "request": "launch", 30 | "preLaunchTask": "Build (Debug)", 31 | "program": "${workspaceFolder}/../bin/tsl_test_d", 32 | "args": [""], 33 | "stopAtEntry": false, 34 | "cwd": "${workspaceFolder}/../bin", 35 | "environment": [], 36 | "externalConsole": true, 37 | "osx":{ 38 | "MIMode": "lldb" 39 | }, 40 | "linux":{ 41 | "MIMode":"gdb" 42 | }, 43 | "windows":{ 44 | "type": "cppvsdbg", 45 | "program": "${workspaceFolder}/../bin/tsl_test_d.exe" 46 | } 47 | } 48 | ] 49 | } -------------------------------------------------------------------------------- /src/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "typeinfo": "cpp", 4 | "ios": "cpp", 5 | "__config": "cpp", 6 | "__nullptr": "cpp", 7 | "cstddef": "cpp", 8 | "exception": "cpp", 9 | "initializer_list": "cpp", 10 | "new": "cpp", 11 | "stdexcept": "cpp", 12 | "type_traits": "cpp", 13 | "algorithm": "cpp", 14 | "__functional_base": "cpp", 15 | "istream": "cpp", 16 | "locale": "cpp", 17 | "memory": "cpp", 18 | "thread": "cpp", 19 | "tuple": "cpp", 20 | "utility": "cpp", 21 | "iterator": "cpp", 22 | "string": "cpp", 23 | "string_view": "cpp", 24 | "vector": "cpp", 25 | "ostream": "cpp", 26 | "iosfwd": "cpp", 27 | "queue": "cpp", 28 | "__mutex_base": "cpp", 29 | "condition_variable": "cpp", 30 | "__split_buffer": "cpp", 31 | "deque": "cpp", 32 | "list": "cpp", 33 | "__locale": "cpp", 34 | "regex": "cpp", 35 | "__functional_base_03": "cpp", 36 | "__hash_table": "cpp", 37 | "__tree": "cpp", 38 | "__tuple": "cpp", 39 | "chrono": "cpp", 40 | "functional": "cpp", 41 | "limits": "cpp", 42 | "ratio": "cpp", 43 | "fstream": "cpp", 44 | "__bit_reference": "cpp", 45 | "__debug": "cpp", 46 | "__string": "cpp", 47 | "__threading_support": "cpp", 48 | "atomic": "cpp", 49 | "bitset": "cpp", 50 | "cctype": "cpp", 51 | "cmath": "cpp", 52 | "cstdarg": "cpp", 53 | "cstdint": "cpp", 54 | "cstdio": "cpp", 55 | "cstdlib": "cpp", 56 | "cstring": "cpp", 57 | "ctime": "cpp", 58 | "cwchar": "cpp", 59 | "cwctype": "cpp", 60 | "iomanip": "cpp", 61 | "iostream": "cpp", 62 | "map": "cpp", 63 | "mutex": "cpp", 64 | "set": "cpp", 65 | "sstream": "cpp", 66 | "streambuf": "cpp", 67 | "system_error": "cpp", 68 | "unordered_map": "cpp", 69 | "unordered_set": "cpp", 70 | "__errc": "cpp", 71 | "__node_handle": "cpp", 72 | "optional": "cpp" 73 | } 74 | } -------------------------------------------------------------------------------- /src/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Build (Debug)", 6 | "type": "shell", 7 | "command": "reset;cd ..;mkdir proj_debug;cd proj_debug;cmake -DCMAKE_BUILD_TYPE=Debug ..;make -j6", 8 | "group": { 9 | "kind": "build", 10 | "isDefault": true 11 | }, 12 | "problemMatcher": "$gcc", 13 | "windows":{ 14 | "command": "cd ..;New-Item -Force -ItemType directory -Path proj_debug;cd proj_debug;cmake -A x64 ..;msbuild /p:Configuration=Debug /property:GenerateFullPaths=true /t:build TSL.sln" 15 | } 16 | }, 17 | { 18 | "label": "Re-Build (Debug)", 19 | "type": "shell", 20 | "command": "reset;cd ..;rm -rf proj_debug;mkdir proj_debug;cd proj_debug;cmake -DCMAKE_BUILD_TYPE=Debug ..;make clean;make -j6", 21 | "group": { 22 | "kind": "build", 23 | "isDefault": true 24 | }, 25 | "problemMatcher": "$gcc", 26 | "windows":{ 27 | "command": "cd ..;New-Item -Force -ItemType directory -Path proj_debug;cd proj_debug;cmake -A x64 ..;msbuild /p:Configuration=Debug /property:GenerateFullPaths=true /t:clean,build TSL.sln" 28 | } 29 | }, 30 | { 31 | "label": "Build (Release)", 32 | "type": "shell", 33 | "command": "reset;cd ..;mkdir proj_release;cd proj_release;cmake -DCMAKE_BUILD_TYPE=Release ..;make -j6", 34 | "group": { 35 | "kind": "build", 36 | "isDefault": true 37 | }, 38 | "problemMatcher": "$gcc", 39 | "windows":{ 40 | "command": "cd ..;New-Item -Force -ItemType directory -Path proj_release;cd proj_release;cmake -A x64 ..;msbuild /p:Configuration=Release /property:GenerateFullPaths=true /t:build TSL.sln" 41 | } 42 | }, 43 | { 44 | "label": "Re-Build (Release)", 45 | "type": "shell", 46 | "command": "reset;cd ..;rm -rf proj_release;mkdir proj_release;cd proj_release;cmake -DCMAKE_BUILD_TYPE=Release ..;make clean;make -j6", 47 | "group": { 48 | "kind": "build", 49 | "isDefault": true 50 | }, 51 | "problemMatcher": "$gcc", 52 | "windows":{ 53 | "command": "cd ..;New-Item -Force -ItemType directory -Path proj_release;cd proj_release;cmake -A x64 ..;msbuild /p:Configuration=Release /property:GenerateFullPaths=true /t:clean,build TSL.sln" 54 | } 55 | }, 56 | ] 57 | } -------------------------------------------------------------------------------- /src/include/tsl_define.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "tsl_version.h" 21 | 22 | TSL_NAMESPACE_BEGIN 23 | 24 | // define platform for tsl 25 | #if defined(_WIN32) || defined(_WIN64) 26 | #define TSL_ON_WINDOWS 27 | #elif defined(__linux__) 28 | #define TSL_ON_LINUX 29 | 30 | // Make sure the compiler is C++14 compatible. Otherwise, make it clear that it is necessary to compile TSL in an error message. 31 | #if (__cplusplus < 201300L) 32 | #error "TSL heavily uses features of C++14/11, please make sure you have a C++14 compatible compiler." 33 | #endif 34 | #elif defined(__APPLE__) 35 | #define TSL_ON_MAC 36 | 37 | #if __aarch64__ 38 | #define TSL_ON_ARM_MAC 39 | #endif 40 | 41 | // Make sure the compiler is C++14 compatible. Otherwise, make it clear that it is necessary to compile TSL in an error message. 42 | #if (__cplusplus < 201300L) 43 | #error "TSL heavily uses features of C++14/11, please make sure you have a C++14 compatible compiler." 44 | #endif 45 | #endif 46 | 47 | #if defined(TSL_ON_WINDOWS) 48 | #if BUILDING_TSL 49 | #define TSL_INTERFACE __declspec(dllexport) 50 | #else 51 | #define TSL_INTERFACE __declspec(dllimport) 52 | #endif 53 | #elif defined(TSL_ON_LINUX) || defined(TSL_ON_MAC) 54 | #if BUILDING_TSL 55 | #define TSL_INTERFACE __attribute__((visibility("default"))) 56 | #else 57 | #define TSL_INTERFACE 58 | #endif 59 | #else 60 | // do nothing and hope for the best? 61 | #define TSL_INTERFACE 62 | #define IMPORT 63 | #error "Unknown dynamic link import/export semantics." 64 | #endif 65 | 66 | // Hide the constructors to prevent it from being constructed in a way that TSL doesn't expect. 67 | // Note, TSL won't even implemented these functions because if TSL users try to invoke either of these calls, compiling will 68 | // fail first and there is no way to see undefined symbol error at all. 69 | #define TSL_HIDE_CONSTRUCTOR(T, ...) private:\ 70 | T(__VA_ARGS__); /* Hide construcotr. */ \ 71 | T(T&); /* Hide copy constructor. */ \ 72 | T(T&&); /* Hide movable constructor. */ 73 | 74 | // Helper macros to make class friendship. Code using TSL will not be interested in learning the friendship among the classes. 75 | // So if it is not TSL library code including this file, it won't even generate any code with this macro. 76 | #if BUILDING_TSL 77 | #define TSL_MAKE_CLASS_FRIEND(T) friend class T; 78 | #define TSL_MAKE_STRUCT_FRIEND(T) friend struct T; 79 | #else 80 | #define TSL_MAKE_CLASS_FRIEND(T) /* ignore me */ 81 | #define TSL_MAKE_STRUCT_FRIEND(T) /* ignore me */ 82 | #endif 83 | 84 | TSL_NAMESPACE_END -------------------------------------------------------------------------------- /src/include/tsl_version.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | 19 | /* 20 | -------------------------------------------------------------------- 21 | WARNING: 22 | This file is automatically generated, do not modify. 23 | -------------------------------------------------------------------- 24 | */ 25 | 26 | #pragma once 27 | 28 | // Version of tiny-shading-language: 29 | #define @PROJ_NAME@_VERSION_MAJOR @TSL_LIBRARY_VERSION_MAJOR@ 30 | #define @PROJ_NAME@_VERSION_MINOR @TSL_LIBRARY_VERSION_MINOR@ 31 | #define @PROJ_NAME@_VERSION_PATCH @TSL_LIBRARY_VERSION_PATCH@ 32 | #define @PROJ_NAME@_VERSION ( 65536 * @PROJ_NAME@_VERSION_MAJOR + 256 * @PROJ_NAME@_VERSION_MINOR + @PROJ_NAME@_VERSION_PATCH ) 33 | 34 | #define Tsl_Namespace Tsl_Namespace_@TSL_LIBRARY_VERSION_MAJOR@_@TSL_LIBRARY_VERSION_MINOR@_@TSL_LIBRARY_VERSION_PATCH@ 35 | 36 | #define TSL_NAMESPACE_BEGIN namespace Tsl_Namespace{ 37 | #define TSL_NAMESPACE_END } 38 | #define USE_TSL_NAMESPACE using namespace Tsl_Namespace; 39 | 40 | // This will generate something like "TinyShadingLanguage 1.2.3" 41 | #define TSL_MAKE_VERSION_STRING2(a,b,c) #a "." #b "." #c 42 | #define TSL_MAKE_VERSION_STRING(a,b,c) TSL_MAKE_VERSION_STRING2(a,b,c) 43 | #define TSL_LIBRARY_VERSION_STRING TSL_MAKE_VERSION_STRING(@PROJ_NAME@_VERSION_MAJOR, @PROJ_NAME@_VERSION_MINOR, @PROJ_NAME@_VERSION_PATCH ) 44 | #define TSL_INTRO_STRING "TinyShadingLanguage " TSL_LIBRARY_VERSION_STRING 45 | 46 | // This is just a hack to make sure the namespace is always valid 47 | TSL_NAMESPACE_BEGIN 48 | TSL_NAMESPACE_END -------------------------------------------------------------------------------- /src/llvm_test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | # platform programming shading language. 4 | # 5 | # Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | # 7 | # TSL is a free software written for educational purpose. Anyone can distribute 8 | # or modify it under the the terms of the GNU General Public License Version 3 as 9 | # published by the Free Software Foundation. However, there is NO warranty that 10 | # all components are functional in a perfect manner. Without even the implied 11 | # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License along with 15 | # this program. If not, see . 16 | # 17 | 18 | # collect all files in this library 19 | file(GLOB_RECURSE project_headers *.h *.hpp) 20 | file(GLOB_RECURSE project_cpps *.cpp) 21 | file(GLOB_RECURSE project_cs *.c) 22 | file(GLOB_RECURSE project_ccs *.cc) 23 | 24 | # group all categories of files into one macro 25 | set(all_project_files ${project_headers} ${project_cpps} ${project_cs} ${project_ccs}) 26 | set(all_files ${all_project_files} ${gtest_files}) 27 | 28 | # give each file a proper folder based on its path 29 | source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${all_project_files}) 30 | 31 | # a separate folder for files outside this folder 32 | source_group( "google test" FILES ${gtest_files} ) 33 | 34 | # include directories 35 | include_directories( "${TSL_SOURCE_DIR}/src/thirdparty" ${LLVM_INCLUDE_DIR} ) 36 | 37 | # specify the output directory 38 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${TSL_SOURCE_DIR}/bin") 39 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${TSL_SOURCE_DIR}/bin") 40 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${TSL_SOURCE_DIR}/bin") 41 | 42 | # an unit test project to verify features are ready in LLVM library 43 | add_executable(LLVM_Test ${all_files}) 44 | 45 | # Setup correct output name for different configurations 46 | set_target_properties( LLVM_Test PROPERTIES RELEASE_OUTPUT_NAME "llvm_test_r" ) 47 | set_target_properties( LLVM_Test PROPERTIES DEBUG_OUTPUT_NAME "llvm_test_d" ) 48 | 49 | # disable all warnings generated from LLVM 50 | if (TSL_PLATFORM_WIN) 51 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4244 /wd4146 /wd4267 /wd4141 /wd4624 /wd4005 /wd4996" ) 52 | 53 | # enable multi-thread compiling 54 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP${N}") 55 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP${N}") 56 | 57 | set_target_properties( LLVM_Test PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} /MD /EHsc" ) 58 | endif() 59 | 60 | if (TSL_PLATFORM_MAC OR TSL_PLATFORM_LINUX) 61 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") 62 | endif() 63 | 64 | # specify the llvm library to link 65 | llvm_map_components_to_libnames(llvm_libs Core ExecutionEngine Interpreter MC MCJIT Support nativecodegen) 66 | 67 | # link llvm libaries 68 | target_link_libraries(LLVM_Test ${llvm_libs}) -------------------------------------------------------------------------------- /src/llvm_test/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | /* 19 | This is a separate project just to verifying features requested by TSL are available and functional as 20 | expected. If the LLVM library is not 10.0.0, this is very necessary to confirm the behavior is exactly 21 | the same with this version since this is what I mainly used for delopment of TSL. Any bias in term of 22 | LLVM behavior will likely cause unknown result. 23 | 24 | Also this is not a full feature requests verification, but if certain LLVM library doesn't pass through 25 | these unit tests, it will not be used to compile TSL. 26 | */ 27 | #include 28 | #include "gtest/gtest.h" 29 | 30 | int main(int argc, char** argv) { 31 | std::cout << "-------------------------- VERIFYING LLVM FEATURES --------------------------" << std::endl; 32 | 33 | ::testing::InitGoogleTest(&argc, argv); 34 | return RUN_ALL_TESTS(); 35 | } -------------------------------------------------------------------------------- /src/thirdparty/gtest/gtest-config.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | # platform programming shading language. 4 | # 5 | # Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | # 7 | # TSL is a free software written for educational purpose. Anyone can distribute 8 | # or modify it under the the terms of the GNU General Public License Version 3 as 9 | # published by the Free Software Foundation. However, there is NO warranty that 10 | # all components are functional in a perfect manner. Without even the implied 11 | # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License along with 15 | # this program. If not, see . 16 | # 17 | 18 | # just two macro for google test source code 19 | set( gtest_src ${TSL_SOURCE_DIR}/src/thirdparty/gtest/gtest-all.cc ) 20 | set( gtest_header ${TSL_SOURCE_DIR}/src/thirdparty/gtest/gtest.h ) 21 | set( gtest_files ${gtest_src} ${gtest_header} ) -------------------------------------------------------------------------------- /src/tsl_lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | # platform programming shading language. 4 | # 5 | # Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | # 7 | # TSL is a free software written for educational purpose. Anyone can distribute 8 | # or modify it under the the terms of the GNU General Public License Version 3 as 9 | # published by the Free Software Foundation. However, there is NO warranty that 10 | # all components are functional in a perfect manner. Without even the implied 11 | # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License along with 15 | # this program. If not, see . 16 | # 17 | 18 | # collect all files in this library 19 | file(GLOB_RECURSE project_headers *.h *.hpp) 20 | file(GLOB_RECURSE project_cpps *.cpp) 21 | file(GLOB_RECURSE project_cs *.c) 22 | file(GLOB_RECURSE project_ccs *.cc) 23 | 24 | # group all categories of files into one macro 25 | set(all_project_files ${project_headers} ${project_cpps} ${project_cs} ${project_ccs}) 26 | set(all_files ${all_project_files} ${tsl_include}) 27 | 28 | # give each file a proper folder based on its path 29 | source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${all_project_files}) 30 | 31 | # a separate folder for files outside this folder 32 | source_group( "tsl_include" FILES ${tsl_include} ) 33 | 34 | # specify the output directory 35 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${TSL_SOURCE_DIR}/bin") 36 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${TSL_SOURCE_DIR}/bin") 37 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${TSL_SOURCE_DIR}/bin") 38 | 39 | # default including folders, it is intentional to leave src folder unspecified to avoid using incorrect header files from other projects 40 | include_directories( "${TSL_SOURCE_DIR}/src/tsl_lib" "${TSL_SOURCE_DIR}/src/include" "${TSL_SOURCE_DIR}/src/thirdparty" ${LLVM_INCLUDE_DIR} ) 41 | 42 | # this is to avoid compilation issue in the file generated by flex 43 | add_definitions( -DYY_NO_UNISTD_H ) 44 | 45 | # make sure bison tells what is wrong 46 | add_definitions( -DYYERROR_VERBOSE ) 47 | 48 | # inform the source code it is building tsl 49 | add_definitions( -DBUILDING_TSL ) 50 | 51 | # no need to compile the code, but it is handy to loop them in the project for easy access 52 | # hopefully this line won't introduce any trouble on any platforms since they are treated as input files for compiler. 53 | set(flex_bison ${TSL_SOURCE_DIR}/src/tsl_lib/compiler/lex.l ${TSL_SOURCE_DIR}/src/tsl_lib/compiler/grammar.y) 54 | source_group( "flex and bison" FILES ${flex_bison} ) 55 | 56 | # Generated source code 57 | set(generated_src ${TSL_SOURCE_DIR}/generated_src/compiled_lex.cpp ${TSL_SOURCE_DIR}/generated_src/compiled_grammar.cpp ${TSL_SOURCE_DIR}/generated_src/compiled_grammar.hpp) 58 | 59 | # add executable, this will be converted to a library in the future 60 | if (TSL_PLATFORM_WIN) 61 | # that 'call' command is purely to avoid the VS 2019 warning, below is a link for further disscussion of the problem 62 | # https://gitlab.kitware.com/cmake/cmake/-/issues/19737 63 | add_library(TSL_Lib SHARED ${all_files} ${generated_src} ${flex_bison}) 64 | add_custom_command( OUTPUT ${generated_src} 65 | COMMAND call; make generate_src 66 | WORKING_DIRECTORY ${TSL_SOURCE_DIR}) 67 | else() 68 | add_library(TSL_Lib SHARED ${all_files} ${generated_src} ${flex_bison}) 69 | add_custom_command( OUTPUT ${generated_src} 70 | COMMAND make generate_src 71 | WORKING_DIRECTORY ${TSL_SOURCE_DIR}) 72 | endif() 73 | 74 | # Separate folder for the generated files 75 | source_group( "generated src" FILES ${generated_src} ) 76 | 77 | # Setup correct output name for different configurations 78 | set_target_properties( TSL_Lib PROPERTIES RELEASE_OUTPUT_NAME "tsl_r" ) 79 | set_target_properties( TSL_Lib PROPERTIES DEBUG_OUTPUT_NAME "tsl_d" ) 80 | set_target_properties( TSL_Lib PROPERTIES PUBLIC_HEADER "${tsl_include}" ) 81 | 82 | # make sure this macro is defined to correctly export interface 83 | add_definitions( -DBUILDING_TSL ) 84 | 85 | if (TSL_PLATFORM_MAC OR TSL_PLATFORM_LINUX) 86 | set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -pthread") 87 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") 88 | endif() 89 | 90 | if (TSL_PLATFORM_WIN) 91 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4244 /wd4146 /wd4267 /wd4141 /wd4624 /wd4005 /wd4996 /EHsc" ) 92 | 93 | # enable multi-thread compiling 94 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP${N}") 95 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP${N}") 96 | 97 | set_target_properties( TSL_Lib PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} /MD" ) 98 | endif() 99 | 100 | # specify the llvm library to link 101 | llvm_map_components_to_libnames(llvm_libs MCJIT nativecodegen) 102 | 103 | # link llvm libaries 104 | target_link_libraries(TSL_Lib ${llvm_libs}) 105 | 106 | # By default, the libraries (LLVM) used in TSL_Lib will also be exposed to whichever program links to TSL library. 107 | # This is totally not necessary. It is desirable to hide LLVM from programs using TSL so that it will be way easier 108 | # to compile renderers using TSL since there is no need to setup LLVM anymore. 109 | # This line is to prevent llvm libs to be linked in apps using this library. 110 | set_property(TARGET TSL_Lib PROPERTY INTERFACE_LINK_LIBRARIES ${TSL_Lib}) 111 | 112 | # This allows install command 113 | install(TARGETS TSL_Lib 114 | LIBRARY 115 | DESTINATION lib 116 | COMPONENT TSL_Lib 117 | PUBLIC_HEADER 118 | DESTINATION include 119 | COMPONENT TSL_Lib) 120 | 121 | # generate the tsl-config file 122 | set( TSL_LIB_NAME tsl_r ) 123 | configure_file(${TSL_SOURCE_DIR}/cmake/tsl-config.cmake.in "${TSL_SOURCE_DIR}/cmake/tsl-config.cmake" @ONLY) 124 | 125 | # this is to topy the tsl-config.cmake file during installation 126 | install(FILES "${TSL_SOURCE_DIR}/cmake/tsl-config.cmake" 127 | DESTINATION .) -------------------------------------------------------------------------------- /src/tsl_lib/compiler/ast_memory_janitor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include "ast_memory_janitor.h" 21 | #include "compiler/ast.h" 22 | 23 | TSL_NAMESPACE_BEGIN 24 | 25 | //! @brief This class will make sure all TSL allocated memory will be registered in it and eventually it will be destroyed. 26 | class TSL_Memory_Janior { 27 | public: 28 | //! @brief Keep track of this node 29 | void track_ast_node(const AstNode* node) { 30 | auto ptr = std::shared_ptr(node); 31 | m_ast_nodes[node] = ptr; 32 | } 33 | 34 | //! @brief Find ast node shared_ptr 35 | std::shared_ptr find_shared_ptr(const AstNode* node) { 36 | return m_ast_nodes.count(node) ? m_ast_nodes[node] : nullptr; 37 | } 38 | 39 | private: 40 | // This data structure keeps track of all ast nodes' life time. 41 | // However, since some of the Ast Node is also owned by other data structures, there is a chance that even if this janitor 42 | // is deallocated and the Ast Nodes are still alive. But since every other part of the problem uses a shared_ptr, it should 43 | // be safe to say there won't be any memory leak caused by AstNode. 44 | std::unordered_map> m_ast_nodes; 45 | }; 46 | 47 | // This container is purely for the purpose of keeping track of the life time of AstNodes. 48 | // As a matter of fact, it is more for incorrect shaders where the compiler fails to compile during parsing because some of the 49 | // ast node will get dangled leaving memory leak. For correct shaders, all nodes will be owned by something in the shader template, 50 | // which eventually will be destroyed at some point. 51 | // In order to make it thread safe, thread local storage is needed here to prevent data racing among threads. 52 | thread_local static std::vector g_tsl_memory_janitor_stack; 53 | 54 | Ast_Memory_Guard::Ast_Memory_Guard() { 55 | g_tsl_memory_janitor_stack.push_back(TSL_Memory_Janior()); 56 | } 57 | 58 | Ast_Memory_Guard::~Ast_Memory_Guard() { 59 | g_tsl_memory_janitor_stack.pop_back(); 60 | } 61 | 62 | void ast_ptr_tracking(const AstNode* node) { 63 | assert(nullptr == ast_ptr_from_raw(node)); 64 | 65 | if (g_tsl_memory_janitor_stack.size()) { 66 | auto& janitor = g_tsl_memory_janitor_stack.back(); 67 | janitor.track_ast_node(node); 68 | } 69 | } 70 | 71 | template 72 | std::shared_ptr ast_ptr_from_raw(const AstNode* ptr) { 73 | for (auto& janitor : g_tsl_memory_janitor_stack) { 74 | std::shared_ptr shared_ptr = janitor.find_shared_ptr(ptr); 75 | if (shared_ptr) 76 | return std::dynamic_pointer_cast(shared_ptr); 77 | } 78 | return nullptr; 79 | } 80 | 81 | // Instantiation with some concrete class that will be used in the compiler. 82 | #define INSTANTIATION_AST_PTR_FROM_RAW(T) template std::shared_ptr ast_ptr_from_raw(const AstNode* ptr); 83 | 84 | INSTANTIATION_AST_PTR_FROM_RAW(AstNode_ArrayInitList) 85 | INSTANTIATION_AST_PTR_FROM_RAW(AstNode_Literal) 86 | INSTANTIATION_AST_PTR_FROM_RAW(AstNode_Expression) 87 | INSTANTIATION_AST_PTR_FROM_RAW(AstNode_Lvalue) 88 | INSTANTIATION_AST_PTR_FROM_RAW(AstNode_Statement) 89 | INSTANTIATION_AST_PTR_FROM_RAW(AstNode_VariableDecl) 90 | INSTANTIATION_AST_PTR_FROM_RAW(AstNode_FunctionBody) 91 | INSTANTIATION_AST_PTR_FROM_RAW(AstNode_Statement_VariableDecl) 92 | INSTANTIATION_AST_PTR_FROM_RAW(AstNode_FunctionPrototype) 93 | INSTANTIATION_AST_PTR_FROM_RAW(AstNode_StructDeclaration) 94 | INSTANTIATION_AST_PTR_FROM_RAW(AstNode_ArgumentList) 95 | INSTANTIATION_AST_PTR_FROM_RAW(AstNode_Statement_StructMemberDecls) 96 | INSTANTIATION_AST_PTR_FROM_RAW(AstNode_SingleVariableDecl) 97 | INSTANTIATION_AST_PTR_FROM_RAW(AstNode_MultiVariableDecl) 98 | 99 | TSL_NAMESPACE_END -------------------------------------------------------------------------------- /src/tsl_lib/compiler/ast_memory_janitor.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | // In an ideal world, I should have switched to smart pointer solution in Bison code so that it is automatically guaranteed to be memory leak free. 19 | // However, TSL uses C version bison instead of C++. This is because the lack of pre-compiled bison with a version higher than 2.7. 20 | // It is also possible to compile the bison source code on Cygwin to run it on Windows, but it will make CI/CD a lot more complex than what is originally 21 | // necessary. 22 | // To make sure there is no memory leak, this file provides interface to make sure no AST node can survive if the shader unit is deallocated to secure 23 | // memory leak problem. It is not the ideal solution, but I don't have time to investigate a better solution unless there is any big problem of this solution. 24 | 25 | #pragma once 26 | 27 | #include "tsl_version.h" 28 | 29 | TSL_NAMESPACE_BEGIN 30 | 31 | // A helper class to make sure there is a temporary janitor during the life time of this guard. 32 | class Ast_Memory_Guard { 33 | public: 34 | Ast_Memory_Guard(); 35 | ~Ast_Memory_Guard(); 36 | }; 37 | 38 | // Keep track of this AstNode. This should be called in the constructor of AstNode to secure memory leak problem. 39 | // All ast nodes have to be allocated on heap because the smart pointers will try deleting them eventually. 40 | // Having an ast node on stack will easily introduce a crash. Since all ast nodes are allocated by Bison script, 41 | // they are allocated on heap instead of stack. 42 | void ast_ptr_tracking(const class AstNode*); 43 | 44 | // It is very important to go through this function whenver TSL manages a raw pointer with smart pointer. 45 | // Failing to do it will result in crash. All other parts of the compiler has to convert their raw pointer input 46 | // through this interface, which will locate the shared_ptr registered during construction. 47 | template 48 | std::shared_ptr ast_ptr_from_raw(const class AstNode* ptr); 49 | 50 | TSL_NAMESPACE_END -------------------------------------------------------------------------------- /src/tsl_lib/compiler/compile_context.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include "compile_context.h" 19 | 20 | TSL_NAMESPACE_BEGIN 21 | 22 | void TSL_Compile_Context::reset() { 23 | m_var_symbols.clear(); 24 | m_var_symbols.push_back({}); // this is for global variables 25 | } 26 | 27 | llvm::Value* TSL_Compile_Context::get_var_symbol(const std::string& name, bool only_top_layer) { 28 | if (only_top_layer) { 29 | auto top = m_var_symbols.back(); 30 | auto it = top.find(name); 31 | return it == top.end() ? nullptr : it->second.first; 32 | } 33 | else { 34 | auto it = m_var_symbols.rbegin(); 35 | while (it != m_var_symbols.rend()) { 36 | auto var = it->find(name); 37 | if (var != it->end()) 38 | return var->second.first; 39 | ++it; 40 | } 41 | } 42 | 43 | emit_error("Undefined variable '%s'.", name.c_str()); 44 | 45 | return nullptr; 46 | } 47 | 48 | DataType TSL_Compile_Context::get_var_type(const std::string& name, bool only_top_layer) { 49 | if (only_top_layer) { 50 | auto top = m_var_symbols.back(); 51 | auto it = top.find(name); 52 | if (it != top.end()) 53 | return it->second.second; 54 | } 55 | else { 56 | auto it = m_var_symbols.rbegin(); 57 | while (it != m_var_symbols.rend()) { 58 | auto var = it->find(name); 59 | if (var != it->end()) 60 | return var->second.second; 61 | ++it; 62 | } 63 | } 64 | 65 | emit_error("Undefined variable '%s'.", name.c_str()); 66 | 67 | return DataType(); 68 | } 69 | 70 | llvm::Value* TSL_Compile_Context::push_var_symbol(const std::string& name, llvm::Value* value, DataType type) { 71 | auto top_layer = m_var_symbols.back(); 72 | 73 | if (top_layer.count(name)) { 74 | emit_error("Redefined variable '%s'.", name.c_str()); 75 | return nullptr; 76 | } 77 | 78 | m_var_symbols.back()[name] = std::make_pair(value, type); 79 | 80 | return nullptr; 81 | } 82 | 83 | void TSL_Compile_Context::push_var_symbol_layer() { 84 | m_var_symbols.push_back({}); 85 | } 86 | 87 | void TSL_Compile_Context::pop_var_symbol_layer() { 88 | m_var_symbols.pop_back(); 89 | } 90 | 91 | TSL_NAMESPACE_END 92 | -------------------------------------------------------------------------------- /src/tsl_lib/compiler/compile_context.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "tsl_version.h" 30 | #include "tsl_system.h" 31 | #include "types.h" 32 | #include "system/impl.h" 33 | 34 | TSL_NAMESPACE_BEGIN 35 | 36 | class AstNode_FunctionPrototype; 37 | 38 | struct StructMemberTypeMetaData { 39 | llvm::Type* m_llvm_type = nullptr; 40 | std::unordered_map> m_member_types; 41 | }; 42 | 43 | using Var_MetaData = std::unordered_map>; 44 | using Struct_Symbol_Table = std::unordered_map; 45 | using Var_Symbol_Table_Stack = std::vector; 46 | using Func_Symbol_Table = std::unordered_map>; 47 | using Closure_Symbol_Table = std::unordered_map; 48 | using Block_Stack = std::stack>; 49 | 50 | //! @brief Compiling context of TSL. 51 | /** 52 | * This data structure keeps track of all necessary information during compilation. Put it in other words, 53 | * it is more of an intermediate data structure to keep track of things during shader compilation. 54 | * Unless the memory is allocated inside this data structure, the compile context takes NO responsibility 55 | * of maintaining the lifetime of the data it points to. 56 | */ 57 | struct TSL_Compile_Context { 58 | // The llvm context pointer, it is just not an owning pointer. 59 | llvm::LLVMContext* context = nullptr; 60 | // The llvm module, again this is not an owning pointer. 61 | llvm::Module* module = nullptr; 62 | // llvm builder pointer 63 | llvm::IRBuilder<>* builder = nullptr; 64 | // tsl global data type 65 | llvm::Type* tsl_global_ty = nullptr; 66 | // tsl global value passed in 67 | llvm::Value* tsl_global_value = nullptr; 68 | // a map keeps track of all global variables 69 | GlobalVarList* tsl_global_mapping = nullptr; 70 | // a map keeps track of all shader resources 71 | ShaderResourceTable* m_shader_resource_table = nullptr; 72 | 73 | // closured touched in the shader 74 | Closure_Symbol_Table m_closures_maps; 75 | 76 | // a table keeps track of structure types 77 | Struct_Symbol_Table m_structure_type_maps; 78 | 79 | // a table keeps track of function symbols 80 | Func_Symbol_Table m_func_symbols; 81 | 82 | // a table keeps track of visited blocks 83 | Block_Stack m_blocks; 84 | 85 | // get a variable if possible 86 | llvm::Value* get_var_symbol(const std::string& name, bool only_top_layer = false); 87 | 88 | // get a variable type if possible 89 | DataType get_var_type(const std::string& name, bool only_top_layer = false); 90 | 91 | // push a variable into the variable symbol table 92 | llvm::Value* push_var_symbol(const std::string& name, llvm::Value* value, DataType type); 93 | 94 | // push/pop a symbol layer 95 | void push_var_symbol_layer(); 96 | void pop_var_symbol_layer(); 97 | 98 | // default constructor simply resets the context 99 | TSL_Compile_Context() { 100 | reset(); 101 | } 102 | 103 | // reset the compile context 104 | void reset(); 105 | 106 | private: 107 | // variable symbol table 108 | Var_Symbol_Table_Stack m_var_symbols; 109 | }; 110 | 111 | TSL_NAMESPACE_END -------------------------------------------------------------------------------- /src/tsl_lib/compiler/compiler.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "tsl_system.h" 31 | #include "types.h" 32 | #include "ast.h" 33 | 34 | TSL_NAMESPACE_BEGIN 35 | 36 | class ShaderUnitTemplate; 37 | class ShaderGroupTemplate; 38 | class ShaderInstance; 39 | class GlobalModule; 40 | struct TSL_Compile_Context; 41 | struct ShaderUnitTemplateCopy; 42 | 43 | //! @brief Internal compiler implementation. 44 | /** 45 | * The sole purpose of another compiler implementation thing is to keep TslCompiler as simple as possible. 46 | * This class hides all details from the TslCompiler, which will eventually be exported to TSL users. 47 | */ 48 | class TslCompiler { 49 | public: 50 | //! @brief Default constructor 51 | TslCompiler(GlobalModule& global_module); 52 | 53 | //! @brief Nuke the state of the compiler so that it can be used for another pass of compiling. 54 | void reset(const std::string& name = ""); 55 | 56 | //! @brief Compile a shader. 57 | //! 58 | //! Ideally, this should be thread-safe. Flex and Bison support it, as long as I can make sure LLVM supports too, 59 | //! it should be thread-safe. 60 | //! 61 | //! @param source_code The source code of the shader module. 62 | //! @param su The shader unit owning this piece of source code. 63 | bool compile(const char* source_code, ShaderUnitTemplate* su); 64 | 65 | //! @brief Resolve a shader group. 66 | //! 67 | //! @param sg The shader group to be resolved. 68 | //! @return Whether the shader is resolved succesfully. 69 | TSL_Resolving_Status resolve(ShaderGroupTemplate* su); 70 | 71 | //! @brief Resolve a shader instance. 72 | //! 73 | //! @param si The shader instance to be resolved. 74 | //! @return Whether the shader is resolved successfully. 75 | TSL_Resolving_Status resolve(ShaderInstance* si); 76 | 77 | //! @brief Get scanner of the compiler 78 | //! 79 | //! @return Get the internal scanner, which will be used by bison generated code. 80 | void* get_scanner(); 81 | 82 | //! @brief Update a function definition. 83 | //! 84 | //! @param node Push a function node in the compiler. 85 | void push_function(AstNode_FunctionPrototype* node, bool is_shader = false); 86 | 87 | //! @brief Push structure declaration. 88 | //! 89 | //! @param node Push a structure declaration. 90 | void push_structure_declaration(AstNode_StructDeclaration* structure); 91 | 92 | //! @brief Push global parameter 93 | //! 94 | //! @param statement This statement should be purely variable declaration. 95 | void push_global_parameter(const AstNode_Statement* statement); 96 | 97 | //! @brief Parameter type cache. 98 | //! 99 | //! @param type Type of the parameter to be parsed. 100 | void cache_next_data_type(const DataType& type) { 101 | m_type_cache = type; 102 | } 103 | 104 | //! @brief Acquire the cached data type. 105 | DataType data_type_cache() const { 106 | return m_type_cache; 107 | } 108 | 109 | //! @brief Ask the compiler to pre-declare make closure function 110 | void closure_touched(const std::string& name) { 111 | m_closures_in_shader.insert(name); 112 | } 113 | 114 | //! @brief Name replacement of shader unit root function. 115 | const std::string& get_shader_root_function_name() const { 116 | return m_shader_root_function_name; 117 | } 118 | 119 | private: 120 | // flex scanner 121 | void* m_scanner = nullptr; 122 | 123 | // root ast node of the parsed program 124 | std::shared_ptr m_ast_root; 125 | 126 | // the shader unit/group template name being compiled. 127 | std::string m_shader_root_function_name; 128 | 129 | // global functions defined in this module 130 | std::vector> m_functions; 131 | // global structure declaration in this module, maybe I should merge it with the above one 132 | std::vector> m_structures; 133 | // global variables defined in this module 134 | std::vector> m_global_var; 135 | 136 | // data type cache 137 | DataType m_type_cache = { DataTypeEnum::VOID , nullptr }; 138 | 139 | // local llvm context 140 | llvm::LLVMContext m_llvm_context; 141 | 142 | // closure register 143 | GlobalModule& m_global_module; 144 | 145 | // closured touched in the shader 146 | std::unordered_set m_closures_in_shader; 147 | 148 | // a string holder, this is purely to workaround bison limitation because DateType can't be non-POD. 149 | // an extra perk of doing this is to make DataType much cheaper. 150 | std::unordered_set m_string_container; 151 | 152 | // this data structure keeps track of used values to bridge shader units 153 | using VarMapping = std::unordered_map>; 154 | 155 | //! @brief Generate shader group source code 156 | TSL_Resolving_Status generate_shader_source(TSL_Compile_Context& context, ShaderGroupTemplate* sg, const ShaderUnitTemplateCopy& su, std::unordered_set& visited, 157 | std::unordered_set& being_visited, VarMapping& var_mapping, 158 | const std::unordered_map& function_mapping, const std::vector& args); 159 | 160 | //! @brief A helper wrapper to make sure all contexts are gone after shader compilation 161 | class ContextWrapper { 162 | public: 163 | ContextWrapper(TslCompiler& impl, const std::string& name) :impl(impl) { impl.reset(name); } 164 | ~ContextWrapper() { impl.reset(); } 165 | private: 166 | TslCompiler& impl; 167 | }; 168 | }; 169 | 170 | TSL_NAMESPACE_END -------------------------------------------------------------------------------- /src/tsl_lib/compiler/global_module.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "tsl_version.h" 27 | #include "ast.h" 28 | #include "tsl_args.h" 29 | 30 | TSL_NAMESPACE_BEGIN 31 | 32 | struct TSL_Compile_Context; 33 | 34 | struct ClosureItem { 35 | const ClosureID m_closure_id = INVALID_CLOSURE_ID; 36 | const ClosureArgList& m_var_list; 37 | const int m_structure_size; 38 | 39 | ClosureItem(ClosureID id, ClosureArgList& var_list, int structure_size) 40 | : m_closure_id(id), m_var_list(var_list), m_structure_size(structure_size) {} 41 | }; 42 | 43 | //! @brief Global module of TSL. 44 | /** 45 | * Unlike other modules owned by shader unit template, global module only have one instance owned by the system. 46 | * It is mainly for defining functions to allocate registered closure data structures. 47 | * Every single module will have this module attached so that it will know some of the very fundermental data 48 | * available in TSL 49 | */ 50 | class GlobalModule { 51 | public: 52 | // initialize the register 53 | bool init(); 54 | 55 | // register a closure type 56 | ClosureID register_closure_type(const std::string& name, ClosureArgList& mapping, int structure_size); 57 | 58 | // get global closure maker module 59 | llvm::Module* get_closure_module(); 60 | 61 | // declare some global data structure type 62 | void declare_closure_tree_types(llvm::LLVMContext& context, Struct_Symbol_Table* mapping = nullptr ); 63 | 64 | // get declaration 65 | llvm::Function* declare_closure_function(const std::string& name, TSL_Compile_Context& context); 66 | 67 | // declare global function 68 | void declare_global_module(TSL_Compile_Context& context); 69 | 70 | private: 71 | /**< a container holding all closures ids. */ 72 | std::unordered_map m_closures; 73 | /**< current allocated closure id. */ 74 | int m_current_closure_id = INVALID_CLOSURE_ID + 1; 75 | /**< a mutex to make sure access to closure container is thread-safe. */ 76 | std::mutex m_closure_mutex; 77 | 78 | llvm::LLVMContext m_llvm_context; 79 | std::unique_ptr m_module; 80 | std::unordered_map m_typing_maps; 81 | 82 | /**< The type of base closure node. */ 83 | const llvm::Type* m_closure_base_type = nullptr; 84 | 85 | Tsl_Namespace::TSL_Compile_Context m_llvm_compiling_context; 86 | }; 87 | 88 | TSL_NAMESPACE_END -------------------------------------------------------------------------------- /src/tsl_lib/compiler/internal_define.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "tsl_version.h" 21 | 22 | TSL_NAMESPACE_BEGIN 23 | 24 | // x86/x64 detection 25 | #if defined(__x86_64__) || defined(_M_X64) 26 | #define TSL_X64_TARGET 27 | #elif defined(__i386) || defined(_M_IX86) 28 | #define TSL_X64_TARGET 29 | #endif 30 | 31 | TSL_NAMESPACE_END -------------------------------------------------------------------------------- /src/tsl_lib/compiler/lex.l: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | %{ 19 | /* 20 | -------------------------------------------------------------------- 21 | WARNING: 22 | This file is automatically generated, do not modify. 23 | -------------------------------------------------------------------- 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "tsl_version.h" 31 | #include "tsl_define.h" 32 | #include "compiler/compiler.h" 33 | #include "compiler/str_helper.h" 34 | #include "compiled_grammar.hpp" 35 | 36 | #if __cplusplus > 199711L 37 | #define register // Deprecated in C++11. 38 | #endif // #if __cplusplus > 199711L 39 | 40 | #define YY_USER_ACTION \ 41 | {\ 42 | yylloc->first_line = yylloc->last_line;\ 43 | yylloc->first_column = yylloc->last_column;\ 44 | int curr_line = yylloc->first_line;\ 45 | int curr_col = yylloc->first_column;\ 46 | for(char* s = yytext; *s != '\0'; s++){\ 47 | if(*s == '\n'){\ 48 | curr_line++;\ 49 | curr_col = 1;\ 50 | }else{\ 51 | curr_col++;\ 52 | }\ 53 | }\ 54 | yylloc->last_line = curr_line;\ 55 | yylloc->last_column = curr_col - 1;\ 56 | } 57 | %} 58 | 59 | %option outfile="generated_src/compiled_lex.cpp" 60 | %option noyywrap 61 | %option never-interactive 62 | %option yylineno 63 | %option reentrant 64 | %option bison-bridge 65 | %option bison-locations 66 | 67 | alpha [a-zA-Z] 68 | digit [0-9] 69 | integer_numbers {digit}+ 70 | hex_numbers 0[xX][0-9a-fA-F]+ 71 | exp [eE][-+]?{digit}+ 72 | flt1 {digit}+\.{digit}*{exp}? 73 | flt2 {digit}*\.{digit}+{exp}? 74 | flt3 {digit}+{exp} 75 | float_numbers ({flt1}|{flt2}|{flt3})f? 76 | double_numbers ({flt1}|{flt2}|{flt3})d 77 | one_line_comment (\/\/)(.*\n) 78 | multi_line_comment \/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\/ 79 | identifier ({alpha}|[_])({alpha}|{digit}|[_])* 80 | whitespace [ \t\r\n\f]+ 81 | 82 | %% 83 | "struct" { return STRUCT; } 84 | "make_closure" { return MAKE_CLOSURE; } 85 | "global_value" { return GLOBAL_VALUE; } 86 | "shader_resource" { return SHADER_RESOURCE_HANDLE; } 87 | "texture2d" { return TEXTURE2D_HANDLE; } 88 | "texture2d_sample" { return TEXTURE2D_SAMPLE; } 89 | "texture2d_sample_alpha" { return TEXTURE2D_SAMPLE_ALPHA; } 90 | "closure" { return CLOSURE; } 91 | "true" { return TRUE; } 92 | "false" { return FALSE; } 93 | "do" { return DO; } 94 | "while" { return WHILE; } 95 | "for" { return FOR; } 96 | "break" { return BREAK; } 97 | "continue" { return CONTINUE; } 98 | "if" { return IF; } 99 | "else" { return ELSE; } 100 | "++" { return INC_OP; } 101 | "--" { return DEC_OP; } 102 | "in" { return IN; } 103 | "const" { return CONST; } 104 | "out" { return OUT; } 105 | ":" { return COLON; } 106 | "?" { return QUESTION_MARK; } 107 | "return" { return RETURN; } 108 | "<<<" { return METADATA_START; } 109 | ">>>" { return METADATA_END; } 110 | "int" { return TYPE_INT; } 111 | "float" { return TYPE_FLOAT; } 112 | "double" { return TYPE_DOUBLE; } 113 | "void" { return TYPE_VOID; } 114 | "color" { return TYPE_COLOR; } 115 | "vector" { return TYPE_VECTOR; } 116 | "bool" { return TYPE_BOOL; } 117 | "." { return DOT; } 118 | "shader" { return SHADER_FUNC_ID; } 119 | "(" { return L_RBRACKET; } 120 | ")" { return R_RBRACKET; } 121 | "{" { return L_CBRACKET; } 122 | "}" { return R_CBRACKET; } 123 | "[" { return L_SBRACKET; } 124 | "]" { return R_SBRACKET; } 125 | "+" { return OP_ADD; } 126 | "-" { return OP_MINUS; } 127 | "*" { return OP_MULT; } 128 | "/" { return OP_DIV; } 129 | "%" { return OP_MOD; } 130 | "+=" { return OP_ADD_ASSIGN; } 131 | "-=" { return OP_MINUS_ASSIGN; } 132 | "*=" { return OP_MULT_ASSIGN; } 133 | "/=" { return OP_DIV_ASSIGN; } 134 | "%=" { return OP_MOD_ASSIGN; } 135 | ";" { return EOL; } 136 | "," { return COMMA; } 137 | "=" { return OP_ASSIGN; } 138 | "&" { return OP_AND; } 139 | "|" { return OP_OR; } 140 | "^" { return OP_XOR; } 141 | "&&" { return OP_LOGIC_AND; } 142 | "||" { return OP_LOGIC_OR; } 143 | "==" { return OP_EQ; } 144 | "!=" { return OP_NE; } 145 | ">=" { return OP_GE; } 146 | ">" { return OP_G; } 147 | "<=" { return OP_LE; } 148 | "<" { return OP_L; } 149 | "<<" { return OP_SHL; } 150 | ">>" { return OP_SHR; } 151 | "&=" { return OP_AND_ASSIGN; } 152 | "|=" { return OP_OR_ASSIGN; } 153 | "^=" { return OP_XOR_ASSIGN; } 154 | "<<=" { return OP_SHL_ASSIGN; } 155 | ">>=" { return OP_SHR_ASSIGN; } 156 | "~" { return OP_COMP; } 157 | "!" { return OP_NOT; } 158 | 159 | {identifier} { 160 | yylval->s = Tsl_Namespace::make_str_unique(yytext); 161 | return ID; 162 | } 163 | 164 | {float_numbers} { 165 | yylval->f = atof(yytext); 166 | return FLT_NUM; 167 | } 168 | 169 | {double_numbers} { 170 | yylval->d = std::stod(yytext); 171 | return DBL_NUM; 172 | } 173 | 174 | {integer_numbers} { 175 | // no over flow control for now 176 | yylval->i = std::atoi(yytext); 177 | return INT_NUM; 178 | } 179 | 180 | {hex_numbers} { 181 | // no over flow control for now 182 | yylval->i = std::stoi("0xeffffff", 0 , 16); 183 | return INT_NUM; 184 | } 185 | 186 | {one_line_comment} { /* eat up one-line comments */ } 187 | {multi_line_comment} { /* eat up multi-line comments */ } 188 | {whitespace} { /* ignore whitespace */ } 189 | . { /* supress output for the unknown */ } 190 | %% 191 | -------------------------------------------------------------------------------- /src/tsl_lib/compiler/llvm_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | // This file has a bunch of helper utility functions so that the rest of the program doesn't 19 | // need to care about the details hiden here. 20 | 21 | #pragma once 22 | 23 | #include 24 | #include 25 | #include 26 | #include "compile_context.h" 27 | #include "tsl_args.h" 28 | 29 | inline llvm::LLVMContext& get_llvm_context(Tsl_Namespace::TSL_Compile_Context& context) { 30 | return *context.context; 31 | } 32 | 33 | inline llvm::IRBuilder<>& get_llvm_builder(Tsl_Namespace::TSL_Compile_Context& context) { 34 | return *context.builder; 35 | } 36 | 37 | inline llvm::Module& get_llvm_module(Tsl_Namespace::TSL_Compile_Context& context) { 38 | return *context.module; 39 | } 40 | 41 | inline llvm::IntegerType* get_int_1_ty(Tsl_Namespace::TSL_Compile_Context& context) { 42 | return llvm::Type::getInt1Ty(get_llvm_context(context)); 43 | } 44 | 45 | inline llvm::IntegerType* get_int_32_ty(Tsl_Namespace::TSL_Compile_Context& context) { 46 | return llvm::Type::getInt32Ty(get_llvm_context(context)); 47 | } 48 | 49 | inline llvm::PointerType* get_int_32_ptr_ty(Tsl_Namespace::TSL_Compile_Context& context) { 50 | return llvm::Type::getInt32PtrTy(get_llvm_context(context)); 51 | } 52 | 53 | inline llvm::Type* get_float_ty(Tsl_Namespace::TSL_Compile_Context& context) { 54 | return llvm::Type::getFloatTy(get_llvm_context(context)); 55 | } 56 | 57 | inline llvm::Type* get_float_ptr_ty(Tsl_Namespace::TSL_Compile_Context& context) { 58 | return llvm::Type::getFloatPtrTy(get_llvm_context(context)); 59 | } 60 | 61 | inline llvm::Type* get_double_ty(Tsl_Namespace::TSL_Compile_Context& context) { 62 | return llvm::Type::getDoubleTy(get_llvm_context(context)); 63 | } 64 | 65 | inline llvm::Type* get_void_ty(Tsl_Namespace::TSL_Compile_Context& context) { 66 | return llvm::Type::getVoidTy(get_llvm_context(context)); 67 | } 68 | 69 | // closure type is just a regular int* 70 | inline llvm::Type* get_closure_ty(Tsl_Namespace::TSL_Compile_Context& context) { 71 | return get_int_32_ptr_ty(context); 72 | } 73 | 74 | inline llvm::Type* get_type_from_context(const Tsl_Namespace::DataType type, Tsl_Namespace::TSL_Compile_Context& context){ 75 | switch (type.m_type) { 76 | case Tsl_Namespace::DataTypeEnum::INT: 77 | return get_int_32_ty(context); 78 | case Tsl_Namespace::DataTypeEnum::FLOAT: 79 | return get_float_ty(context); 80 | case Tsl_Namespace::DataTypeEnum::DOUBLE: 81 | return get_double_ty(context); 82 | case Tsl_Namespace::DataTypeEnum::VOID: 83 | return get_void_ty(context); 84 | case Tsl_Namespace::DataTypeEnum::BOOL: 85 | return get_int_1_ty(context); 86 | case Tsl_Namespace::DataTypeEnum::CLOSURE: 87 | return get_closure_ty(context); 88 | case Tsl_Namespace::DataTypeEnum::STRUCT: 89 | return context.m_structure_type_maps[type.m_structure_name].m_llvm_type; 90 | default: 91 | break; 92 | } 93 | return nullptr; 94 | } 95 | 96 | inline llvm::Type* get_type_from_context(const std::string& type, Tsl_Namespace::TSL_Compile_Context& context) { 97 | if (type == "Tsl_int") 98 | return get_int_32_ty(context); 99 | else if (type == "Tsl_float") 100 | return get_float_ty(context); 101 | else if (type == "Tsl_float3") 102 | return context.m_structure_type_maps["float3"].m_llvm_type; 103 | else if( type == "Tsl_double" ) 104 | return get_double_ty(context); 105 | else if( type == "Tsl_matrix" ) // not well supported for now 106 | return get_float_ptr_ty(context); 107 | else if( type == "Tsl_closure" ) 108 | return get_int_32_ptr_ty(context); 109 | else if( type == "Tsl_resource" ) 110 | return get_int_32_ptr_ty(context); 111 | else if (type == "void") 112 | return get_void_ty(context); 113 | else if( type == "Tsl_bool" ) 114 | return get_int_1_ty(context); 115 | return nullptr; 116 | } 117 | 118 | inline llvm::Value* get_llvm_constant_fp(const float v, Tsl_Namespace::TSL_Compile_Context& context){ 119 | auto& llvm_context = get_llvm_context(context); 120 | return llvm::ConstantFP::get(llvm_context, llvm::APFloat(v)); 121 | } 122 | 123 | inline llvm::Value* get_llvm_constant_fp(const double v, Tsl_Namespace::TSL_Compile_Context& context) { 124 | auto& llvm_context = get_llvm_context(context); 125 | return llvm::ConstantFP::get(llvm_context, llvm::APFloat(v)); 126 | } 127 | 128 | inline llvm::Value* get_llvm_constant_int(const int v, const int bw, Tsl_Namespace::TSL_Compile_Context& context) { 129 | auto& llvm_context = get_llvm_context(context); 130 | return llvm::ConstantInt::get(llvm_context, llvm::APInt(bw, v)); 131 | } 132 | 133 | inline llvm::Value* get_llvm_constant_float3(const Tsl_Namespace::float3& vec, Tsl_Namespace::TSL_Compile_Context& context) { 134 | auto& builder = get_llvm_builder(context); 135 | 136 | auto float3_type = context.m_structure_type_maps["float3"].m_llvm_type; 137 | auto var = builder.CreateAlloca(float3_type, nullptr); 138 | 139 | const auto x_ptr = builder.CreateConstGEP2_32(nullptr, var, 0, 0); 140 | auto x = get_llvm_constant_fp(vec.x, context); 141 | builder.CreateStore(x, x_ptr); 142 | 143 | const auto y_ptr = builder.CreateConstGEP2_32(nullptr, var, 0, 1); 144 | auto y = get_llvm_constant_fp(vec.y, context); 145 | builder.CreateStore(y, y_ptr); 146 | 147 | const auto z_ptr = builder.CreateConstGEP2_32(nullptr, var, 0, 2); 148 | auto z = get_llvm_constant_fp(vec.z, context); 149 | builder.CreateStore(z, z_ptr); 150 | 151 | return builder.CreateLoad(var); 152 | } 153 | 154 | inline llvm::Value* convert_to_bool(llvm::Value* value, Tsl_Namespace::TSL_Compile_Context& context) { 155 | auto& builder = get_llvm_builder(context); 156 | if (value->getType() == get_float_ty(context)) 157 | value = builder.CreateFCmpONE(value, get_llvm_constant_fp(0.0f, context)); 158 | else if (!value->getType()->isIntegerTy(1)) 159 | value = builder.CreateICmpNE(value, get_llvm_constant_int(0, value->getType()->getIntegerBitWidth(), context)); 160 | return value; 161 | } 162 | 163 | inline llvm::Value* get_llvm_add(llvm::Value* left, llvm::Value* right, Tsl_Namespace::TSL_Compile_Context& context) { 164 | if (left->getType() == get_float_ty(context) && right->getType() == get_float_ty(context)) 165 | return context.builder->CreateFAdd(left, right); 166 | if (left->getType() == get_int_32_ty(context) && right->getType() == get_int_32_ty(context)) 167 | return context.builder->CreateAdd(left, right); 168 | 169 | return nullptr; 170 | } 171 | 172 | inline llvm::Value* get_llvm_sub(llvm::Value* left, llvm::Value* right, Tsl_Namespace::TSL_Compile_Context& context) { 173 | if (left->getType() == get_float_ty(context) && right->getType() == get_float_ty(context)) 174 | return context.builder->CreateFSub(left, right); 175 | if (left->getType() == get_int_32_ty(context) && right->getType() == get_int_32_ty(context)) 176 | return context.builder->CreateSub(left, right); 177 | 178 | return nullptr; 179 | } 180 | 181 | inline llvm::Value* get_llvm_mul(llvm::Value* left, llvm::Value* right, Tsl_Namespace::TSL_Compile_Context& context) { 182 | if (left->getType() == get_float_ty(context) && right->getType() == get_float_ty(context)) 183 | return context.builder->CreateFMul(left, right); 184 | if (left->getType() == get_int_32_ty(context) && right->getType() == get_int_32_ty(context)) 185 | return context.builder->CreateMul(left, right); 186 | 187 | return nullptr; 188 | } 189 | 190 | inline llvm::Value* get_llvm_div(llvm::Value* left, llvm::Value* right, Tsl_Namespace::TSL_Compile_Context& context) { 191 | if (left->getType() == get_float_ty(context) && right->getType() == get_float_ty(context)) 192 | return context.builder->CreateFDiv(left, right); 193 | if (left->getType() == get_int_32_ty(context) && right->getType() == get_int_32_ty(context)) 194 | return context.builder->CreateSDiv(left, right); 195 | 196 | return nullptr; 197 | } 198 | 199 | inline llvm::Value* get_llvm_mod(llvm::Value* left, llvm::Value* right, Tsl_Namespace::TSL_Compile_Context& context) { 200 | if (left->getType() == get_float_ty(context) && right->getType() == get_float_ty(context)) 201 | return context.builder->CreateFRem(left, right); 202 | if (left->getType() == get_int_32_ty(context) && right->getType() == get_int_32_ty(context)) 203 | return context.builder->CreateSRem(left, right); 204 | 205 | return nullptr; 206 | } 207 | 208 | inline bool is_llvm_integer(llvm::Value* value) { 209 | return value->getType()->isIntegerTy(); 210 | } 211 | -------------------------------------------------------------------------------- /src/tsl_lib/compiler/str_helper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "internal_define.h" 24 | #include "str_helper.h" 25 | 26 | #if defined(TSL_X64_TARGET) 27 | #include 28 | #endif 29 | 30 | TSL_NAMESPACE_BEGIN 31 | 32 | // since this is only a very small amount of memory needed, there is no cleanning interface for simplicity. 33 | std::unordered_set g_string_container; 34 | 35 | // a lock free version of spin 'lock' 36 | class spinlock_mutex { 37 | public: 38 | void lock() { 39 | // std::memory_order_acquire is neccessary here to prevent the out-of-order execution optimization. 40 | // It makes sure all memory load will happen after the lock is acquired. 41 | while (locked.test_and_set(std::memory_order_acquire)) { 42 | // In a very contended multi-threading environment, full busy loop may not be the most efficient thing to do since 43 | // they consume CPU cycles all the time. This instruction could allow delaying CPU instructions for a few cycles in 44 | // some cases to allow other threads to take ownership of hardware resources. 45 | // https://software.intel.com/en-us/comment/1134767 46 | #if defined(TSL_X64_TARGET) 47 | _mm_pause(); 48 | #endif 49 | } 50 | } 51 | void unlock() { 52 | // std::memory_order_release will make sure all memory writting operations will be finished by the time this is done. 53 | locked.clear(std::memory_order_release); 54 | } 55 | 56 | private: 57 | std::atomic_flag locked = ATOMIC_FLAG_INIT; 58 | }; 59 | 60 | // This is by no means the most performance implementation, but it works and this will unlikely to be the bottleneck 61 | // I will leave it this way unless there is a performance problem. 62 | const char* make_str_unique(const char* s) { 63 | static spinlock_mutex g_spin_lock; 64 | std::lock_guard guard(g_spin_lock); 65 | 66 | if (s == nullptr) 67 | return nullptr; 68 | 69 | const auto str = std::string(s); 70 | std::unordered_set::iterator it = g_string_container.find(str); 71 | if (it == g_string_container.end()) { 72 | g_string_container.insert(str); 73 | it = g_string_container.find(str); 74 | } 75 | return it->c_str(); 76 | } 77 | 78 | TSL_NAMESPACE_END -------------------------------------------------------------------------------- /src/tsl_lib/compiler/str_helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | // There are a few places requesting storing strings and comparisons too. This is a nice helper 21 | // file hiding the details of string implementation. Basically, it does two things 22 | // 23 | // - Each string is an unique pointer, which makes comparison of string a lot cheapper. 24 | // - String memory will be kepted in an internal container, not explicit memory management is needed. 25 | // - It is already sychronized so it is thread safe. 26 | 27 | #include "tsl_version.h" 28 | 29 | TSL_NAMESPACE_BEGIN 30 | 31 | // create a unique string 32 | const char* make_str_unique(const char*); 33 | 34 | TSL_NAMESPACE_END -------------------------------------------------------------------------------- /src/tsl_lib/compiler/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "tsl_version.h" 21 | 22 | TSL_NAMESPACE_BEGIN 23 | 24 | // Data types that can be used as funciton arguments supported in TSL. 25 | enum class DataTypeEnum : int{ 26 | INVALID = 0, 27 | VOID , 28 | INT , 29 | FLOAT , 30 | DOUBLE , 31 | BOOL , 32 | CLOSURE , 33 | STRUCT 34 | }; 35 | 36 | // A thin wrapper of data type with structure name if necessary. 37 | struct DataType{ 38 | DataTypeEnum m_type; 39 | const char* m_structure_name; // this is only used for structure type 40 | }; 41 | 42 | static inline bool operator == (DataType& data_type0, DataType& data_type1) { 43 | return data_type0.m_type == data_type1.m_type && data_type0.m_structure_name == data_type1.m_structure_name; 44 | } 45 | 46 | // Each argument could have some configuration 47 | enum VariableConfig : int { 48 | NONE = 0, 49 | INPUT = 1, 50 | OUTPUT = 2, 51 | CONST = 4, 52 | }; 53 | 54 | TSL_NAMESPACE_END -------------------------------------------------------------------------------- /src/tsl_lib/system/callback.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include "tsl_define.h" 19 | #include "system/impl.h" 20 | 21 | TSL_NAMESPACE_BEGIN 22 | 23 | #ifdef TSL_ON_WINDOWS 24 | #define DLLEXPORT __declspec(dllexport) 25 | #else 26 | #define DLLEXPORT 27 | #endif 28 | 29 | using generic_ptr = int*; 30 | 31 | extern "C" { 32 | // allocate memory inside shaders 33 | DLLEXPORT int* TSL_MALLOC(int size) { 34 | return (int*)allocate_memory(size); 35 | } 36 | 37 | // 2D texture sample 38 | DLLEXPORT void TSL_TEXTURE2D_SAMPLE(generic_ptr ptr, float3* color, float u, float v) { 39 | sample_2d((const void*)ptr, u, v, *color); 40 | } 41 | 42 | // 2D texture sample alpha 43 | DLLEXPORT void TSL_TEXTURE2D_SAMPLE_ALPHA(generic_ptr ptr, float* alpha, float u, float v) { 44 | sample_alpha_2d((const void*)ptr, u, v, *alpha); 45 | } 46 | } 47 | 48 | TSL_NAMESPACE_END 49 | -------------------------------------------------------------------------------- /src/tsl_lib/system/impl.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "tsl_system.h" 28 | #include "compiler/types.h" 29 | 30 | TSL_NAMESPACE_BEGIN 31 | 32 | class GlobalModule; 33 | class ShaderResourceHandle; 34 | class AstNode_FunctionPrototype; 35 | using ShaderResourceTable = std::unordered_map; 36 | using ShaderUnitConnection = std::unordered_map>>; 37 | using ShaderWrapperConnection = std::unordered_map>; 38 | using ShaderUnitInputDefaultMapping = std::unordered_map>; 39 | 40 | //! @brief Exposed argument descriptor. 41 | /** 42 | * Argument descriptor is used to describe the exposed arguments in a shader group template. 43 | * This data structure keeps track of argument name, type and output signature, meaning it is 44 | * both for input arguments and output arguments. 45 | * This is only used for shader group, shader unit exposes everything defined in the shader 46 | * source code. 47 | */ 48 | struct ExposedArgDescriptor { 49 | std::string m_source_shader_unit_name; 50 | std::string m_source_shader_unit_arg_name; 51 | std::string m_name; 52 | DataType m_type; 53 | bool m_is_output = false; 54 | }; 55 | 56 | // This data structure hides all LLVM related data from ShaderInstance. 57 | struct ShaderInstance_Impl { 58 | public: 59 | ~ShaderInstance_Impl() { 60 | // explicit order of destruction is mandatory here to prevent crashing in LLVM code. 61 | m_execution_engine = nullptr; 62 | m_shader_unit_template = nullptr; 63 | } 64 | 65 | /**< Shader unit template that creates this shader instance. */ 66 | std::shared_ptr m_shader_unit_template; 67 | 68 | // the execute engine for this module, it is important to keep this execution engine alive to make sure 69 | // the raw function pointer is still valid. 70 | std::unique_ptr m_execution_engine; 71 | 72 | // the function address for host code to call 73 | uint64_t m_function_pointer = 0; 74 | }; 75 | 76 | struct ShadingSystem_Impl { 77 | /**< Closure register */ 78 | std::unique_ptr m_global_module; 79 | 80 | /**< This is needs to be bound before shader compilation. */ 81 | std::unique_ptr m_callback; 82 | }; 83 | 84 | struct ShaderUnitTemplate_Impl { 85 | /**< Name of the shader unit. */ 86 | std::string m_name; 87 | 88 | /**< TSL global data. */ 89 | GlobalVarList m_tsl_global; 90 | unsigned m_tsl_global_hash = 0; 91 | 92 | /**< root function name. */ 93 | std::string m_root_function_name; 94 | 95 | /**< root ast node. */ 96 | std::shared_ptr m_ast_root; 97 | 98 | /**< The llvm context created in the shading_context is needed as long as this is alive. */ 99 | std::shared_ptr m_shading_context; 100 | 101 | /**< Shader resource table. */ 102 | ShaderResourceTable m_shader_resource_table; 103 | 104 | /**< Description of exposed arguments. */ 105 | std::vector m_exposed_args; 106 | 107 | // the llvm module owned by this shader unit 108 | std::unique_ptr m_module; 109 | 110 | // the dependent llvm module 111 | std::unordered_set m_dependencies; 112 | 113 | // llvm function pointer 114 | // this is just a copy to the llvm object, the memory ownership is maintained through m_module. 115 | llvm::Function* m_llvm_function = nullptr; 116 | 117 | /**< Whether llvm verification is enabled. */ 118 | bool m_llvm_verification_enabled = false; 119 | 120 | //! @brief Parse shader group dependencies. 121 | //! 122 | //! @param sut Dependencies of this module. 123 | virtual void parse_dependencies(ShaderUnitTemplate_Impl* sut) const; 124 | 125 | //! @brief Virtual destructor, this is needed to make sure deletes all members of derived class. 126 | virtual ~ShaderUnitTemplate_Impl() {} 127 | }; 128 | 129 | //! @brief A thin wrapper to allow a shader unit added in a group more than once. 130 | /** 131 | * In order to allow a shader unit to be added in a shader group multiple times, there needs to be a thin wrapper 132 | * to differentiate different instances of shader unit. 133 | */ 134 | struct ShaderUnitTemplateCopy { 135 | std::string m_name; 136 | std::shared_ptr m_shader_unit_template; 137 | }; 138 | 139 | struct ShaderGroupTemplate_Impl : public ShaderUnitTemplate_Impl { 140 | /**< Name of the root shader unit. */ 141 | std::string m_root_shader_unit_name; 142 | 143 | /**< Shader units belong to this group. */ 144 | std::unordered_map m_shader_units; 145 | 146 | /**< Shader unit connection. */ 147 | ShaderUnitConnection m_shader_unit_connections; 148 | 149 | /**< Wrapper parameter connection. */ 150 | ShaderWrapperConnection m_input_args; 151 | ShaderWrapperConnection m_output_args; 152 | 153 | /**< Shader default value. */ 154 | ShaderUnitInputDefaultMapping m_shader_input_defaults; 155 | 156 | //! @brief Parse shader group dependencies. 157 | //! 158 | //! @param sut Dependencies of this module. 159 | void parse_dependencies(ShaderUnitTemplate_Impl* sut) const override; 160 | }; 161 | 162 | struct ShadingContext_Impl { 163 | /**< TSL compiler. */ 164 | std::unique_ptr m_compiler; 165 | 166 | /**< Shading system owning the context. */ 167 | std::shared_ptr m_shading_system_impl = nullptr; 168 | }; 169 | 170 | //! @brief Allocate memory in shader. 171 | void* allocate_memory(const unsigned size); 172 | 173 | //! @brief Output error during shader compilation. 174 | void emit_error(const char* error, ...); 175 | 176 | //! @brief Output warning during shader compilation. 177 | void emit_warning(const char* format, ...); 178 | 179 | //! @brief Texture sampling 180 | void sample_2d(const void* texture, float u, float v, float3& color); 181 | 182 | //! @brief Texture sampling alpha channel only. 183 | void sample_alpha_2d(const void* texture, float u, float v, float& alpha); 184 | 185 | TSL_NAMESPACE_END -------------------------------------------------------------------------------- /src/tsl_lib/system/shading_system.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include "tsl_system.h" 22 | #include "compiler/global_module.h" 23 | #include "system/impl.h" 24 | 25 | TSL_NAMESPACE_BEGIN 26 | 27 | /** This data structure is only accessable from shading system */ 28 | static std::shared_ptr g_shading_system_impl = nullptr; 29 | 30 | ShadingSystem& ShadingSystem::get_instance() { 31 | static ShadingSystem ss; 32 | return ss; 33 | } 34 | 35 | ShadingSystem::ShadingSystem() { 36 | llvm::InitializeNativeTarget(); 37 | llvm::InitializeNativeTargetAsmPrinter(); 38 | 39 | g_shading_system_impl = std::make_shared(); 40 | 41 | g_shading_system_impl->m_global_module = std::make_unique(); 42 | g_shading_system_impl->m_global_module->init(); 43 | } 44 | 45 | ShadingSystem::~ShadingSystem() { 46 | g_shading_system_impl = nullptr; 47 | } 48 | 49 | std::shared_ptr ShadingSystem::make_shading_context() { 50 | return std::shared_ptr(new ShadingContext(g_shading_system_impl)); 51 | } 52 | 53 | ClosureID ShadingSystem::register_closure_type(const std::string& name, ClosureArgList& mapping, int structure_size) { 54 | return g_shading_system_impl->m_global_module->register_closure_type(name, mapping, structure_size); 55 | } 56 | 57 | void ShadingSystem::register_shadingsystem_interface(std::unique_ptr ssi){ 58 | g_shading_system_impl->m_callback = std::move(ssi); 59 | } 60 | 61 | void* allocate_memory(const unsigned size) { 62 | const auto callback = g_shading_system_impl->m_callback.get(); 63 | return callback ? callback->allocate(size) : nullptr; 64 | } 65 | 66 | void emit_error(const char* format, ...) { 67 | va_list argList; 68 | 69 | // 1MB should be good enough for most errors. 70 | constexpr int max_buf_size = 1024 * 1024; 71 | 72 | std::unique_ptr buf = std::make_unique(max_buf_size); 73 | va_start(argList, format); 74 | vsprintf(buf.get(), format, argList); 75 | va_end(argList); 76 | 77 | const auto callback = g_shading_system_impl->m_callback.get(); 78 | if (callback) 79 | callback->catch_debug(TSL_DEBUG_LEVEL::TSL_DEBUG_ERROR, buf.get()); 80 | } 81 | 82 | void emit_warning(const char* format, ...) { 83 | va_list argList; 84 | 85 | // 1MB should be good enough for most errors. 86 | constexpr int max_buf_size = 1024 * 1024; 87 | 88 | std::unique_ptr buf = std::make_unique(max_buf_size); 89 | va_start(argList, format); 90 | vsprintf(buf.get(), format, argList); 91 | va_end(argList); 92 | 93 | const auto callback = g_shading_system_impl->m_callback.get(); 94 | if (callback) 95 | callback->catch_debug(TSL_DEBUG_LEVEL::TSL_DEBUG_WARNING, buf.get()); 96 | } 97 | 98 | void sample_2d(const void* texture, float u, float v, float3& color) { 99 | const auto callback = g_shading_system_impl->m_callback.get(); 100 | if (nullptr == callback) 101 | return; 102 | callback->sample_2d(texture, u, v, color); 103 | } 104 | 105 | void sample_alpha_2d(const void* texture, float u, float v, float& alpha) { 106 | const auto callback = g_shading_system_impl->m_callback.get(); 107 | if (nullptr == callback) 108 | return; 109 | callback->sample_alpha_2d(texture, u, v, alpha); 110 | } 111 | 112 | TSL_NAMESPACE_END 113 | -------------------------------------------------------------------------------- /src/tsl_sample/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | # platform programming shading language. 4 | # 5 | # Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | # 7 | # TSL is a free software written for educational purpose. Anyone can distribute 8 | # or modify it under the the terms of the GNU General Public License Version 3 as 9 | # published by the Free Software Foundation. However, there is NO warranty that 10 | # all components are functional in a perfect manner. Without even the implied 11 | # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License along with 15 | # this program. If not, see . 16 | # 17 | 18 | # collect all files in this library 19 | file(GLOB_RECURSE project_headers *.h *.hpp) 20 | file(GLOB_RECURSE project_cpps *.cpp) 21 | file(GLOB_RECURSE project_cs *.c) 22 | file(GLOB_RECURSE project_ccs *.cc) 23 | 24 | # group all categories of files into one macro 25 | set(all_project_files ${project_headers} ${project_cpps} ${project_cs} ${project_ccs}) 26 | set(all_files ${all_project_files} ${tsl_include}) 27 | 28 | # give each file a proper folder based on its path 29 | source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${all_project_files}) 30 | 31 | # a separate folder for files outside this folder 32 | source_group( "tsl_include" FILES ${tsl_include} ) 33 | 34 | # include directories 35 | include_directories( "${TSL_SOURCE_DIR}/src/thirdparty" "${TSL_SOURCE_DIR}/src/include" "${TSL_SOURCE_DIR}/src/tsl_sample/common/") 36 | 37 | # specify the output directory 38 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${TSL_SOURCE_DIR}/bin") 39 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${TSL_SOURCE_DIR}/bin") 40 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${TSL_SOURCE_DIR}/bin") 41 | 42 | # CMake will strip the full rpath that is generated in building process during installation. 43 | # In order to link the libraries succesfully, it is necessary to specify the relatively path where the share lib is in. 44 | if(TSL_PLATFORM_LINUX) 45 | SET(CMAKE_INSTALL_RPATH "$ORIGIN/../lib:$ORIGIN/") 46 | elseif(TSL_PLATFORM_MAC) 47 | SET(CMAKE_INSTALL_RPATH "@loader_path/../lib;@loader_path") 48 | endif() 49 | 50 | # unit test project to make sure TSL is functional properly 51 | add_executable(TSL_Sample ${all_files}) 52 | 53 | # Setup correct output name for different configurations 54 | set_target_properties( TSL_Sample PROPERTIES RELEASE_OUTPUT_NAME "tsl_sample_r" ) 55 | set_target_properties( TSL_Sample PROPERTIES DEBUG_OUTPUT_NAME "tsl_sample_d" ) 56 | 57 | if (TSL_PLATFORM_MAC OR TSL_PLATFORM_LINUX) 58 | set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -pthread") 59 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") 60 | 61 | # link to tsl library 62 | target_link_libraries( TSL_Sample TSL_Lib ) 63 | endif() 64 | 65 | if (TSL_PLATFORM_WIN) 66 | set_target_properties( TSL_Sample PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} /MD /wd4251 /wd4530" ) 67 | 68 | # enable multi-thread compiling 69 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP${N}") 70 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP${N}") 71 | 72 | # ignore "warning LNK4199: /DELAYLOAD:shell32.dll ignored; no imports found from shell32.dll" 73 | target_link_libraries( TSL_Sample PRIVATE "-ignore:4199" TSL_Lib ) 74 | endif() 75 | 76 | # This allows install command 77 | install(TARGETS TSL_Sample 78 | RUNTIME DESTINATION bin) -------------------------------------------------------------------------------- /src/tsl_sample/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | /* 19 | This project is a simple ray tracer program with TSL integrated in its tiny material 20 | system. The purpose of this project is to demonstrate how TSL could be used in a ray 21 | tracer projects with least amount of code. 22 | 23 | Of course, TSL is capable of driving shading system for ray tracer way more complex 24 | than this toy program. For a more sophisticated material system implementation in a 25 | reasonable complex ray tracing rendering project, please check out this project 26 | SORT ( Simple Open-source Ray Tracing ) 27 | main page: http://sort-renderer.com/ 28 | github repository: https://github.com/JiayinCao/SORT 29 | */ 30 | 31 | #include 32 | #include "rt_tsl.h" 33 | 34 | int rt_main(int); 35 | int main(int argc, char* argv[]) { 36 | // initialize tsl library 37 | initialize_tsl_system(); 38 | 39 | const int spp = (argc < 2) ? 4 : std::atoi(argv[1]); 40 | return rt_main( spp ); 41 | } -------------------------------------------------------------------------------- /src/tsl_sample/rt_bxdf.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include "rt_common.h" 20 | #include "rt_bxdf.h" 21 | 22 | // uniformly sample a point on disk 23 | void UniformSampleDisk(float& x, float& y) { 24 | const auto u = random_number(), v = random_number(); 25 | const auto theta = 2.0f * PI * u; 26 | const auto radius = sqrt(v); 27 | x = radius * cos(theta); 28 | y = radius * sin(theta); 29 | } 30 | 31 | float clamp(const float x, const float a, const float b) { 32 | return (x < a) ? a : ((x > b) ? b : x); 33 | } 34 | 35 | Vec spherical_vec(float theta, float phi) { 36 | const auto x = sin(theta) * cos(phi); 37 | const auto y = cos(theta); 38 | const auto z = sin(theta) * sin(phi); 39 | return Vec(x, y, z); 40 | } 41 | 42 | float cos_theta(const Vec& v) { 43 | return v.y; 44 | } 45 | 46 | float cos_theta2(const Vec& v) { 47 | return SQR(cos_theta(v)); 48 | } 49 | 50 | float tan_theta2(const Vec& w) { 51 | return 1.0f / cos_theta2(w) - 1.0f; 52 | } 53 | 54 | Vec cross(const Vec& v0, const Vec& v1) { 55 | return Vec( v0.y * v1.z - v0.z * v1.y, v0.z * v1.x - v0.x * v1.z, v0.x * v1.y - v0.y * v1.x); 56 | } 57 | 58 | float sin_theta2(const Vec& w) { 59 | return std::max(0.f, 1.f - cos_theta2(w)); 60 | } 61 | 62 | float sin_theta(const Vec& w) { 63 | return sqrtf(sin_theta2(w)); 64 | } 65 | 66 | float cos_phi(const Vec& w) { 67 | float sintheta = sin_theta(w); 68 | if (sintheta == 0.f) return 1.f; 69 | return clamp(w.x / sintheta, -1.f, 1.f); 70 | } 71 | 72 | float cos_phi2(const Vec& w) { 73 | return SQR(cos_phi(w)); 74 | } 75 | 76 | 77 | void coordinateSystem(const Vec& v0, Vec& v1, Vec& v2) { 78 | if (fabs(v0.x) > fabs(v0.y)) { 79 | float invLen = 1.0f / sqrtf(v0.x * v0.x + v0.z * v0.z); 80 | v1 = Vec(-v0.z * invLen, 0.0f, v0.x * invLen); 81 | } 82 | else { 83 | float invLen = 1.0f / sqrtf(v0.y * v0.y + v0.z * v0.z); 84 | v1 = Vec(0.0f, v0.z * invLen, -v0.y * invLen); 85 | } 86 | v2 = cross(v0, v1); 87 | } 88 | 89 | Vec Bxdf::local_to_world(const Vec& pos, const Vec& vec) { 90 | auto n = (pos - sphere_center).norm(); 91 | 92 | if (flip_normal) 93 | n = n * -1.0f; 94 | 95 | Vec t, bt; 96 | coordinateSystem(n, t, bt); 97 | 98 | Vec ret; 99 | ret.x = t.x * vec.x + n.x * vec.y + bt.x * vec.z; 100 | ret.y = t.y * vec.x + n.y * vec.y + bt.y * vec.z; 101 | ret.z = t.z * vec.x + n.z * vec.y + bt.z * vec.z; 102 | return ret; 103 | } 104 | 105 | Vec Bxdf::world_to_local(const Vec& pos, const Vec& vec) { 106 | auto n = (pos - sphere_center).norm(); 107 | 108 | if (flip_normal) 109 | n = n * -1.0f; 110 | 111 | Vec t, bt; 112 | coordinateSystem(n, t, bt); 113 | 114 | Vec ret; 115 | ret.x = t.x * vec.x + t.y * vec.y + t.z * vec.z; 116 | ret.y = n.x * vec.x + n.y * vec.y + n.z * vec.z; 117 | ret.z = bt.x * vec.x + bt.y * vec.y + bt.z * vec.z; 118 | return ret; 119 | } 120 | 121 | Vec Lambert::sample(const Vec& pos, const Vec& wo, Vec& wi, float& pdf) { 122 | const auto local_wo = world_to_local(pos, wo); 123 | 124 | if ( local_wo.y <= 0.0f ) { 125 | pdf = 0.0f; 126 | return Vec(); 127 | } 128 | 129 | float x, z; 130 | UniformSampleDisk(x, z); 131 | float y = sqrt(std::max(0.0f, 1.0f - x * x - z * z)); 132 | const auto local_wi = Vec(x, y, z); 133 | wi = local_to_world(pos, local_wi); 134 | 135 | pdf = fabs(local_wi.y) / PI; 136 | 137 | return basecolor * (fabs(local_wi.y) / PI) ; 138 | } 139 | 140 | Vec Microfacet::sample(const Vec& pos, const Vec& wo, Vec& wi, float& pdf) { 141 | const auto local_wo = world_to_local(pos, wo); 142 | if (local_wo.y <= 0.0f) { 143 | pdf = 0.0f; 144 | return Vec(); 145 | } 146 | 147 | // importance sampling of GGX distribution 148 | // https://agraphicsguy.wordpress.com/2015/11/01/sampling-microfacet-brdf/ 149 | const float u = random_number(), v = random_number(); 150 | const auto theta = atan(alpha * std::sqrt(v / (1.0f - v))); 151 | const auto phi = TWO_PI * u; 152 | const auto h = spherical_vec(theta, phi); 153 | 154 | // reflect the wo along the sampled normal 155 | const auto local_wi = h * ( 2.0f * local_wo.dot(h) ) - local_wo; 156 | wi = local_to_world(pos, local_wi); 157 | 158 | // kill all sampled direction that is below the surface. 159 | auto n = (pos - sphere_center).norm(); 160 | if (wi.dot(n) <= 0.0f) { 161 | pdf = 0.0f; 162 | return Vec(); 163 | } 164 | 165 | // https://www.pbrt.org/ 166 | // Anisotropic GGX (Trowbridge-Reitz) distribution formula, pbrt-v3 ( page 539 ) 167 | const auto cos_theta_h_sq = cos_theta2(h); 168 | if (cos_theta_h_sq <= 0.0f) return 0.f; 169 | const auto ggx = 1.0f / (cos_theta_h_sq + (1.0f - cos_theta_h_sq) / alpha2); 170 | const auto nov = cos_theta(local_wo); 171 | 172 | // evaluate the pdf 173 | pdf = ggx * cos_theta(h) / (4.0f * local_wo.dot(h)); 174 | 175 | // fresnel, to be done 176 | const auto fresnel = basecolor + ((Vec(1.0f) - basecolor) * pow(1.0f - nov, 5.0f)); 177 | 178 | // visibility term 179 | // Smith shadow - masking function 180 | const auto smith_vis = [](const Vec& v, const float alpha2) { 181 | const auto tan_theta_sq = tan_theta2(v); 182 | if (isinf(tan_theta_sq)) return 0.0f; 183 | const auto cos_phi_sq = cos_phi2(v); 184 | return 2.0f / (1.0f + sqrt(1.0f + alpha2 * tan_theta_sq)); 185 | }; 186 | const auto vis = smith_vis(local_wo, alpha2) * smith_vis(local_wi, alpha2); 187 | 188 | // the final evaluated microfacet brdf multiplied by cos( n , wi ) 189 | return fresnel * ( ggx * vis / (4.0f * nov)); 190 | } -------------------------------------------------------------------------------- /src/tsl_sample/rt_bxdf.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #include "rt_common.h" 21 | 22 | // Bxdf is the basic of surface interaction. 23 | class Bxdf { 24 | public: 25 | Bxdf(const Vec center, const bool fn) 26 | :sphere_center(center), flip_normal(fn) {} 27 | virtual ~Bxdf() {} 28 | 29 | // Take sample based on bxdf. The returned value is the multiplication of cosine 30 | // of the angle between sampled direction and normal and its bxdf given the input 31 | // direction and sampled direction. 32 | virtual Vec sample(const Vec& pos, const Vec& wo, Vec& wi, float& pdf) = 0; 33 | 34 | protected: 35 | // The way this program converting world space vector to local space is very specific 36 | // since all primitives are sphere, I took advantage of the fact and simplified the 37 | // transformation. 38 | const Vec sphere_center; 39 | const bool flip_normal; 40 | 41 | // Helper method to convert vector between world space and local space 42 | Vec local_to_world(const Vec& pos, const Vec& vec); 43 | Vec world_to_local(const Vec& pos, const Vec& vec); 44 | }; 45 | 46 | class Lambert : public Bxdf{ 47 | public: 48 | Lambert(const Vec color, const Vec center, const bool fn) 49 | :basecolor(color), Bxdf(center, fn) {} 50 | Vec sample(const Vec& pos, const Vec& wo, Vec& wi, float& pdf) override; 51 | 52 | private: 53 | const Vec basecolor; 54 | }; 55 | 56 | class Microfacet : public Bxdf { 57 | public: 58 | Microfacet(const Vec bc, const float r, const Vec center, const bool fn) 59 | :Bxdf(center, fn), basecolor(bc), alpha(SQR(std::max(r,(float)1e-3))), alpha2(SQR(alpha)){} 60 | Vec sample(const Vec& pos, const Vec& wo, Vec& wi, float& pdf) override; 61 | 62 | private: 63 | const Vec basecolor; 64 | const float alpha; 65 | const float alpha2; 66 | }; -------------------------------------------------------------------------------- /src/tsl_sample/rt_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #define PI 3.1415926f 25 | #define TWO_PI PI * 2.0f 26 | #define SQR(x) ((x)*(x)) 27 | 28 | // The type of bxdf available in this ray tracer, there is really no limitation on 29 | // the number of bxdf that can be registered in a ray tracer program. 30 | // It is just a few bxdfs here used to demonstrate how TSL could drive the material 31 | // system. 32 | enum MaterialType : int { 33 | MT_Matt = 0, // matte material 34 | MT_Gold, // gold material 35 | MT_Perlin_Matt, // material with noise 36 | 37 | Cnt 38 | }; 39 | 40 | // basic vector data structure. it is a vector of three for multiple purposes, like color, position, vector. 41 | struct Vec { 42 | double x, y, z; 43 | Vec(double x_=0.0) { x = x_; y = x_; z = x_; } 44 | Vec(const Tsl_Namespace::float3& v) { x = v.x; y = v.y; z = v.z; } 45 | Vec(double x_, double y_, double z_) { x = x_; y = y_; z = z_; } 46 | Vec operator+(const Vec& b) const { return Vec(x + b.x, y + b.y, z + b.z); } 47 | Vec operator-(const Vec& b) const { return Vec(x - b.x, y - b.y, z - b.z); } 48 | Vec operator*(double b) const { return Vec(x * b, y * b, z * b); } 49 | Vec mult(const Vec& b) const { return Vec(x * b.x, y * b.y, z * b.z); } 50 | Vec& norm() { return *this = *this * (1 / sqrt(x * x + y * y + z * z)); } 51 | double dot(const Vec& b) const { return x * b.x + y * b.y + z * b.z; } // cross: 52 | Vec operator%(Vec& b) { return Vec(y * b.z - z * b.y, z * b.x - x * b.z, x * b.y - y * b.x); } 53 | }; 54 | 55 | // data structure representing a ray 56 | struct Ray { Vec o, d; Ray(Vec o_, Vec d_) : o(o_), d(d_) {} }; 57 | 58 | // data structure representing a sphere 59 | struct Sphere { 60 | double rad; // radius 61 | Vec p, e, c; // position, emission, color 62 | MaterialType mt; // material type 63 | const bool fn; // whether normal is flipped 64 | Sphere(double rad_, Vec p_, Vec e_, Vec c_, MaterialType mt_, bool fn) : 65 | rad(rad_), p(p_), e(e_), c(c_), mt(mt_), fn(fn) {} 66 | 67 | // ray sphere intersection 68 | double intersect(const Ray& r) const { // returns distance, 0 if nohit 69 | Vec op = p - r.o; // Solve t^2*d.d + 2*t*(o-p).d + (o-p).(o-p)-R^2 = 0 70 | double t, eps = 1e-4, b = op.dot(r.d), det = b * b - op.dot(op) + rad * rad; 71 | if (det < 0) return 0; else det = sqrt(det); 72 | return (t = b - det) > eps ? t : ((t = b + det) > eps ? t : 0); 73 | } 74 | }; 75 | 76 | // generate a random number 77 | inline float random_number() { 78 | thread_local static std::random_device r; 79 | thread_local static std::default_random_engine e1(r()); 80 | std::uniform_int_distribution uniform_dist(0, 65535); 81 | return (float)uniform_dist(e1) / 65535.f; 82 | } -------------------------------------------------------------------------------- /src/tsl_sample/rt_tsl.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "rt_bxdf.h" 26 | 27 | // Initialize tiny shading language system 28 | // It basically takes the chances to initialize all necessary data structure, like registering callback, 29 | // closure type, tsl global data structure. 30 | // This is considered the set up of TSL system, it is totally fine to leave it in one single thread, since 31 | // it is fairly cheap to do so, multi-threading the initialization literally means nothing. 32 | void initialize_tsl_system(); 33 | 34 | // reset memory pool counter 35 | void reset_memory_allocator(); 36 | 37 | // Given a sphere object, acquire the material based on it. 38 | // Note, the bxdf is returned through a smart pointer, this is by no means a performant way of doing this. 39 | // In a reasonable complex ray tracing program, one may need to implement a memory pool to allocate bxdf 40 | // in a much cheapper manner to avoid memory allocation overhead. 41 | // However, this is not the focus of this program, I chose to live with it. 42 | std::unique_ptr get_bxdf(const Sphere& sphere, const Vec& p); 43 | 44 | // tsl global data structure 45 | DECLARE_TSLGLOBAL_BEGIN(TslGlobal) 46 | DECLARE_TSLGLOBAL_VAR(Tsl_float3, base_color) // base color of the material 47 | DECLARE_TSLGLOBAL_VAR(Tsl_float3, center) // center of the sphere in world space 48 | DECLARE_TSLGLOBAL_VAR(Tsl_float, radius) // radius of the sphere 49 | DECLARE_TSLGLOBAL_VAR(Tsl_float3, position) // shaded poisition in world space 50 | DECLARE_TSLGLOBAL_VAR(Tsl_bool, flip_normal) // whether the normal is flipped 51 | DECLARE_TSLGLOBAL_END() 52 | 53 | // closure for lambert type 54 | DECLARE_CLOSURE_TYPE_BEGIN(ClosureTypeLambert, "lambert") 55 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeLambert, Tsl_float3, base_color) 56 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeLambert, Tsl_float3, sphere_center) 57 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeLambert, Tsl_bool, flip_normal) 58 | DECLARE_CLOSURE_TYPE_END(ClosureTypeLambert) 59 | 60 | // closure for microfacet type 61 | DECLARE_CLOSURE_TYPE_BEGIN(ClosureTypeMicrofacet, "microfacet") 62 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeMicrofacet, Tsl_float3, base_color) 63 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeMicrofacet, Tsl_float, roughness) 64 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeMicrofacet, Tsl_float3, sphere_center) 65 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeMicrofacet, Tsl_bool, flip_normal) 66 | DECLARE_CLOSURE_TYPE_END(ClosureTypeMicrofacet) -------------------------------------------------------------------------------- /src/tsl_test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | # platform programming shading language. 4 | # 5 | # Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | # 7 | # TSL is a free software written for educational purpose. Anyone can distribute 8 | # or modify it under the the terms of the GNU General Public License Version 3 as 9 | # published by the Free Software Foundation. However, there is NO warranty that 10 | # all components are functional in a perfect manner. Without even the implied 11 | # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | # General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License along with 15 | # this program. If not, see . 16 | # 17 | 18 | # collect all files in this library 19 | file(GLOB_RECURSE project_headers *.h *.hpp) 20 | file(GLOB_RECURSE project_cpps *.cpp) 21 | file(GLOB_RECURSE project_cs *.c) 22 | file(GLOB_RECURSE project_ccs *.cc) 23 | 24 | # group all categories of files into one macro 25 | set(all_project_files ${project_headers} ${project_cpps} ${project_cs} ${project_ccs}) 26 | set(all_files ${all_project_files} ${tsl_include} ${gtest_files}) 27 | 28 | # give each file a proper folder based on its path 29 | source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${all_project_files}) 30 | 31 | # a separate folder for files outside this folder 32 | source_group( "tsl_include" FILES ${tsl_include} ) 33 | source_group( "google test" FILES ${gtest_files} ) 34 | 35 | # include directories 36 | include_directories( "${TSL_SOURCE_DIR}/src/thirdparty" "${TSL_SOURCE_DIR}/src/include" ) 37 | 38 | # specify the output directory 39 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${TSL_SOURCE_DIR}/bin") 40 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${TSL_SOURCE_DIR}/bin") 41 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${TSL_SOURCE_DIR}/bin") 42 | 43 | # CMake will strip the full rpath that is generated in building process during installation. 44 | # In order to link the libraries succesfully, it is necessary to specify the relatively path where the share lib is in. 45 | if(TSL_PLATFORM_LINUX) 46 | SET(CMAKE_INSTALL_RPATH "$ORIGIN/../lib:$ORIGIN/") 47 | elseif(TSL_PLATFORM_MAC) 48 | SET(CMAKE_INSTALL_RPATH "@loader_path/../lib;@loader_path") 49 | endif() 50 | 51 | # unit test project to make sure TSL is functional properly 52 | add_executable(TSL_Test ${all_files}) 53 | 54 | # Setup correct output name for different configurations 55 | set_target_properties( TSL_Test PROPERTIES RELEASE_OUTPUT_NAME "tsl_test_r" ) 56 | set_target_properties( TSL_Test PROPERTIES DEBUG_OUTPUT_NAME "tsl_test_d" ) 57 | 58 | if (TSL_PLATFORM_MAC OR TSL_PLATFORM_LINUX) 59 | set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -pthread") 60 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") 61 | 62 | # link to tsl library 63 | target_link_libraries( TSL_Test TSL_Lib ) 64 | endif() 65 | 66 | if (TSL_PLATFORM_WIN) 67 | set_target_properties( TSL_Test PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} /MD /wd4251 /wd4530" ) 68 | 69 | # enable multi-thread compiling 70 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP${N}") 71 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP${N}") 72 | 73 | # ignore "warning LNK4199: /DELAYLOAD:shell32.dll ignored; no imports found from shell32.dll" 74 | target_link_libraries( TSL_Test PRIVATE "-ignore:4199" TSL_Lib ) 75 | endif() 76 | 77 | # This allows install command 78 | install(TARGETS TSL_Test 79 | RUNTIME DESTINATION bin) -------------------------------------------------------------------------------- /src/tsl_test/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | /* 19 | This project is mainly for the purpose of verifying features offered by TSL are properly executed 20 | as expected. It has quite a few number of unit tests that verify lots of areas in the shading 21 | language. If anything inside the shading language breaks, there is a good chance it will fail at 22 | least one of the unit tests in it. 23 | Every commit show make sure all unit tests are passed before checking in on Git. Otherwise, it means 24 | there is a bug in the system. 25 | 26 | WARNING, since it is a shading language, there is for sure tons of corner cases which I didn't cover 27 | that could also break the system. I will try covering as much as possible in the future, but since 28 | it already replaced all features offered by OSL in my renderer SORT (http://sort-renderer.com/), the 29 | priority of populating this project with more unit tests is relatively low. 30 | */ 31 | 32 | #include 33 | #include "gtest/gtest.h" 34 | #include "tsl_system.h" 35 | #include "test/test_common.h" 36 | 37 | class ShadingSystemInterfaceSimple : public Tsl_Namespace::ShadingSystemInterface { 38 | public: 39 | // This is by no mean a good example of allocating memory of bxdf in real renderer. 40 | // The purpose of this code is simply for testing, not for performance. 41 | void* allocate(unsigned int size) const override { 42 | m_memory_holder.push_back(std::move(std::make_unique(size))); 43 | return m_memory_holder.back().get(); 44 | } 45 | 46 | // No error will be output since there are invalid unit tests. 47 | void catch_debug(const Tsl_Namespace::TSL_DEBUG_LEVEL level, const char* error) const override { 48 | #if defined(TSL_DEBUG) 49 | std::cout << error << std::endl; 50 | #endif 51 | } 52 | 53 | // Sample texture 2d 54 | void sample_2d(const void* texture, float u, float v, float3& color) const override { 55 | auto ts = (const TextureSimple*)texture; 56 | color = ts->sample2d(u, v); 57 | } 58 | void sample_alpha_2d(const void* texture, float u, float v, float& alpha) const override { 59 | auto ts = (const TextureSimple*)texture; 60 | alpha = ts->sample_alpha_2d(u, v); 61 | } 62 | 63 | private: 64 | mutable std::vector> m_memory_holder; 65 | }; 66 | 67 | ClosureID g_lambert_closure_id = INVALID_CLOSURE_ID; 68 | ClosureID g_random_closure_id = INVALID_CLOSURE_ID; 69 | ClosureID g_bxdf_with_double_id = INVALID_CLOSURE_ID; 70 | ClosureID g_microfacete_id = INVALID_CLOSURE_ID; 71 | ClosureID g_layered_bxdf_id = INVALID_CLOSURE_ID; 72 | ClosureID g_lambert_in_sort_id = INVALID_CLOSURE_ID; 73 | ClosureID g_measured_brdf_id = INVALID_CLOSURE_ID; 74 | 75 | int main(int argc, char** argv) { 76 | std::cout << "-------------------------- " TSL_INTRO_STRING " --------------------------" << std::endl; 77 | 78 | auto& shading_system = Tsl_Namespace::ShadingSystem::get_instance(); 79 | 80 | std::unique_ptr ssis = std::make_unique< ShadingSystemInterfaceSimple>(); 81 | shading_system.register_shadingsystem_interface(std::move(ssis)); 82 | 83 | // register all closure types 84 | g_lambert_closure_id = ClosureTypeLambert::RegisterClosure(); 85 | g_random_closure_id = ClosureTypeRandom0::RegisterClosure(); 86 | g_bxdf_with_double_id = ClosureTypeBxdfWithDouble::RegisterClosure(); 87 | g_microfacete_id = ClosureTypeMicrofacet::RegisterClosure(); 88 | g_layered_bxdf_id = ClosureTypeLayeredBxdf::RegisterClosure(); 89 | g_lambert_in_sort_id = ClosureTypeLambertInSORT::RegisterClosure(); 90 | g_measured_brdf_id = ClosureTypeMeasuredBrdf::RegisterClosure(); 91 | 92 | ::testing::InitGoogleTest(&argc, argv); 93 | return RUN_ALL_TESTS(); 94 | } -------------------------------------------------------------------------------- /src/tsl_test/test/array.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include "test_common.h" 19 | 20 | TEST(Array, Initializer) { 21 | auto shader_source = R"( 22 | shader function_name(out float var){ 23 | float a[2] = { 1.0f, 5.0f }; 24 | var = a[1]; 25 | } 26 | )"; 27 | 28 | auto ret = compile_shader(shader_source); 29 | auto func_ptr = ret.first; 30 | 31 | float data = 0.0f; 32 | func_ptr(&data); 33 | EXPECT_EQ(5.0f, data); 34 | } 35 | 36 | TEST(Array, GlobalArray) { 37 | auto shader_source = R"( 38 | float a[2] = { 1.0f, 5.0f }; 39 | shader function_name(out float var){ 40 | var = a[1]; 41 | } 42 | )"; 43 | 44 | auto ret = compile_shader(shader_source); 45 | auto func_ptr = ret.first; 46 | 47 | float data = 0.0f; 48 | func_ptr(&data); 49 | EXPECT_EQ(5.0f, data); 50 | } 51 | -------------------------------------------------------------------------------- /src/tsl_test/test/basic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include "test_common.h" 19 | 20 | TEST(Basic, SingleFloatOutput) { 21 | auto shader_source = R"( 22 | int k = 5; 23 | shader function_name(out float var){ 24 | var = (float)k; 25 | } 26 | )"; 27 | 28 | auto ret = compile_shader(shader_source); 29 | auto func_ptr = ret.first; 30 | 31 | float data = 0.0f; 32 | func_ptr(&data); 33 | EXPECT_EQ(5.0f, data); 34 | } 35 | 36 | TEST(Basic, MathOps) { 37 | auto shader_source = R"( 38 | shader function_name(int a, int b, out int o0, out int o1, out int o2, out int o3, out int o4){ 39 | o0 = a + b; 40 | o1 = a - b; 41 | o2 = a * b; 42 | o3 = a / b; 43 | o4 = a % b; 44 | } 45 | )"; 46 | 47 | auto ret = compile_shader(shader_source); 48 | auto func_ptr = ret.first; 49 | 50 | auto verify_func = [&](int a, int b) { 51 | int o0, o1, o2, o3, o4; 52 | func_ptr(a, b, &o0, &o1, &o2, &o3, &o4); 53 | EXPECT_EQ(a + b, o0); 54 | EXPECT_EQ(a - b, o1); 55 | EXPECT_EQ(a * b, o2); 56 | EXPECT_EQ(a / b, o3); 57 | EXPECT_EQ(a % b, o4); 58 | }; 59 | 60 | verify_func(1, 1); 61 | verify_func(23, 12); 62 | verify_func(0, 1024); 63 | verify_func(1, 213); 64 | } 65 | 66 | TEST(Basic, Inc_Dec) { 67 | auto shader_source = R"( 68 | shader function_name(int a, out int o0, out int o1, out int o2, 69 | out int o3, out int o4, out int o5, out int o6, out int o7){ 70 | int b = a; 71 | o0 = b++; 72 | o4 = b; 73 | b = a; 74 | o1 = ++b; 75 | o5 = b; 76 | b = a; 77 | o2 = b--; 78 | o6 = b; 79 | b = a; 80 | o3 = --b; 81 | o7 = b; 82 | } 83 | )"; 84 | 85 | auto ret = compile_shader(shader_source); 86 | auto func_ptr = ret.first; 87 | 88 | auto verify_func = [&](int a) { 89 | int o0, o1, o2, o3, o4, o5, o6, o7; 90 | func_ptr(a, &o0, &o1, &o2, &o3, &o4, &o5, &o6, &o7); 91 | EXPECT_EQ(a , o0); 92 | EXPECT_EQ(a + 1, o1); 93 | EXPECT_EQ(a , o2); 94 | EXPECT_EQ(a - 1, o3); 95 | EXPECT_EQ(a + 1, o4); 96 | EXPECT_EQ(a + 1, o5); 97 | EXPECT_EQ(a - 1, o6); 98 | EXPECT_EQ(a - 1, o7); 99 | }; 100 | 101 | verify_func(1); 102 | verify_func(23); 103 | verify_func(0); 104 | 105 | // make sure it has the same overflow behavior as c++ code. 106 | verify_func(std::numeric_limits::min()); 107 | verify_func(std::numeric_limits::max()); 108 | } 109 | 110 | TEST(Basic, And_Or_Xor) { 111 | auto shader_source = R"( 112 | shader function_name(int a, int b, out int o0, out int o1, out int o2){ 113 | o0 = a & b; 114 | o1 = a | b; 115 | o2 = a ^ b; 116 | } 117 | )"; 118 | 119 | auto ret = compile_shader(shader_source); 120 | auto func_ptr = ret.first; 121 | 122 | auto verify_func = [&](int a, int b) { 123 | int o0, o1, o2; 124 | func_ptr(a, b, &o0, &o1, &o2); 125 | EXPECT_EQ(a & b, o0); 126 | EXPECT_EQ(a | b, o1); 127 | EXPECT_EQ(a ^ b, o2); 128 | }; 129 | 130 | verify_func(1, 12); 131 | verify_func(23, 0x3232); 132 | verify_func(0, 0xffffffff); 133 | 134 | // make sure it has the same overflow behavior as c++ code. 135 | verify_func(std::numeric_limits::min(), 12); 136 | verify_func(std::numeric_limits::max(), 12); 137 | } 138 | 139 | TEST(Basic, ArrayAccess) { 140 | auto shader_source = R"( 141 | shader function_name(int a, int b, out int o0){ 142 | int arr[10]; 143 | arr[9] = a + b; 144 | o0 = arr[9]; 145 | } 146 | )"; 147 | 148 | auto ret = compile_shader(shader_source); 149 | auto func_ptr = ret.first; 150 | 151 | auto verify_func = [&](int a, int b) { 152 | int o0; 153 | func_ptr(a, b, &o0); 154 | EXPECT_EQ(a + b, o0); 155 | }; 156 | 157 | verify_func(1, 12); 158 | verify_func(23, 0x3232); 159 | verify_func(0, 0xffffffff); 160 | 161 | // make sure it has the same overflow behavior as c++ code. 162 | verify_func(std::numeric_limits::min(), 12); 163 | verify_func(std::numeric_limits::max(), 12); 164 | } 165 | 166 | TEST(Basic, VariableLifeTime) { 167 | auto shader_source = R"( 168 | shader function_name(int a, out int o0, out int o1){ 169 | { 170 | int a = 123; 171 | o0 = 123; 172 | } 173 | o1 = a; 174 | } 175 | )"; 176 | 177 | auto ret = compile_shader(shader_source); 178 | auto func_ptr = ret.first; 179 | 180 | auto verify_func = [&](int a, int b) { 181 | int o0, o1; 182 | func_ptr(a, &o0, &o1); 183 | EXPECT_EQ(123, o0); 184 | EXPECT_EQ(a, o1); 185 | }; 186 | 187 | verify_func(1, 12); 188 | verify_func(23, 0x3232); 189 | verify_func(0, 0xffffffff); 190 | 191 | // make sure it has the same overflow behavior as c++ code. 192 | verify_func(std::numeric_limits::min(), 12); 193 | verify_func(std::numeric_limits::max(), 12); 194 | } 195 | 196 | TEST(Basic, InvalidVariableLifeTime0) { 197 | validate_shader(R"( 198 | shader function_name(int a, out int o0, out int o1){ 199 | { 200 | int k = 0; 201 | } 202 | o1 = 0; 203 | } 204 | )"); 205 | } 206 | 207 | TEST(Basic, InvalidVariableLifeTime1) { 208 | validate_shader(R"( 209 | shader function_name(int a, out int o0, out int o1){ 210 | if( a ) 211 | int k = 0; 212 | o1 = 0; 213 | } 214 | )"); 215 | } 216 | 217 | TEST(Basic, InvalidVariableLifeTime2) { 218 | validate_shader(R"( 219 | shader function_name(int a, out int o0, out int o1){ 220 | while( a ) 221 | int k = 0; 222 | o1 = 0; 223 | } 224 | )"); 225 | } 226 | 227 | TEST(Basic, InvalidVariableLifeTime3) { 228 | validate_shader(R"( 229 | shader function_name(int a, out int o0, out int o1){ 230 | do 231 | int k = 0; 232 | while( k ); 233 | 234 | o1 = 0; 235 | } 236 | )"); 237 | } -------------------------------------------------------------------------------- /src/tsl_test/test/callback.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include "test_common.h" 20 | 21 | #ifdef _WIN32 22 | #define DLLEXPORT __declspec(dllexport) 23 | #else 24 | #define DLLEXPORT 25 | #endif 26 | 27 | extern "C" DLLEXPORT float custom_square(float x) { 28 | return x * x; 29 | } 30 | 31 | TEST(CallbackFunction, Basic_Callback) { 32 | auto shader_source = R"( 33 | float custom_square(float x); 34 | 35 | shader function_name( float arg0 , out float data ){ 36 | data = custom_square(arg0); 37 | } 38 | )"; 39 | 40 | auto ret = compile_shader(shader_source); 41 | auto func_ptr = ret.first; 42 | 43 | float arg0 = 2.0f , test_value = 1.0f; 44 | func_ptr(arg0, &test_value); 45 | EXPECT_EQ(test_value, 4.0f); 46 | } 47 | 48 | TEST(CallbackFunction, System_Callback0) { 49 | auto shader_source = R"( 50 | double cos(double x); 51 | 52 | shader function_name( double arg0 , out double data ){ 53 | data = cos(arg0); 54 | } 55 | )"; 56 | 57 | auto ret = compile_shader(shader_source); 58 | auto func_ptr = ret.first; 59 | 60 | double arg0 = 2.0, test_value = 1.0; 61 | func_ptr(arg0, &test_value); 62 | EXPECT_EQ(test_value, cos(arg0)); 63 | } 64 | 65 | TEST(CallbackFunction, System_Callback1) { 66 | auto shader_source = R"( 67 | float cosf( float base ); 68 | float powf( float base , float exp ); 69 | 70 | shader function_name( float arg0 , out float data ){ 71 | data = powf( cosf(arg0) , 2.0f ); 72 | } 73 | )"; 74 | 75 | auto ret = compile_shader(shader_source); 76 | auto func_ptr = ret.first; 77 | 78 | float arg0 = 2.0, test_value = 1.0; 79 | func_ptr(arg0, &test_value); 80 | EXPECT_EQ(test_value, powf( cosf(arg0) , 2.0f )); 81 | } 82 | 83 | TEST(CallbackFunction, Complex_Callback) { 84 | auto shader_source = R"( 85 | float custom_square(float x); 86 | 87 | shader function_name( float arg0 , out float data ){ 88 | float local = 1.0; 89 | float a = arg0 / local; 90 | float b = (custom_square(custom_square(a)) + local) * (arg0 + 3.0); 91 | data = custom_square(b+local); 92 | data = data * 2.0; 93 | } 94 | )"; 95 | 96 | auto referenced_func = [](float arg0) { 97 | float local = 1.0; 98 | float a = arg0 / local; 99 | float b = (custom_square(custom_square(a)) + local) * (arg0 + 3.0f); 100 | float data = custom_square(b + local); 101 | return data * 2.0f; 102 | }; 103 | 104 | auto ret = compile_shader(shader_source); 105 | auto func_ptr = ret.first; 106 | 107 | float arg0 = 2.0, test_value = 1.0; 108 | func_ptr(arg0, &test_value); 109 | EXPECT_EQ(test_value, referenced_func(arg0)); 110 | } -------------------------------------------------------------------------------- /src/tsl_test/test/closures.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include "test_common.h" 21 | #include "tsl_args.h" 22 | 23 | 24 | TEST(Closure, ClosureMake) { 25 | auto& shading_system = ShadingSystem::get_instance(); 26 | 27 | auto shader_source = R"( 28 | shader closure_make(out closure o0){ 29 | o0 = make_closure( 11 , 2.0 ); 30 | } 31 | )"; 32 | 33 | Tsl_Namespace::ClosureTreeNodeBase* root = nullptr; 34 | auto ret = compile_shader(shader_source); 35 | auto func_ptr = ret.first; 36 | func_ptr(&root); 37 | 38 | auto lambert_param = (ClosureTypeLambert*)root->m_params; 39 | EXPECT_VALID_RAW_PTR(root); 40 | EXPECT_EQ(root->m_id, g_lambert_closure_id); 41 | EXPECT_VALID_RAW_PTR(root->m_params); 42 | EXPECT_EQ(lambert_param->base_color, 11); 43 | EXPECT_EQ(lambert_param->normal, 2.0f); 44 | } 45 | 46 | TEST(Closure, ClosureMakeWithFloat3) { 47 | auto& shading_system = ShadingSystem::get_instance(); 48 | 49 | auto shader_source = R"( 50 | shader closure_make(out closure o0){ 51 | color diffuse = color( 1.0f, 2.0f, 3.0f ); 52 | o0 = make_closure( diffuse ); 53 | } 54 | )"; 55 | 56 | Tsl_Namespace::ClosureTreeNodeBase* root = nullptr; 57 | auto ret = compile_shader(shader_source); 58 | auto func_ptr = ret.first; 59 | func_ptr(&root); 60 | 61 | auto random_param = (ClosureTypeRandom0*)root->m_params; 62 | EXPECT_VALID_RAW_PTR(root); 63 | EXPECT_EQ(g_random_closure_id, root->m_id); 64 | EXPECT_VALID_RAW_PTR(root->m_params); 65 | EXPECT_EQ(random_param->roughness.x, 1.0f); 66 | EXPECT_EQ(random_param->roughness.y, 2.0f); 67 | EXPECT_EQ(random_param->roughness.z, 3.0f); 68 | } 69 | 70 | // this needs to wait for TSL to support double literal and type conversion later. 71 | TEST(Closure, ClosureMakeWithDouble) { 72 | auto shader_source = R"( 73 | shader closure_make(out closure o0){ 74 | o0 = make_closure( 11.0d , 2.0f ); 75 | } 76 | )"; 77 | 78 | Tsl_Namespace::ClosureTreeNodeBase* root = nullptr; 79 | auto ret = compile_shader(shader_source); 80 | auto func_ptr = ret.first; 81 | func_ptr(&root); 82 | 83 | auto bxdf_double_param = (ClosureTypeBxdfWithDouble*)root->m_params; 84 | EXPECT_VALID_RAW_PTR(root); 85 | EXPECT_EQ(g_bxdf_with_double_id, root->m_id); 86 | EXPECT_VALID_RAW_PTR(root->m_params); 87 | EXPECT_EQ(bxdf_double_param->roughness, 11.0); 88 | EXPECT_EQ(bxdf_double_param->specular, 2.0f); 89 | } 90 | 91 | TEST(Closure, ClosureMul) { 92 | auto shader_source = R"( 93 | shader closure_mul(out closure o0){ 94 | o0 = 3.0f * make_closure( 11 , 2.0 ); 95 | } 96 | )"; 97 | 98 | Tsl_Namespace::ClosureTreeNodeMul* root = nullptr; 99 | auto ret = compile_shader(shader_source); 100 | auto func_ptr = ret.first; 101 | func_ptr(&root); 102 | 103 | // auto lambert_param = (ClosureTypeLambert*)root->m_params; 104 | EXPECT_VALID_RAW_PTR(root); 105 | EXPECT_EQ(root->m_id, CLOSURE_MUL); 106 | EXPECT_VALID_RAW_PTR(root->m_closure); 107 | EXPECT_VALID_RAW_PTR(root->m_closure->m_params); 108 | EXPECT_EQ(root->m_closure->m_id, g_lambert_closure_id); 109 | auto lambert_param = (ClosureTypeLambert*)root->m_closure->m_params; 110 | EXPECT_EQ(lambert_param->base_color, 11); 111 | EXPECT_EQ(lambert_param->normal, 2.0f); 112 | } 113 | 114 | TEST(Closure, ClosureAdd) { 115 | auto shader_source = R"( 116 | shader closure_add(out closure o0){ 117 | o0 = make_closure( 13 , 4.0 ) + make_closure( 123.0 , 5.0 ); 118 | } 119 | )"; 120 | 121 | Tsl_Namespace::ClosureTreeNodeAdd* root = nullptr; 122 | auto ret = compile_shader(shader_source); 123 | auto func_ptr = ret.first; 124 | func_ptr(&root); 125 | 126 | EXPECT_VALID_RAW_PTR(root); 127 | EXPECT_EQ(root->m_id, CLOSURE_ADD); 128 | EXPECT_VALID_RAW_PTR(root->m_closure0); 129 | EXPECT_EQ(root->m_closure0->m_id, g_lambert_closure_id); 130 | EXPECT_VALID_RAW_PTR(root->m_closure0->m_params); 131 | auto closure0 = (ClosureTypeLambert*)root->m_closure0->m_params; 132 | EXPECT_EQ(closure0->base_color, 13); 133 | EXPECT_EQ(closure0->normal, 4.0f); 134 | 135 | EXPECT_VALID_RAW_PTR(root->m_closure1); 136 | EXPECT_EQ(root->m_closure1->m_id, g_microfacete_id); 137 | EXPECT_VALID_RAW_PTR(root->m_closure1->m_params); 138 | auto closure1 = (ClosureTypeMicrofacet*)root->m_closure1->m_params; 139 | EXPECT_EQ(closure1->roughness, 123.0f); 140 | EXPECT_EQ(closure1->specular, 5.0f); 141 | } 142 | 143 | TEST(Closure, ClosureComplex) { 144 | auto& shading_system = ShadingSystem::get_instance(); 145 | 146 | auto shader_source = R"( 147 | shader closure_add(out closure o0){ 148 | o0 = ( 0.3 * make_closure( 13 , 4.0 ) + make_closure( 123.0 , 5.0 ) ) * 0.5; 149 | } 150 | )"; 151 | 152 | Tsl_Namespace::ClosureTreeNodeMul* root = nullptr; 153 | auto ret = compile_shader(shader_source); 154 | auto func_ptr = ret.first; 155 | func_ptr(&root); 156 | 157 | EXPECT_VALID_RAW_PTR(root); 158 | EXPECT_EQ(root->m_id, CLOSURE_MUL); 159 | EXPECT_VALID_RAW_PTR(root->m_closure); 160 | auto closure = root->m_closure; 161 | EXPECT_EQ(closure->m_id, CLOSURE_ADD); 162 | auto closure_add = (ClosureTreeNodeAdd*)closure; 163 | EXPECT_VALID_RAW_PTR(closure_add->m_closure0); 164 | EXPECT_VALID_RAW_PTR(closure_add->m_closure1); 165 | 166 | EXPECT_EQ(closure_add->m_closure0->m_id, CLOSURE_MUL); 167 | auto closure_lambert_mul = (ClosureTreeNodeMul*)closure_add->m_closure0; 168 | EXPECT_EQ(closure_lambert_mul->m_weight, 0.3f); 169 | EXPECT_VALID_RAW_PTR(closure_lambert_mul->m_closure); 170 | EXPECT_VALID_RAW_PTR(closure_lambert_mul->m_closure); 171 | EXPECT_EQ(closure_lambert_mul->m_closure->m_id, g_lambert_closure_id); 172 | EXPECT_VALID_RAW_PTR(closure_lambert_mul->m_closure->m_params); 173 | auto lambert_param = (ClosureTypeLambert*)closure_lambert_mul->m_closure->m_params; 174 | EXPECT_EQ(lambert_param->base_color, 13); 175 | EXPECT_EQ(lambert_param->normal, 4.0f); 176 | 177 | EXPECT_EQ(closure_add->m_closure1->m_id, g_microfacete_id); 178 | auto microfacet_param = (ClosureTypeMicrofacet*)closure_add->m_closure1->m_params; 179 | EXPECT_EQ(microfacet_param->roughness, 123.0f); 180 | EXPECT_EQ(microfacet_param->specular, 5.0f); 181 | } 182 | 183 | TEST(Closure, ClosureAsOtherClosureInput) { 184 | auto& shading_system = ShadingSystem::get_instance(); 185 | 186 | auto shader_source = R"( 187 | shader closure_add(out closure o0){ 188 | closure bottom = make_closure( 123.0 , 5.0 ); 189 | o0 = make_closure( 1233.0 , 4.0 , bottom ); 190 | } 191 | )"; 192 | 193 | Tsl_Namespace::ClosureTreeNodeBase* root = nullptr; 194 | auto ret = compile_shader(shader_source); 195 | auto func_ptr = ret.first; 196 | func_ptr(&root); 197 | 198 | EXPECT_VALID_RAW_PTR(root); 199 | EXPECT_EQ(root->m_id, g_layered_bxdf_id); 200 | EXPECT_VALID_RAW_PTR(root->m_params); 201 | 202 | ClosureTypeLayeredBxdf* layered_bxdf_params = (ClosureTypeLayeredBxdf*)root->m_params; 203 | EXPECT_EQ(layered_bxdf_params->roughness, 1233.0); 204 | EXPECT_EQ(layered_bxdf_params->specular, 4.0); 205 | 206 | ClosureTreeNodeBase* bottom_bxdf = (ClosureTreeNodeBase*)layered_bxdf_params->closure; 207 | EXPECT_EQ(bottom_bxdf->m_id, g_microfacete_id); 208 | ClosureTypeMicrofacet* mf_bxdf = (ClosureTypeMicrofacet*)bottom_bxdf->m_params; 209 | 210 | EXPECT_EQ(mf_bxdf->roughness, 123.0f); 211 | EXPECT_EQ(mf_bxdf->specular, 5.0f); 212 | } -------------------------------------------------------------------------------- /src/tsl_test/test/comments.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include "test_common.h" 19 | 20 | TEST(Comments, Full_Test){ 21 | validate_shader(R"( 22 | /* 23 | this is some random comments. 24 | */ 25 | shader /* I'm everywhere! */ function_name( /* just giv eit a try */ ) 26 | { 27 | // /* this should be ignored. 28 | //* this should be valid 29 | 30 | // This is an ugly line that is full of comments, but it is a valid one. 31 | /* start from here */ int /* I'm here. */ k /* I'm also here. */ = /* Here again. */ 123 /* again */; 32 | 33 | int kk = 43; // this should be fine too. 34 | } 35 | 36 | /* I'm not a blocker. // */ 37 | 38 | /* /* This is valid. */ 39 | )"); 40 | } 41 | 42 | TEST(Comments, Invalid_Comment0){ 43 | validate_shader(R"( 44 | shader function_name(){ 45 | /*/ 46 | } 47 | )", false); 48 | } 49 | 50 | TEST(Comments, Invalid_Comment1) { 51 | validate_shader(R"( 52 | shader function_name(){ 53 | /* this is right for now. */ this is so wrong! */ 54 | } 55 | )", false); 56 | } 57 | 58 | TEST(Comments, Invalid_Comment2) { 59 | validate_shader(R"( 60 | shader function_name( // ){ 61 | } 62 | )", false); 63 | } 64 | 65 | TEST(Comments, Invalid_Comment3) { 66 | validate_shader(R"( 67 | shader functio/*this should be treated as an error*/n_name(){ 68 | } 69 | )", false); 70 | } 71 | 72 | TEST(Comments, Invalid_Comment4) { 73 | validate_shader(R"( 74 | shader function_name(){ 75 | 76 | /* // */ this is not correct. 77 | } 78 | )", false); 79 | } -------------------------------------------------------------------------------- /src/tsl_test/test/empty.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include "test_common.h" 19 | 20 | // empty shader should also be valid 21 | TEST(EmptyShader, Full_Test) { 22 | validate_shader(R"()"); 23 | } 24 | 25 | TEST(EmptyShader, Comment_Only) { 26 | validate_shader(R"( 27 | // this is an empty shader 28 | )"); 29 | } 30 | 31 | TEST(EmptyShader, Multiline_Comment_Only) { 32 | validate_shader(R"( 33 | /* 34 | It is still an empty shader. 35 | */ 36 | )"); 37 | } -------------------------------------------------------------------------------- /src/tsl_test/test/expression.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include "test_common.h" 19 | 20 | TEST(Expression, Simple_Test) { 21 | validate_shader(R"( 22 | shader func(){ 23 | int k = 234234; 24 | } 25 | )"); 26 | } 27 | 28 | TEST(Expression, MathOperation) { 29 | validate_shader(R"( 30 | shader func(){ 31 | int a = 23; 32 | int k = a + 2; 33 | int k2 = k - a; 34 | int g = k * k; 35 | int w = k / k; 36 | } 37 | )"); 38 | } 39 | 40 | /* 41 | TEST(Expression, Compound_Expression) { 42 | validate_shader(R"( 43 | shader func(){ 44 | int g = ( 1 + 2 , 34 ); 45 | } 46 | )"); 47 | } 48 | TEST(Expression, Recursive_Compound_Expression) { 49 | validate_shader(R"( 50 | shader func(){ 51 | int g = ( 1 + 2 , ( 34 + k ) ); 52 | } 53 | )"); 54 | } 55 | */ 56 | 57 | TEST(Expression, Type_Cast) { 58 | validate_shader(R"( 59 | shader func(){ 60 | // int g = (int) 23.0; 61 | // float k = (float) 2; 62 | } 63 | )"); 64 | 65 | auto shader_source = R"( 66 | int k = 5; 67 | int floor( float x ){ 68 | return (int)x; 69 | } 70 | shader function_name(out float var, out int var1){ 71 | var = (float)k + 0.5f; 72 | var1 = floor(var); 73 | } 74 | )"; 75 | 76 | auto ret = compile_shader(shader_source); 77 | auto func_ptr = ret.first; 78 | 79 | float data = 0.0f; 80 | int data1 = 0; 81 | func_ptr(&data, &data1); 82 | EXPECT_EQ(5.5f, data); 83 | EXPECT_EQ(5, data1); 84 | } -------------------------------------------------------------------------------- /src/tsl_test/test/functions.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include "test_common.h" 19 | 20 | TEST(Functions, Default_Shader) { 21 | validate_shader(R"( 22 | shader func(){ 23 | } 24 | )"); 25 | } 26 | 27 | TEST(Functions, Non_Shader) { 28 | validate_shader(R"( 29 | void none_shader_func(){} 30 | )"); 31 | } 32 | 33 | TEST(Functions, Mixed_Shader) { 34 | validate_shader(R"( 35 | int none_shader_func111(){ 36 | return 3; 37 | } 38 | 39 | shader shader_func() 40 | { 41 | {} 42 | } 43 | 44 | float non_shader_func222(){ 45 | return 1.0; 46 | } 47 | )"); 48 | } 49 | 50 | TEST(Functions, Single_Argument) { 51 | validate_shader(R"( 52 | int none_shader_func( int k ) 53 | { 54 | } 55 | )"); 56 | } 57 | 58 | TEST(Functions, Multi_Arguments) { 59 | validate_shader(R"( 60 | int none_shader_func( int arg0 , float arg1 , int arg2 , int arg3 ) 61 | { 62 | } 63 | )"); 64 | } 65 | 66 | TEST(Functions, Single_Argument_With_Defaults) { 67 | validate_shader(R"( 68 | int none_shader_func( float arg0 = 0.0 ) 69 | { 70 | } 71 | )"); 72 | } 73 | 74 | TEST(Functions, Multi_Argument_With_Defaults) { 75 | validate_shader(R"( 76 | // unlike C, there is no function overloading in TSL 77 | // default value can go to any argument, instead of just the last ones 78 | void none_shader_func( float arg0 = 0.0 , float arg1 , int arg2 = 0.0 , int arg3 ) 79 | { 80 | } 81 | )"); 82 | } 83 | 84 | TEST(Functions, Multi_Argument_With_Defaults_Multi_Line) { 85 | validate_shader(R"( 86 | // unlike C, there is no function overloading in TSL 87 | // default value can go to any argument, instead of just the last ones 88 | void none_shader_func( float arg0 = 0.0 , 89 | float arg1 , 90 | int arg2 = 0.0 , 91 | int arg3 ){ 92 | } 93 | )"); 94 | } 95 | 96 | TEST(Functions, Shader_Single_Argument) { 97 | validate_shader(R"( 98 | shader shader_func( float arg0 ){ 99 | return; 100 | } 101 | )"); 102 | } 103 | 104 | TEST(Functions, Shader_Single_Argument_With_Metadata ) { 105 | validate_shader(R"( 106 | shader shader_func( float arg0 <<< >>> ){ 107 | } 108 | )"); 109 | } 110 | 111 | TEST(Functions, Shader_Single_Argument_With_Metadata_and_Default ) { 112 | validate_shader(R"( 113 | shader shader_func( float arg0 = 0.0 <<< >>> ){ 114 | } 115 | )"); 116 | } 117 | 118 | TEST(Functions, Shader_Multi_Arguments_With_Metadata_and_Default ) { 119 | validate_shader(R"( 120 | shader shader_func( float arg0 = 0.0 <<< >>>, 121 | int arg1 = 0 <<< >>> , 122 | int arg2 = 2 <<<>>> , 123 | int arg3 = 1 ){ 124 | } 125 | )"); 126 | } 127 | 128 | TEST(Functions, Non_Shader_Func_With_Return ) { 129 | validate_shader(R"( 130 | void generic_func( float arg0 = 0.0 ){ 131 | } 132 | 133 | int generic_func2( float arg0 = 0.0 ){ 134 | return a + generic_func( arg0 ); 135 | } 136 | )"); 137 | } 138 | 139 | TEST(Functions, Call_Function_No_Arg ) { 140 | validate_shader(R"( 141 | void generic_func( float arg0 = 0.0 ){ 142 | } 143 | 144 | int generic_func2( float arg0 = 0.0 ){ 145 | generic_func(); 146 | 147 | return 2 + 12; 148 | } 149 | )"); 150 | } 151 | 152 | TEST(Functions, Call_Function_Single_Arg ) { 153 | validate_shader(R"( 154 | void generic_func( float arg0 = 0.0 , int k = 0.0 ){ 155 | } 156 | 157 | int generic_func2( float arg0 = 0.0 ){ 158 | int arg0 = 0; 159 | 160 | // fix me 161 | generic_func( arg0 = 0 ); 162 | 163 | return generic_func2(); 164 | } 165 | )"); 166 | } 167 | 168 | TEST(Functions, Call_Function_Multi_Args ) { 169 | validate_shader(R"( 170 | int generic_func2(){ 171 | int k = 0; 172 | 173 | generic_func( arg0 , gg = 0 ); 174 | 175 | return k = 2; 176 | } 177 | )"); 178 | } 179 | 180 | TEST(Functions, Function_As_Argument ) { 181 | validate_shader(R"( 182 | int generic_func2(){ 183 | int k = 0; 184 | 185 | generic_func( func( arg0 = 0 , arg1 = 0 ) , k ); 186 | 187 | return 2; 188 | } 189 | )"); 190 | } 191 | 192 | TEST(Functions, Config_Decorator ) { 193 | validate_shader(R"( 194 | shader main( int arg0 = 232 , 195 | const int arg1 = 2, 196 | in const float arg2 = 3.0, 197 | // const in matrix mat, 198 | in float input_arg = 0.2 <<< >>> , 199 | out int last_arg = 2.0 <<< >>> ){ 200 | arg2 = input_arg + 2.0; 201 | 202 | last_arg = arg0 + arg1; 203 | } 204 | )"); 205 | } 206 | 207 | TEST(Functions, Simple_Test) { 208 | validate_shader(R"( 209 | shader main( out float arg2 ){ 210 | int k = 0; 211 | 212 | while( k < 100 ) 213 | { 214 | k = k + 1; 215 | } 216 | 217 | arg2 = k == 100 ? 122.0 : 22.0; 218 | } 219 | )"); 220 | } 221 | 222 | TEST(Functions, Single_Return) { 223 | validate_shader(R"( 224 | shader main(int arg0 = 0, 225 | int arg1 = 2, 226 | int arg2 = 3, 227 | int arg3 = 4, 228 | int arg4 = 5){ 229 | int a = ( ( arg0 + arg1 ) * arg2 + arg3 / arg4 ) & arg0; 230 | return; 231 | } 232 | )"); 233 | } 234 | 235 | TEST(Functions, Call_AnotherFunction) { 236 | validate_shader(R"( 237 | int helper_func( int k ){ 238 | return k * k; 239 | } 240 | 241 | shader main(int arg0 = 0, 242 | out int arg2 = 5){ 243 | arg2 = helper_func( arg0 ); 244 | } 245 | )"); 246 | } -------------------------------------------------------------------------------- /src/tsl_test/test/logic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include "test_common.h" 19 | 20 | TEST(Logic, Basic_Test) { 21 | auto shader_source = R"( 22 | shader function_name( int arg0 , out float data ){ 23 | if( arg0 ) 24 | data = 3.0; 25 | else 26 | data = 2.0; 27 | } 28 | )"; 29 | 30 | auto ret = compile_shader(shader_source); 31 | auto func_ptr = ret.first; 32 | 33 | float test_value = 1.0f; 34 | func_ptr(2, &test_value); 35 | EXPECT_EQ(test_value, 3.0f); 36 | 37 | func_ptr(0, &test_value); 38 | EXPECT_EQ(test_value, 2.0f); 39 | } 40 | 41 | TEST(Logic, Ternary_Operation) { 42 | auto shader_source = R"( 43 | shader func(int a, int b, int c, out int o0 , out int o1){ 44 | o0 = ( a ) ? b : c; 45 | o1 = ( o0 < 100 ) ? c : 12; 46 | } 47 | )"; 48 | 49 | auto ret = compile_shader(shader_source); 50 | auto func_ptr = ret.first; 51 | 52 | int a = 12, b = 32, c = 0, o0 = 0, o1 = 0; 53 | func_ptr(a, b, c, &o0, &o1); 54 | EXPECT_EQ(o0, 32); 55 | EXPECT_EQ(o1, 0); 56 | } 57 | 58 | TEST(Logic, Logic_And) { 59 | auto shader_source = R"( 60 | shader func(int a, int b, int c, out int o0 , out int o1){ 61 | if( a && c ){ 62 | o0 = a * b; 63 | }else if( 0 ){ 64 | o0 = 12; 65 | }else 66 | o0 = ( a + b ) / b; 67 | 68 | o1 = ( a && c ) ? a * b : 12; 69 | } 70 | )"; 71 | 72 | auto ret = compile_shader(shader_source); 73 | auto func_ptr = ret.first; 74 | 75 | int a = 12, b = 32, c = 0, o0 = 0, o1 = 0; 76 | func_ptr(a, b, c, &o0, &o1); 77 | EXPECT_EQ(o0, (a + b) / b); 78 | EXPECT_EQ(o1, 12); 79 | } 80 | 81 | TEST(Logic, While_Loop) { 82 | auto shader_source = R"( 83 | shader main( int cnt, out int arg2 ){ 84 | int k = cnt; 85 | int g = 0; 86 | while( k && --k ){ 87 | if( k % 3 == 1 ) 88 | g = g + 1; 89 | } 90 | 91 | arg2 = g; 92 | } 93 | )"; 94 | 95 | auto ret = compile_shader(shader_source); 96 | auto func_ptr = ret.first; 97 | 98 | int o1 = 0; 99 | func_ptr(100, &o1); 100 | EXPECT_EQ(o1, 99 / 3); 101 | 102 | func_ptr(0, &o1); 103 | EXPECT_EQ(o1, 0); 104 | } 105 | 106 | TEST(Logic, Do_While_Loop) { 107 | auto shader_source = R"( 108 | shader main( int cnt , out int arg2 ){ 109 | int k = 1; 110 | int g = 0; 111 | do{ 112 | if( k % 3 == 1 ) 113 | g = g + 1; 114 | k = k + 1; 115 | }while( k < cnt ); 116 | 117 | arg2 = g; 118 | } 119 | )"; 120 | 121 | auto ret = compile_shader(shader_source); 122 | auto func_ptr = ret.first; 123 | 124 | int o1 = 0; 125 | func_ptr(100, &o1); 126 | EXPECT_EQ(o1, 99 / 3); 127 | 128 | func_ptr(1, &o1); 129 | EXPECT_EQ(o1, 1); 130 | } 131 | 132 | TEST(Logic, For_Loop) { 133 | auto shader_source = R"( 134 | shader main( int cnt , out int arg2 ){ 135 | int k = 1; 136 | int g = 0; 137 | for(; k < cnt ; ++k ){ 138 | if( k % 3 == 1 ) 139 | g = g + 1; 140 | } 141 | 142 | arg2 = g; 143 | } 144 | )"; 145 | 146 | auto ret = compile_shader(shader_source); 147 | auto func_ptr = ret.first; 148 | 149 | int o1 = 0; 150 | func_ptr(100, &o1); 151 | EXPECT_EQ(o1, 99 / 3); 152 | 153 | func_ptr(1, &o1); 154 | EXPECT_EQ(o1, 0); 155 | } 156 | 157 | TEST(Logic, While_Break_Continue) { 158 | auto shader_source = R"( 159 | shader main( int cnt , out int arg2 ){ 160 | int k = 1; 161 | int g = 0; 162 | while( k < cnt ){ 163 | if( k % 3 == 0 ){ 164 | k = k + 1; 165 | continue; 166 | } 167 | 168 | g = g + 1; 169 | if( k > 20 ) 170 | break; 171 | k = k + 1; 172 | } 173 | 174 | arg2 = g; 175 | } 176 | )"; 177 | 178 | auto ret = compile_shader(shader_source); 179 | auto func_ptr = ret.first; 180 | 181 | int o1 = 0; 182 | func_ptr(100, &o1); 183 | EXPECT_EQ(15, o1); 184 | 185 | func_ptr(1, &o1); 186 | EXPECT_EQ(0, o1); 187 | } 188 | 189 | TEST(Logic, DoWhile_Break_Continue) { 190 | auto shader_source = R"( 191 | shader main( int cnt , out int arg2 ){ 192 | int k = 1; 193 | int g = 0; 194 | do{ 195 | if( k % 3 == 0 ){ 196 | k = k + 1; 197 | continue; 198 | } 199 | 200 | g = g + 1; 201 | if( k > 20 ) 202 | break; 203 | k = k + 1; 204 | }while( k < cnt ); 205 | 206 | arg2 = g; 207 | } 208 | )"; 209 | 210 | auto ret = compile_shader(shader_source); 211 | auto func_ptr = ret.first; 212 | 213 | int o1 = 0; 214 | func_ptr(100, &o1); 215 | EXPECT_EQ(15, o1); 216 | 217 | func_ptr(1, &o1); 218 | EXPECT_EQ(1, o1); 219 | } 220 | 221 | TEST(Logic, For_Break_Continue) { 222 | auto shader_source = R"( 223 | shader main( int cnt , out int arg2 ){ 224 | int g = 0; 225 | int kk = 0; 226 | for( int k = 1 ; k < cnt ; ++k ){ 227 | if( k % 3 == 0 ){ 228 | continue; 229 | } 230 | 231 | g = g + 1; 232 | if( k > 20 ) 233 | break; 234 | } 235 | arg2 = g; 236 | } 237 | )"; 238 | 239 | auto ret = compile_shader(shader_source); 240 | auto func_ptr = ret.first; 241 | 242 | int o1 = 0; 243 | func_ptr(100, &o1); 244 | EXPECT_EQ(15, o1); 245 | 246 | func_ptr(1, &o1); 247 | EXPECT_EQ(0, o1); 248 | } -------------------------------------------------------------------------------- /src/tsl_test/test/multi_thread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | #include "test_common.h" 21 | 22 | // LLVM is not properly configured to support multi-thread now 23 | TEST(Thread, Full_Test) { 24 | // thread number, this should be large enough to make sure it fails if the compiler is not thread safe. 25 | constexpr int TN = 16; 26 | 27 | auto& shading_system = ShadingSystem::get_instance(); 28 | 29 | try { 30 | // Unlike other unit test, this one can cause crash if it is not thread safe. 31 | std::vector threads(TN); 32 | for (int i = 0; i < TN; ++i) 33 | threads[i] = std::thread([&](int tid) { 34 | int k = 0; 35 | while (k++ < 100) { 36 | char name_buffer[256] = { 0 }; 37 | name_buffer[0] = 'a' + tid; 38 | auto shading_context = shading_system.make_shading_context(); 39 | auto shader_unit = compile_shader_unit_template(shading_context.get(), name_buffer, 40 | R"( 41 | shader func(){ 42 | int flag = 1; 43 | int flag2 = 3; 44 | if( flag ){ 45 | if( flag2 ) 46 | flag = 0; 47 | int test = 0; 48 | } 49 | 50 | if( !flag ){ 51 | }else 52 | 53 | { 54 | int k = 0; 55 | } 56 | } 57 | )"); 58 | 59 | EXPECT_VALID_SMART_PTR(shader_unit); 60 | 61 | auto shader_instance = shader_unit->make_shader_instance(); 62 | EXPECT_VALID_SMART_PTR(shader_instance); 63 | } 64 | }, i); 65 | 66 | // making sure all threads are done 67 | std::for_each(threads.begin(), threads.end(), [](std::thread& thread) { thread.join(); }); 68 | } 69 | catch (...) 70 | { 71 | // make sure it fails 72 | EXPECT_EQ(0, 1); 73 | } 74 | } -------------------------------------------------------------------------------- /src/tsl_test/test/numbers.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include "test_common.h" 19 | 20 | TEST(Numbers, Float_Numbers) { 21 | validate_shader(R"( 22 | shader func(){ 23 | float t = (float)1; 24 | t = .0; 25 | t = 2.; 26 | t = -43.3e3; 27 | t = +3.e1; 28 | t = -.0e-2; 29 | t = 0.e0; 30 | t = .1e+0; 31 | t = 1.e-0; 32 | } 33 | )"); 34 | } 35 | 36 | TEST(Numbers, Invalid_Float0 ) { 37 | validate_shader(R"( 38 | shader func(){ 39 | int t = .e0; 40 | } 41 | )", false); 42 | } 43 | 44 | TEST(Numbers, Invalid_Float1 ) { 45 | validate_shader(R"( 46 | shader func(){ 47 | int t = .1e; 48 | } 49 | )", false); 50 | } 51 | 52 | TEST(Numbers, Integer) { 53 | validate_shader(R"( 54 | shader func(){ 55 | int t = 0; // zero number 56 | t = -0; // negative zero ? 57 | t = -1132; // nagative number 58 | t = +23323; // positive number 59 | t = 0xaaf; // hex number 60 | t = -0xaaf; // this is actually a combination of a negate sign and a hex number 61 | t = +0xa9932; 62 | } 63 | )"); 64 | } 65 | 66 | TEST(Numbers, Number_Expression) { 67 | validate_shader(R"( 68 | shader func(){ 69 | 2; 70 | .45; 71 | } 72 | )"); 73 | } -------------------------------------------------------------------------------- /src/tsl_test/test/output.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include "test_common.h" 19 | 20 | TEST(VerifyOutput, Basic_Output) { 21 | auto shader_source = R"( 22 | shader function_name( out float data ){ 23 | data = 2.0; 24 | } 25 | )"; 26 | 27 | auto ret = compile_shader(shader_source); 28 | auto func_ptr = ret.first; 29 | 30 | float test_value = 1.0f; 31 | func_ptr(&test_value); 32 | EXPECT_EQ(test_value, 2.0f); 33 | } 34 | 35 | TEST(VerifyOutput, Complex_Output) { 36 | auto shader_source = R"( 37 | shader function_name( float arg0 , float arg1 , float arg2 , out float oarg0 , out float oarg1 ){ 38 | oarg0 = ( arg0 + arg1 ) * arg2; 39 | oarg1 = ( arg0 - arg1 ) / arg2 * oarg0; 40 | } 41 | )"; 42 | 43 | auto ret = compile_shader(shader_source); 44 | auto func_ptr = ret.first; 45 | 46 | float arg0 = 2.0f, arg1 = 3.0f, arg2 = 0.5f; 47 | float oarg0 = 0.0f, oarg1 = 0.0f; 48 | func_ptr(arg0, arg1, arg2, &oarg0, &oarg1); 49 | EXPECT_EQ(oarg0, (arg0 + arg1) * arg2); 50 | EXPECT_EQ(oarg1, (arg0 - arg1) / arg2 * oarg0); 51 | } -------------------------------------------------------------------------------- /src/tsl_test/test/shader_resource.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include "test_common.h" 19 | 20 | namespace { 21 | DECLARE_TSLGLOBAL_BEGIN(AnotherTslGlobal) 22 | DECLARE_TSLGLOBAL_VAR(Tsl_float3, basecolor) 23 | DECLARE_TSLGLOBAL_END() 24 | 25 | IMPLEMENT_TSLGLOBAL_BEGIN(AnotherTslGlobal) 26 | IMPLEMENT_TSLGLOBAL_VAR(Tsl_float3, basecolor) 27 | IMPLEMENT_TSLGLOBAL_END() 28 | } 29 | 30 | TEST(ShaderResource, SimpleTexture) { 31 | auto shader_source = R"( 32 | texture2d g_diffuse; 33 | shader function_name(out color diffuse){ 34 | color base_color = global_value; 35 | diffuse = texture2d_sample( base_color.r , 2.0f ); 36 | } 37 | )"; 38 | 39 | // tsl global data 40 | AnotherTslGlobal tsl_global; 41 | tsl_global.basecolor = make_float3(123.0f); 42 | 43 | // the texture handle 44 | TextureSimple texture_simple; 45 | 46 | // the tsl shading system 47 | auto& shading_system = ShadingSystem::get_instance(); 48 | 49 | // make a shader context 50 | auto shading_context = shading_system.make_shading_context(); 51 | 52 | // compile the shader 53 | const auto shader_unit_template = shading_context->begin_shader_unit_template("texture_handle_shader"); 54 | 55 | // register the texture handle 56 | shader_unit_template->register_shader_resource("g_diffuse", (const ShaderResourceHandle*)&texture_simple); 57 | 58 | // register tsl_global 59 | shader_unit_template->register_tsl_global(tsl_global.m_var_list); 60 | 61 | // compile the shader unit 62 | shader_unit_template->compile_shader_source(shader_source); 63 | 64 | // shader unit done. 65 | shading_context->end_shader_unit_template(shader_unit_template.get()); 66 | 67 | // make a shader instance after the template is ready 68 | auto shader_instance = shader_unit_template->make_shader_instance(); 69 | EXPECT_VALID_SMART_PTR(shader_instance); 70 | 71 | // resolve the shader instance 72 | const auto resolve_ret = shader_instance->resolve_shader_instance(); 73 | EXPECT_EQ(Tsl_Namespace::TSL_Resolving_Status::TSL_Resolving_Succeed, resolve_ret); 74 | 75 | // get the raw function pointer for execution 76 | auto func_ptr = (void(*)(float3*, AnotherTslGlobal*))shader_instance->get_function(); 77 | EXPECT_VALID_RAW_PTR(func_ptr); 78 | 79 | float3 data; 80 | func_ptr(&data, &tsl_global); 81 | EXPECT_EQ(123.0f, data.x); 82 | EXPECT_EQ(2.0f, data.y); 83 | EXPECT_EQ(1234.0f, data.z); 84 | } 85 | 86 | TEST(ShaderResource, SimpleTextureAlpha) { 87 | auto shader_source = R"( 88 | texture2d g_diffuse; 89 | shader function_name(out float diffuse){ 90 | color base_color = global_value; 91 | diffuse = texture2d_sample_alpha( base_color.r , 2.0f ); 92 | } 93 | )"; 94 | 95 | // tsl global data 96 | AnotherTslGlobal tsl_global; 97 | tsl_global.basecolor = make_float3(123.0f); 98 | 99 | // the texture handle 100 | TextureSimple texture_simple; 101 | 102 | // the tsl shading system 103 | auto& shading_system = ShadingSystem::get_instance(); 104 | 105 | // make a shader context 106 | auto shading_context = shading_system.make_shading_context(); 107 | 108 | // compile the shader 109 | const auto shader_unit_template = shading_context->begin_shader_unit_template("texture_handle_alpha"); 110 | 111 | // register the texture handle 112 | shader_unit_template->register_shader_resource("g_diffuse", (const ShaderResourceHandle *)&texture_simple); 113 | 114 | // register tsl_global 115 | shader_unit_template->register_tsl_global(tsl_global.m_var_list); 116 | 117 | // compile the shader unit 118 | shader_unit_template->compile_shader_source(shader_source); 119 | 120 | // shader unit done. 121 | shading_context->end_shader_unit_template(shader_unit_template.get()); 122 | 123 | // make a shader instance after the template is ready 124 | auto shader_instance = shader_unit_template->make_shader_instance(); 125 | EXPECT_VALID_SMART_PTR(shader_instance); 126 | 127 | // resolve the shader instance 128 | const auto resolve_ret = shader_instance->resolve_shader_instance(); 129 | EXPECT_EQ(Tsl_Namespace::TSL_Resolving_Status::TSL_Resolving_Succeed, resolve_ret); 130 | 131 | // get the raw function pointer for execution 132 | auto func_ptr = (void(*)(float*, AnotherTslGlobal*))shader_instance->get_function(); 133 | EXPECT_VALID_RAW_PTR(func_ptr); 134 | 135 | float data; 136 | func_ptr(&data, &tsl_global); 137 | EXPECT_EQ(123.0f, data); 138 | } 139 | 140 | class CustomShaderResource : public ShaderResourceHandle { 141 | public: 142 | // just for verification purpose 143 | const int m_signature = 0x12345678; 144 | }; 145 | 146 | TEST(ShaderResource, CustomShaderResource) { 147 | auto shader_source = R"( 148 | shader_resource custom_data; 149 | shader function_name(out closure diffuse){ 150 | diffuse = make_closure( 123 , custom_data ); 151 | } 152 | )"; 153 | 154 | // the texture handle 155 | CustomShaderResource custom_data; 156 | 157 | // the tsl shading system 158 | auto& shading_system = ShadingSystem::get_instance(); 159 | 160 | // make a shader context 161 | auto shading_context = shading_system.make_shading_context(); 162 | 163 | // compile the shader 164 | const auto shader_unit_template = shading_context->begin_shader_unit_template("custom_reousrce_shader"); 165 | EXPECT_VALID_SMART_PTR(shader_unit_template); 166 | 167 | // register the texture handle 168 | shader_unit_template->register_shader_resource("custom_data", &custom_data); 169 | 170 | // compile the shader unit 171 | shader_unit_template->compile_shader_source(shader_source); 172 | 173 | // shader unit done. 174 | shading_context->end_shader_unit_template(shader_unit_template.get()); 175 | 176 | // make a shader instance after the template is ready 177 | auto shader_instance = shader_unit_template->make_shader_instance(); 178 | EXPECT_VALID_SMART_PTR(shader_instance); 179 | 180 | // resolve the shader instance 181 | const auto resolve_ret = shader_instance->resolve_shader_instance(); 182 | EXPECT_EQ(Tsl_Namespace::TSL_Resolving_Status::TSL_Resolving_Succeed, resolve_ret); 183 | 184 | // get the raw function pointer for execution 185 | auto func_ptr = (void(*)(Tsl_Namespace::ClosureTreeNodeBase**))shader_instance->get_function(); 186 | EXPECT_VALID_RAW_PTR(func_ptr); 187 | 188 | Tsl_Namespace::ClosureTreeNodeBase* closure = nullptr; 189 | func_ptr(&closure); 190 | 191 | EXPECT_EQ(g_measured_brdf_id, closure->m_id); 192 | const ClosureTypeMeasuredBrdf* param = (const ClosureTypeMeasuredBrdf*)closure->m_params; 193 | EXPECT_EQ(123, param->signature); 194 | 195 | auto handle = (const CustomShaderResource*)param->custom_data; 196 | EXPECT_EQ(&custom_data, handle); 197 | EXPECT_EQ(0x12345678, handle->m_signature); 198 | } -------------------------------------------------------------------------------- /src/tsl_test/test/struct.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include "test_common.h" 19 | 20 | TEST(Struct, StructureDefine) { 21 | validate_shader(R"( 22 | struct vec3 { 23 | float x; 24 | float y; 25 | float z; 26 | }; 27 | 28 | shader func(){ 29 | struct vec3 light_dir; 30 | light_dir.x = 2.0; 31 | } 32 | )"); 33 | } 34 | 35 | TEST(Struct, StructureDefineRecusive) { 36 | const auto shader_source = R"( 37 | struct vec2 { 38 | float x; 39 | float y; 40 | }; 41 | 42 | struct vec3 { 43 | struct vec2 xy; 44 | float z; 45 | }; 46 | 47 | struct vec2 test(){ 48 | struct vec2 t; 49 | t.y = 1233.0; 50 | t.x = 0.0; 51 | return t; 52 | } 53 | 54 | void helper( out struct vec2 v ){ 55 | v = test(); 56 | } 57 | 58 | shader func( out struct vec3 light_dir ){ 59 | light_dir.z = 123.0; 60 | helper( light_dir.xy ); 61 | light_dir.xy.x = 111.0; 62 | } 63 | )"; 64 | 65 | struct vec2 { 66 | float x, y; 67 | }; 68 | struct vec3 { 69 | vec2 xy; 70 | float z; 71 | }; 72 | auto ret = compile_shader(shader_source); 73 | auto func_ptr = ret.first; 74 | 75 | vec3 v; 76 | func_ptr(&v); 77 | EXPECT_EQ(111.0f, v.xy.x); 78 | EXPECT_EQ(1233.0f, v.xy.y); 79 | EXPECT_EQ(123.0f, v.z); 80 | } 81 | 82 | TEST(Struct, StructureAsArgument) { 83 | const auto shader_source = R"( 84 | struct vec2 { 85 | float x; 86 | float y; 87 | }; 88 | 89 | struct vec3 { 90 | struct vec2 xy; 91 | float z; 92 | }; 93 | 94 | void internal_helper( out struct vec2 output ){ 95 | output.y = 123.0; 96 | } 97 | 98 | shader func( out struct vec2 output ){ 99 | output.x = 3123.0; 100 | internal_helper( output ); 101 | } 102 | )"; 103 | 104 | struct vec2{ 105 | float x, y; 106 | }; 107 | auto ret = compile_shader(shader_source); 108 | auto func_ptr = ret.first; 109 | 110 | vec2 v; 111 | func_ptr(&v); 112 | EXPECT_EQ(3123.0f, v.x); 113 | EXPECT_EQ(123.0f, v.y); 114 | } 115 | 116 | TEST(Struct, IntrinsicDataStructure) { 117 | const auto shader_source = R"( 118 | shader func( out vector output ){ 119 | output.x = 3123.0; 120 | output.g = 12.0; 121 | output.z = 23.0; 122 | } 123 | )"; 124 | 125 | struct float3 { 126 | float x, y, z; 127 | }; 128 | auto ret = compile_shader(shader_source); 129 | auto func_ptr = ret.first; 130 | 131 | float3 v; 132 | func_ptr(&v); 133 | EXPECT_EQ(3123.0f, v.x); 134 | EXPECT_EQ(12.0f, v.y); 135 | EXPECT_EQ(23.0f, v.z); 136 | } -------------------------------------------------------------------------------- /src/tsl_test/test/system.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include "gtest/gtest.h" 19 | #include "tsl_system.h" 20 | #include "test_common.h" 21 | 22 | USE_TSL_NAMESPACE 23 | 24 | TEST(TSL, Basic) { 25 | // allocate a shading context 26 | std::shared_ptr sc = ShadingSystem::get_instance().make_shading_context(); 27 | 28 | // make sure the context is allocated. 29 | EXPECT_VALID_SMART_PTR(sc); 30 | } -------------------------------------------------------------------------------- /src/tsl_test/test/test_common.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include "test_common.h" 19 | 20 | IMPLEMENT_CLOSURE_TYPE_BEGIN(ClosureTypeLambert) 21 | IMPLEMENT_CLOSURE_TYPE_VAR(ClosureTypeLambert, Tsl_int, base_color) 22 | IMPLEMENT_CLOSURE_TYPE_VAR(ClosureTypeLambert, Tsl_float, normal) 23 | IMPLEMENT_CLOSURE_TYPE_END(ClosureTypeLambert) 24 | 25 | IMPLEMENT_CLOSURE_TYPE_BEGIN(ClosureTypeMicrofacet) 26 | IMPLEMENT_CLOSURE_TYPE_VAR(ClosureTypeMicrofacet, Tsl_float, roughness) 27 | IMPLEMENT_CLOSURE_TYPE_VAR(ClosureTypeMicrofacet, Tsl_float, specular) 28 | IMPLEMENT_CLOSURE_TYPE_END(ClosureTypeMicrofacet) 29 | 30 | IMPLEMENT_CLOSURE_TYPE_BEGIN(ClosureTypeLayeredBxdf) 31 | IMPLEMENT_CLOSURE_TYPE_VAR(ClosureTypeLayeredBxdf, Tsl_float, roughness) 32 | IMPLEMENT_CLOSURE_TYPE_VAR(ClosureTypeLayeredBxdf, Tsl_float, specular) 33 | IMPLEMENT_CLOSURE_TYPE_VAR(ClosureTypeLayeredBxdf, Tsl_closure, closure) 34 | IMPLEMENT_CLOSURE_TYPE_END(ClosureTypeLayeredBxdf) 35 | 36 | IMPLEMENT_CLOSURE_TYPE_BEGIN(ClosureTypeRandom0) 37 | IMPLEMENT_CLOSURE_TYPE_VAR(ClosureTypeRandom0, Tsl_float3, roughness) 38 | IMPLEMENT_CLOSURE_TYPE_END(ClosureTypeRandom0) 39 | 40 | IMPLEMENT_CLOSURE_TYPE_BEGIN(ClosureTypeBxdfWithDouble) 41 | IMPLEMENT_CLOSURE_TYPE_VAR(ClosureTypeBxdfWithDouble, Tsl_double, roughness) 42 | IMPLEMENT_CLOSURE_TYPE_VAR(ClosureTypeBxdfWithDouble, Tsl_float, specular) 43 | IMPLEMENT_CLOSURE_TYPE_END(ClosureTypeBxdfWithDouble) 44 | 45 | IMPLEMENT_CLOSURE_TYPE_BEGIN(ClosureTypeLambertInSORT) 46 | IMPLEMENT_CLOSURE_TYPE_VAR(ClosureTypeLambertInSORT, Tsl_float3, base_color) 47 | IMPLEMENT_CLOSURE_TYPE_VAR(ClosureTypeLambertInSORT, Tsl_float3, normal) 48 | IMPLEMENT_CLOSURE_TYPE_END(ClosureTypeLambertInSORT) 49 | 50 | IMPLEMENT_CLOSURE_TYPE_BEGIN(ClosureTypeMeasuredBrdf) 51 | IMPLEMENT_CLOSURE_TYPE_VAR(ClosureTypeMeasuredBrdf, Tsl_int, signature) 52 | IMPLEMENT_CLOSURE_TYPE_VAR(ClosureTypeMeasuredBrdf, Tsl_resource, custom_data) 53 | IMPLEMENT_CLOSURE_TYPE_END(ClosureTypeMeasuredBrdf) 54 | 55 | int g_name_counter = 0; -------------------------------------------------------------------------------- /src/tsl_test/test/test_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | #include "gtest/gtest.h" 24 | #include "tsl_system.h" 25 | #include "tsl_args.h" 26 | 27 | #define EXPECT_VALID_SMART_PTR(p) EXPECT_VALID_RAW_PTR(p.get()) 28 | #define EXPECT_VALID_RAW_PTR(p) EXPECT_NE((void*)NULL, (void*)p) 29 | 30 | USE_TSL_NAMESPACE 31 | 32 | DECLARE_CLOSURE_TYPE_BEGIN(ClosureTypeLambert, "lambert") 33 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeLambert, Tsl_int, base_color) 34 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeLambert, Tsl_float, normal) 35 | DECLARE_CLOSURE_TYPE_END(ClosureTypeLambert) 36 | 37 | DECLARE_CLOSURE_TYPE_BEGIN(ClosureTypeMicrofacet, "microfacet") 38 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeMicrofacet, Tsl_float, roughness) 39 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeMicrofacet, Tsl_float, specular) 40 | DECLARE_CLOSURE_TYPE_END(ClosureTypeMicrofacet) 41 | 42 | DECLARE_CLOSURE_TYPE_BEGIN(ClosureTypeRandom0, "random0") 43 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeRandom0, Tsl_float3, roughness) 44 | DECLARE_CLOSURE_TYPE_END(ClosureTypeRandom0) 45 | 46 | DECLARE_CLOSURE_TYPE_BEGIN(ClosureTypeLayeredBxdf, "layered_bxdf") 47 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeLayeredBxdf, Tsl_float, roughness) 48 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeLayeredBxdf, Tsl_float, specular) 49 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeLayeredBxdf, Tsl_closure, closure) 50 | DECLARE_CLOSURE_TYPE_END(ClosureTypeLayeredBxdf) 51 | 52 | DECLARE_CLOSURE_TYPE_BEGIN(ClosureTypeBxdfWithDouble, "bxdf_with_double") 53 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeBxdfWithDouble, Tsl_double, roughness) 54 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeBxdfWithDouble, Tsl_float, specular) 55 | DECLARE_CLOSURE_TYPE_END(ClosureTypeBxdfWithDouble) 56 | 57 | DECLARE_CLOSURE_TYPE_BEGIN(ClosureTypeLambertInSORT, "lambert_in_sort") 58 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeLambertInSORT, Tsl_float3, base_color) 59 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeLambertInSORT, Tsl_float3, normal) 60 | DECLARE_CLOSURE_TYPE_END(ClosureTypeLambertInSORT) 61 | 62 | DECLARE_CLOSURE_TYPE_BEGIN(ClosureTypeMeasuredBrdf, "measured_brdf") 63 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeMeasuredBrdf, Tsl_int, signature) 64 | DECLARE_CLOSURE_TYPE_VAR(ClosureTypeMeasuredBrdf, Tsl_resource, custom_data) 65 | DECLARE_CLOSURE_TYPE_END(ClosureTypeMeasuredBrdf) 66 | 67 | extern int g_name_counter; 68 | 69 | extern ClosureID g_lambert_closure_id; 70 | extern ClosureID g_random_closure_id; 71 | extern ClosureID g_bxdf_with_double_id; 72 | extern ClosureID g_microfacete_id; 73 | extern ClosureID g_layered_bxdf_id; 74 | extern ClosureID g_lambert_in_sort_id; 75 | extern ClosureID g_measured_brdf_id; 76 | 77 | class TextureSimple { 78 | public: 79 | float3 sample2d(float u, float v) const { 80 | return make_float3(u, v, 1234.0f); 81 | } 82 | 83 | float sample_alpha_2d(float u, float v) const { 84 | return u; 85 | } 86 | }; 87 | 88 | inline std::shared_ptr compile_shader_unit_template(ShadingContext* shading_context, const char* name, const char* shader_source) { 89 | const auto shader_unit_template = shading_context->begin_shader_unit_template(name); 90 | const auto ret = shader_unit_template->compile_shader_source(shader_source); 91 | shading_context->end_shader_unit_template(shader_unit_template.get()); 92 | return ret && shader_unit_template ? shader_unit_template : nullptr; 93 | } 94 | 95 | template 96 | inline std::shared_ptr compile_shader_unit_template(ShadingContext* shading_context, const char* name, const char* shader_source) { 97 | const auto shader_unit_template = shading_context->begin_shader_unit_template(name); 98 | 99 | // register tsl shader global 100 | TG::shader_unit_register(shader_unit_template.get()); 101 | const auto ret = shader_unit_template->compile_shader_source(shader_source); 102 | shading_context->end_shader_unit_template(shader_unit_template.get()); 103 | return ret && shader_unit_template ? shader_unit_template : nullptr; 104 | } 105 | 106 | inline void validate_shader(const char* shader_source, bool valid = true, TslCompiler* compiler = nullptr) { 107 | auto shading_context = ShadingSystem::get_instance().make_shading_context(); 108 | 109 | const auto name = std::to_string(g_name_counter++); 110 | const auto shader_unit = compile_shader_unit_template(shading_context.get(), name.c_str(), shader_source); 111 | const auto ret = shader_unit != nullptr; 112 | 113 | EXPECT_EQ(ret, valid); 114 | } 115 | 116 | template 117 | inline std::pair> compile_shader(const char* shader_source) { 118 | auto shading_context = ShadingSystem::get_instance().make_shading_context(); 119 | 120 | // this name is meanless, but I just want something unique 121 | const auto name = std::to_string(g_name_counter++); 122 | const auto shader_unit_template = compile_shader_unit_template(shading_context.get(), name.c_str(), shader_source); 123 | 124 | if (!shader_unit_template) 125 | return std::make_pair(nullptr, nullptr); 126 | 127 | auto shader_instance = shader_unit_template->make_shader_instance(); 128 | 129 | // resolve the shader before using it. 130 | if(Tsl_Namespace::TSL_Resolving_Status::TSL_Resolving_Succeed != shader_instance->resolve_shader_instance()) 131 | return std::make_pair(nullptr, nullptr); 132 | 133 | return std::make_pair((T)shader_instance->get_function(), shader_instance); 134 | } 135 | 136 | template 137 | inline std::pair> compile_shader(const char* shader_source) { 138 | auto shading_context = ShadingSystem::get_instance().make_shading_context(); 139 | 140 | // this name is meanless, but I just want something unique 141 | const auto name = std::to_string(g_name_counter++); 142 | const auto shader_unit_template = compile_shader_unit_template(shading_context.get(), name.c_str(), shader_source); 143 | 144 | if (!shader_unit_template) 145 | return std::make_pair(nullptr, nullptr); 146 | 147 | auto shader_instance = shader_unit_template->make_shader_instance(); 148 | 149 | // resolve the shader before using it. 150 | if (Tsl_Namespace::TSL_Resolving_Status::TSL_Resolving_Succeed != shader_instance->resolve_shader_instance()) 151 | return std::make_pair(nullptr, nullptr); 152 | 153 | return std::make_pair((T)shader_instance->get_function(), shader_instance); 154 | } -------------------------------------------------------------------------------- /src/tsl_test/test/variables.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is a part of Tiny-Shading-Language or TSL, an open-source cross 3 | platform programming shading language. 4 | 5 | Copyright (c) 2020-2020 by Jiayin Cao - All rights reserved. 6 | 7 | TSL is a free software written for educational purpose. Anyone can distribute 8 | or modify it under the the terms of the GNU General Public License Version 3 as 9 | published by the Free Software Foundation. However, there is NO warranty that 10 | all components are functional in a perfect manner. Without even the implied 11 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along with 15 | this program. If not, see . 16 | */ 17 | 18 | #include "test_common.h" 19 | 20 | TEST(Variables, Full_Test) { 21 | validate_shader(R"( 22 | float k = 0.0f; 23 | float global_array[12] = { 12.0f, 3.0f }; 24 | shader func(){ 25 | int k = 0; 26 | float gg = 0; 27 | float t = 0.0; 28 | float kkk = 0.0; 29 | int k = 0; 30 | float gg = 0; 31 | // CustomData cd; 32 | float ka[12] = { 12.0f, 3.0f }; 33 | 34 | // this is not supported for now 35 | // CustomData cd = CustomData(); 36 | 37 | { 38 | int gG = 0; 39 | { 40 | int g = 0; 41 | } 42 | float kga = 0.0; 43 | } 44 | } 45 | 46 | // not quite sure about whether to allow this, to be decided later. 47 | shader second_func(){ 48 | int _this_should_work = 0; 49 | } 50 | )"); 51 | } 52 | 53 | TEST(Variables, Local_Variables) { 54 | validate_shader(R"( 55 | shader func(){ 56 | int k = 0; 57 | float gg = 0.0; 58 | float t = 0.0; 59 | float kkk = 0.0; 60 | } 61 | )"); 62 | } 63 | 64 | TEST(Variables, Recursive_Variables) { 65 | validate_shader(R"( 66 | shader func(){ 67 | // data.time = 0.0; 68 | // data_array[0].t.da[2] = 2; 69 | } 70 | )"); 71 | } 72 | 73 | TEST(Variables, Inc_or_Dec) { 74 | validate_shader(R"( 75 | shader func(){ 76 | int d = 0; 77 | d++; 78 | --d; 79 | } 80 | )"); 81 | } 82 | 83 | TEST(Variables, Invalid_Inc) { 84 | validate_shader(R"( 85 | shader func(){ 86 | data.time++ = 0; 87 | } 88 | )", false); 89 | } 90 | 91 | TEST(Variables, Invalid_Dec) { 92 | validate_shader(R"( 93 | shader func(){ 94 | --data.time = 0; 95 | } 96 | )", false ); 97 | } --------------------------------------------------------------------------------