├── .clang-format ├── .github └── workflows │ └── cmake.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── cmake ├── ANTLRGrammarUtil.cmake ├── ANTLRGrammarUtil.ps1.in ├── ANTLRGrammarUtil.sh.in ├── Antlr4Package.md ├── ExternalAntlr4Cpp.cmake ├── FindANTLR.cmake ├── FindD3D12.cmake ├── antlr4-generator.cmake.in ├── antlr4-runtime.cmake.in └── glm.cmake ├── external ├── json.hpp └── parallel_hashmap │ ├── btree.h │ ├── conanfile.py │ ├── meminfo.h │ ├── phmap.h │ ├── phmap_base.h │ ├── phmap_bits.h │ ├── phmap_config.h │ ├── phmap_dump.h │ ├── phmap_fwd_decl.h │ └── phmap_utils.h ├── src ├── CMakeLists.txt ├── chameleonrtc │ ├── CMakeLists.txt │ └── chameleonrtc.cpp ├── crtl │ ├── CMakeLists.txt │ ├── compiler │ │ ├── CMakeLists.txt │ │ ├── ast │ │ │ ├── declaration.cpp │ │ │ ├── declaration.h │ │ │ ├── expression.cpp │ │ │ ├── expression.h │ │ │ ├── modifying_visitor.cpp │ │ │ ├── modifying_visitor.h │ │ │ ├── node.cpp │ │ │ ├── node.h │ │ │ ├── statement.cpp │ │ │ ├── statement.h │ │ │ ├── symbol.cpp │ │ │ ├── symbol.h │ │ │ ├── type.cpp │ │ │ ├── type.h │ │ │ ├── visitor.cpp │ │ │ └── visitor.h │ │ ├── ast_builder_visitor.cpp │ │ ├── ast_builder_visitor.h │ │ ├── ast_expr_builder_visitor.cpp │ │ ├── ast_expr_builder_visitor.h │ │ ├── ast_struct_array_access_builder_visitor.cpp │ │ ├── ast_struct_array_access_builder_visitor.h │ │ ├── builtins.cpp │ │ ├── builtins.h │ │ ├── error_listener.cpp │ │ ├── error_listener.h │ │ ├── global_struct_param_expansion_visitor.cpp │ │ ├── global_struct_param_expansion_visitor.h │ │ ├── hlsl │ │ │ ├── crtl_to_hlsl.cpp │ │ │ ├── crtl_to_hlsl.h │ │ │ ├── output_visitor.cpp │ │ │ ├── output_visitor.h │ │ │ ├── parameter_metadata_output_visitor.cpp │ │ │ ├── parameter_metadata_output_visitor.h │ │ │ ├── shader_register_allocator.cpp │ │ │ ├── shader_register_allocator.h │ │ │ ├── shader_register_binding.cpp │ │ │ ├── shader_register_binding.h │ │ │ ├── translate_builtin_function_call.cpp │ │ │ ├── translate_builtin_function_call.h │ │ │ ├── translate_builtin_type.cpp │ │ │ └── translate_builtin_type.h │ │ ├── json_visitor.cpp │ │ ├── json_visitor.h │ │ ├── parameter_transforms.cpp │ │ ├── parameter_transforms.h │ │ ├── rename_entry_point_param_visitor.cpp │ │ ├── rename_entry_point_param_visitor.h │ │ ├── resolver_visitor.cpp │ │ ├── resolver_visitor.h │ │ └── target_api.h │ ├── core │ │ ├── CMakeLists.txt │ │ ├── api_object.h │ │ ├── backend_plugin.cpp │ │ ├── backend_plugin.h │ │ ├── buffer.h │ │ ├── buffer_view.h │ │ ├── crtl_buffer.cpp │ │ ├── crtl_device.cpp │ │ ├── crtl_event.cpp │ │ ├── crtl_geometry.cpp │ │ ├── crtl_parameter_block.cpp │ │ ├── crtl_queue.cpp │ │ ├── crtl_rtpipeline.cpp │ │ ├── crtl_shader.cpp │ │ ├── crtl_texture.cpp │ │ ├── device.cpp │ │ ├── device.h │ │ ├── dxr │ │ │ ├── CMakeLists.txt │ │ │ ├── crtl_dxr.cpp │ │ │ ├── dxr_blas.cpp │ │ │ ├── dxr_blas.h │ │ │ ├── dxr_buffer.cpp │ │ │ ├── dxr_buffer.h │ │ │ ├── dxr_buffer_view.cpp │ │ │ ├── dxr_buffer_view.h │ │ │ ├── dxr_command_allocator.cpp │ │ │ ├── dxr_command_allocator.h │ │ │ ├── dxr_command_buffer.cpp │ │ │ ├── dxr_command_buffer.h │ │ │ ├── dxr_descriptor_heap.cpp │ │ │ ├── dxr_descriptor_heap.h │ │ │ ├── dxr_device.cpp │ │ │ ├── dxr_device.h │ │ │ ├── dxr_enums.cpp │ │ │ ├── dxr_enums.h │ │ │ ├── dxr_event.cpp │ │ │ ├── dxr_event.h │ │ │ ├── dxr_geometry.h │ │ │ ├── dxr_global_parameter_block.cpp │ │ │ ├── dxr_global_parameter_block.h │ │ │ ├── dxr_group.cpp │ │ │ ├── dxr_group.h │ │ │ ├── dxr_instance.cpp │ │ │ ├── dxr_instance.h │ │ │ ├── dxr_parameter_block.cpp │ │ │ ├── dxr_parameter_block.h │ │ │ ├── dxr_queue.cpp │ │ │ ├── dxr_queue.h │ │ │ ├── dxr_renderable.cpp │ │ │ ├── dxr_renderable.h │ │ │ ├── dxr_resource.cpp │ │ │ ├── dxr_resource.h │ │ │ ├── dxr_root_parameter.cpp │ │ │ ├── dxr_root_parameter.h │ │ │ ├── dxr_root_signature.cpp │ │ │ ├── dxr_root_signature.h │ │ │ ├── dxr_rtpipeline.cpp │ │ │ ├── dxr_rtpipeline.h │ │ │ ├── dxr_scene.cpp │ │ │ ├── dxr_scene.h │ │ │ ├── dxr_shader_entry_point.cpp │ │ │ ├── dxr_shader_entry_point.h │ │ │ ├── dxr_shader_library.cpp │ │ │ ├── dxr_shader_library.h │ │ │ ├── dxr_shader_parameter_desc.cpp │ │ │ ├── dxr_shader_parameter_desc.h │ │ │ ├── dxr_shader_record.cpp │ │ │ ├── dxr_shader_record.h │ │ │ ├── dxr_shader_record_parameter_block.cpp │ │ │ ├── dxr_shader_record_parameter_block.h │ │ │ ├── dxr_texture.cpp │ │ │ ├── dxr_texture.h │ │ │ ├── dxr_tlas.cpp │ │ │ ├── dxr_tlas.h │ │ │ ├── dxr_triangle_geometry.cpp │ │ │ ├── dxr_triangle_geometry.h │ │ │ ├── dxr_utils.cpp │ │ │ └── dxr_utils.h │ │ ├── error.cpp │ │ ├── error.h │ │ ├── include │ │ │ └── crtl │ │ │ │ ├── crtl.h │ │ │ │ ├── crtl_buffer.h │ │ │ │ ├── crtl_core.h │ │ │ │ ├── crtl_device.h │ │ │ │ ├── crtl_enums.h │ │ │ │ ├── crtl_event.h │ │ │ │ ├── crtl_geometry.h │ │ │ │ ├── crtl_parameter_block.h │ │ │ │ ├── crtl_queue.h │ │ │ │ ├── crtl_rtpipeline.h │ │ │ │ ├── crtl_shader.h │ │ │ │ └── crtl_texture.h │ │ ├── shader_entry_point.h │ │ ├── shader_library.h │ │ ├── type.cpp │ │ ├── type.h │ │ ├── util.cpp │ │ └── util.h │ └── grammar │ │ ├── CMakeLists.txt │ │ ├── ChameleonRTLexer.g4 │ │ └── ChameleonRTParser.g4 └── renderer │ ├── CMakeLists.txt │ └── main.cpp └── tests ├── sketch.crtl ├── sketch.glsl ├── sketch.hlsl ├── small.crtl └── small.hlsl /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: false 6 | AlignConsecutiveDeclarations: false 7 | AlignEscapedNewlinesLeft: true 8 | AlignOperands: true 9 | AlignTrailingComments: true 10 | AllowAllParametersOfDeclarationOnNextLine: true 11 | AllowShortBlocksOnASingleLine: false 12 | AllowShortCaseLabelsOnASingleLine: false 13 | AllowShortFunctionsOnASingleLine: Empty 14 | AllowShortIfStatementsOnASingleLine: false 15 | AllowShortLoopsOnASingleLine: false 16 | AlwaysBreakAfterDefinitionReturnType: None 17 | AlwaysBreakAfterReturnType: None 18 | AlwaysBreakBeforeMultilineStrings: true 19 | AlwaysBreakTemplateDeclarations: true 20 | BinPackArguments: false 21 | BinPackParameters: false 22 | BraceWrapping: 23 | AfterClass: false 24 | AfterControlStatement: false 25 | AfterEnum: false 26 | AfterFunction: true 27 | AfterNamespace: false 28 | AfterStruct: false 29 | AfterUnion: false 30 | AfterExternBlock: false 31 | BeforeCatch: false 32 | BeforeElse: false 33 | IndentBraces: false 34 | BreakBeforeBinaryOperators: None 35 | BreakBeforeBraces: Custom 36 | BreakBeforeTernaryOperators: true 37 | BreakConstructorInitializersBeforeComma: false 38 | BreakStringLiterals: true 39 | ColumnLimit: 90 40 | CommentPragmas: '^ IWYU pragma:' 41 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 42 | Cpp11BracedListStyle: true 43 | DerivePointerAlignment: false 44 | DisableFormat: false 45 | ExperimentalAutoDetectBinPacking: false 46 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 47 | IncludeCategories: 48 | - Regex: '^<[^\.]*>' 49 | Priority: 1 50 | - Regex: '^<.*\.h>' 51 | Priority: 2 52 | - Regex: '^<.*\.hpp>' 53 | Priority: 2 54 | - Regex: '.*' 55 | Priority: 3 56 | SortIncludes: true 57 | ConstructorInitializerIndentWidth: 4 58 | ContinuationIndentWidth: 4 59 | IndentCaseLabels: false 60 | IndentWidth: 4 61 | IndentWrappedFunctionNames: false 62 | KeepEmptyLinesAtTheStartOfBlocks: false 63 | MacroBlockBegin: '' 64 | MacroBlockEnd: '' 65 | MaxEmptyLinesToKeep: 1 66 | NamespaceIndentation: None 67 | PenaltyBreakBeforeFirstCallParameter: 1 68 | PenaltyBreakComment: 300 69 | PenaltyBreakFirstLessLess: 120 70 | PenaltyBreakString: 1000 71 | PenaltyExcessCharacter: 1000000 72 | PenaltyReturnTypeOnItsOwnLine: 200 73 | PointerAlignment: Right 74 | ReflowComments: true 75 | SpaceAfterCStyleCast: false 76 | SpaceAfterTemplateKeyword: true 77 | SpaceBeforeAssignmentOperators: true 78 | SpaceBeforeParens: ControlStatements 79 | SpaceInEmptyParentheses: false 80 | SpacesBeforeTrailingComments: 2 81 | SpacesInAngles: false 82 | SpacesInContainerLiterals: false 83 | SpacesInCStyleCastParentheses: false 84 | SpacesInParentheses: false 85 | SpacesInSquareBrackets: false 86 | Standard: Cpp11 87 | TabWidth: 4 88 | FixNamespaceComments: false 89 | UseTab: Never 90 | ... 91 | 92 | 93 | -------------------------------------------------------------------------------- /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: CMake 2 | 3 | on: [push] 4 | 5 | env: 6 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 7 | BUILD_TYPE: RelWithDebInfo 8 | ANTLR_VERSION: 4.10.1 9 | 10 | jobs: 11 | build: 12 | strategy: 13 | matrix: 14 | os: [ubuntu-latest, windows-latest, macos-latest] 15 | runs-on: ${{ matrix.os }} 16 | # Share ANTLR4 config for all runners 17 | env: 18 | # Can't seem to use ${{env.ANTLR_VERSION}} here? 19 | CLASSPATH: ${{github.workspace}}/antlr-4.10.1-complete.jar 20 | ANTLR_EXECUTABLE: ${{github.workspace}}/antlr-4.10.1-complete.jar 21 | steps: 22 | - uses: actions/checkout@v2 23 | - uses: actions/setup-java@v2 24 | with: 25 | distribution: 'zulu' 26 | java-version: '15' 27 | 28 | - name: Install wget 29 | if: ${{matrix.os == 'windows-latest'}} 30 | run: choco install wget 31 | 32 | - name: Setup ANTLR4 33 | # Can't seem to use ${{env.ANTLR_VERSION}} here? 34 | working-directory: ${{github.workspace}}/ 35 | run: wget https://www.antlr.org/download/antlr-4.10.1-complete.jar 36 | 37 | - name: Create Build Environment 38 | run: cmake -E make_directory ${{github.workspace}}/build 39 | 40 | - name: Configure CMake 41 | # Use a bash shell so we can use the same syntax for environment variable 42 | # access regardless of the host operating system 43 | shell: bash 44 | working-directory: ${{github.workspace}}/build 45 | run: > 46 | cmake $GITHUB_WORKSPACE 47 | -DCMAKE_BUILD_TYPE=$BUILD_TYPE 48 | -DANTLR_EXECUTABLE=$ANTLR_EXECUTABLE 49 | 50 | - name: Build 51 | working-directory: ${{github.workspace}}/build 52 | shell: bash 53 | run: cmake --build . --config $BUILD_TYPE 54 | 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | *.swp 34 | *.swo 35 | */build/ 36 | */cmake-build/ 37 | compile_commands.json 38 | interpreter/.cache/ 39 | .cache 40 | cmake-build* 41 | .DS_Store 42 | build-linux 43 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | project(chameleonrtlang) 3 | 4 | set(CMAKE_C_STANDARD 99) 5 | set(CMAKE_C_STANDARD_REQUIRED ON) 6 | 7 | set(CMAKE_CXX_STANDARD 20) 8 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 9 | 10 | include(ExternalProject) 11 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 12 | 13 | # Put all build artifacts in the root build directory 14 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 15 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 16 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 17 | 18 | add_subdirectory(src) 19 | 20 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Will Usher 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ChameleonRT Language 2 | 3 | A hobby language and API for cross API and cross platform ray tracing. 4 | 5 | Developed off what I've learned in [ChameleonRT](https://github.com/Twinklebear/ChameleonRT), and what I've wanted to make writing true cross platform ray tracers easier. 6 | 7 | -------------------------------------------------------------------------------- /cmake/ANTLRGrammarUtil.cmake: -------------------------------------------------------------------------------- 1 | find_package(Java QUIET) 2 | if (WIN32) 3 | find_file(ANTLR_GRAMMAR_UTIL_SCRIPT NAME ANTLRGrammarUtil.ps1.in 4 | PATHS 5 | ${CMAKE_MODULE_PATH} 6 | ${CMAKE_CURRENT_LIST_DIR}) 7 | else() 8 | find_file(ANTLR_GRAMMAR_UTIL_SCRIPT NAME ANTLRGrammarUtil.sh.in 9 | PATHS 10 | ${CMAKE_MODULE_PATH} 11 | ${CMAKE_CURRENT_LIST_DIR}) 12 | endif() 13 | 14 | function(antlr_grammar_util) 15 | set(ANTLR_ONE_VALUE_ARGS LEXER PARSER) 16 | cmake_parse_arguments(PARSE_ARGV 1 ANTLR_UTIL 17 | "" 18 | "${ANTLR_ONE_VALUE_ARGS}" 19 | "") 20 | if (NOT ANTLR_UTIL_LEXER OR NOT ANTLR_UTIL_PARSER) 21 | message(FATAL_ERROR "Both the lexer and parser must be provided") 22 | endif() 23 | 24 | get_filename_component(ANTLR_INPUT_LEXER ${ANTLR_UTIL_LEXER} NAME_WE) 25 | get_filename_component(ANTLR_INPUT_PARSER ${ANTLR_UTIL_PARSER} NAME_WE) 26 | set(OUTPUT_DIR 27 | ${CMAKE_CURRENT_BINARY_DIR}/antlr4java_generated_src/${ANTLR_INPUT_PARSER}) 28 | 29 | set(LEXER_JAVA_SRC 30 | ${OUTPUT_DIR}/${ANTLR_INPUT_LEXER}.java) 31 | 32 | set(LEXER_OUTPUTS 33 | ${OUTPUT_DIR}/${ANTLR_INPUT_LEXER}.interp 34 | ${OUTPUT_DIR}/${ANTLR_INPUT_LEXER}.tokens 35 | ${LEXER_JAVA_SRC}) 36 | 37 | add_custom_command( 38 | OUTPUT ${LEXER_OUTPUTS} 39 | COMMAND ${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE} 40 | ${ANTLR_UTIL_LEXER} 41 | -o ${OUTPUT_DIR} 42 | DEPENDS 43 | ${ANTLR_UTIL_LEXER} 44 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 45 | COMMENT "Building util for lexer ${ANTLR_INPUT_LEXER}") 46 | 47 | set(PARSER_JAVA_SRC 48 | ${OUTPUT_DIR}/${ANTLR_INPUT_PARSER}.java) 49 | 50 | set(PARSER_OUTPUTS 51 | ${OUTPUT_DIR}/${ANTLR_INPUT_PARSER}.interp 52 | ${OUTPUT_DIR}/${ANTLR_INPUT_PARSER}.tokens 53 | ${PARSER_JAVA_SRC}) 54 | 55 | add_custom_command( 56 | OUTPUT ${PARSER_OUTPUTS} 57 | COMMAND ${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE} 58 | ${ANTLR_UTIL_PARSER} 59 | -o ${OUTPUT_DIR} 60 | -no-listener 61 | -no-visitor 62 | DEPENDS 63 | ${ANTLR_UTIL_PARSER} 64 | ${LEXER_OUTPUTS} 65 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 66 | COMMENT "Building util for lexer ${ANTLR_INPUT_LEXER}") 67 | 68 | set(JAVA_CLASSES 69 | ${OUTPUT_DIR}/${ANTLR_INPUT_LEXER}.class 70 | ${OUTPUT_DIR}/${ANTLR_INPUT_PARSER}.class) 71 | 72 | add_custom_command( 73 | OUTPUT ${JAVA_CLASSES} 74 | COMMAND ${Java_JAVAC_EXECUTABLE} 75 | -classpath "${OUTPUT_DIR}" 76 | -classpath "${ANTLR_EXECUTABLE}" 77 | ${LEXER_JAVA_SRC} 78 | ${PARSER_JAVA_SRC} 79 | DEPENDS 80 | ${LEXER_JAVA_SRC} ${PARSER_JAVA_SRC} 81 | WORKING_DIRECTORY ${OUTPUT_DIR} 82 | COMMENT "Compiling ${ANTLR_INPUT} Java Files") 83 | 84 | string(REGEX REPLACE "Lexer" "" ANTLR_GRAMMAR_NAME ${ANTLR_INPUT_LEXER}) 85 | if (${ANTLR_GRAMMAR_NAME} STREQUAL ${ANTLR_INPUT_LEXER}) 86 | message(FATAL_ERROR "The lexer must be named Lexer and the parser Parser") 87 | endif() 88 | 89 | if (WIN32) 90 | configure_file(${ANTLR_GRAMMAR_UTIL_SCRIPT} ${CMAKE_CURRENT_BINARY_DIR}/${ARGV0}.ps1 @ONLY) 91 | add_custom_target(${ARGV0} ALL DEPENDS ${JAVA_CLASSES} ${CMAKE_CURRENT_BINARY_DIR}/${ARGV0}.ps1) 92 | else() 93 | configure_file(${ANTLR_GRAMMAR_UTIL_SCRIPT} ${CMAKE_CURRENT_BINARY_DIR}/${ARGV0}.sh @ONLY) 94 | add_custom_target(${ARGV0} ALL DEPENDS ${JAVA_CLASSES} ${CMAKE_CURRENT_BINARY_DIR}/${ARGV0}.sh) 95 | endif() 96 | endfunction() 97 | 98 | -------------------------------------------------------------------------------- /cmake/ANTLRGrammarUtil.ps1.in: -------------------------------------------------------------------------------- 1 | $prev_classpath = $env:CLASSPATH 2 | $env:CLASSPATH = "@OUTPUT_DIR@;@ANTLR_EXECUTABLE@$env:CLASSPATH" 3 | 4 | & "@Java_JAVA_EXECUTABLE@" org.antlr.v4.gui.TestRig @ANTLR_GRAMMAR_NAME@ $Args 5 | 6 | $env:CLASSPATH = $prev_classpath 7 | -------------------------------------------------------------------------------- /cmake/ANTLRGrammarUtil.sh.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export CLASSPATH="@OUTPUT_DIR@:@ANTLR_EXECUTABLE@:$CLASSPATH" 4 | 5 | @Java_JAVA_EXECUTABLE@ org.antlr.v4.gui.TestRig @ANTLR_GRAMMAR_NAME@ $@ 6 | 7 | -------------------------------------------------------------------------------- /cmake/antlr4-runtime.cmake.in: -------------------------------------------------------------------------------- 1 | set(ANTLR_VERSION @ANTLR_VERSION@) 2 | 3 | @PACKAGE_INIT@ 4 | 5 | set_and_check(ANTLR4_INCLUDE_DIR "@PACKAGE_ANTLR4_INCLUDE_DIR@") 6 | set_and_check(ANTLR4_LIB_DIR "@PACKAGE_ANTLR4_LIB_DIR@") 7 | 8 | include(${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake) 9 | 10 | check_required_components(antlr) 11 | -------------------------------------------------------------------------------- /cmake/glm.cmake: -------------------------------------------------------------------------------- 1 | ExternalProject_Add(glm_ext 2 | PREFIX glm 3 | DOWNLOAD_DIR glm 4 | STAMP_DIR glm/stamp 5 | SOURCE_DIR glm/src 6 | BINARY_DIR glm 7 | URL "https://github.com/g-truc/glm/releases/download/0.9.9.8/glm-0.9.9.8.zip" 8 | URL_HASH "SHA256=37e2a3d62ea3322e43593c34bae29f57e3e251ea89f4067506c94043769ade4c" 9 | CONFIGURE_COMMAND "" 10 | BUILD_COMMAND "" 11 | INSTALL_COMMAND "" 12 | BUILD_ALWAYS OFF 13 | ) 14 | 15 | set(GLM_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/glm/src) 16 | 17 | add_library(glm INTERFACE) 18 | 19 | add_dependencies(glm glm_ext) 20 | 21 | target_include_directories(glm INTERFACE 22 | ${GLM_INCLUDE_DIRS}) 23 | 24 | 25 | -------------------------------------------------------------------------------- /external/parallel_hashmap/conanfile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from conans import ConanFile, tools 5 | import os 6 | 7 | class SparseppConan(ConanFile): 8 | name = "parallel_hashmap" 9 | version = "1.27" 10 | description = "A header-only, very fast and memory-friendly hash map" 11 | 12 | # Indicates License type of the packaged library 13 | license = "https://github.com/greg7mdp/parallel-hashmap/blob/master/LICENSE" 14 | 15 | # Packages the license for the conanfile.py 16 | exports = ["LICENSE"] 17 | 18 | # Custom attributes for Bincrafters recipe conventions 19 | source_subfolder = "source_subfolder" 20 | 21 | def source(self): 22 | source_url = "https://github.com/greg7mdp/parallel-hashmap" 23 | tools.get("{0}/archive/{1}.tar.gz".format(source_url, self.version)) 24 | extracted_dir = self.name + "-" + self.version 25 | 26 | #Rename to "source_folder" is a convention to simplify later steps 27 | os.rename(extracted_dir, self.source_subfolder) 28 | 29 | 30 | def package(self): 31 | include_folder = os.path.join(self.source_subfolder, "parallel_hashmap") 32 | self.copy(pattern="LICENSE") 33 | self.copy(pattern="*", dst="include/parallel_hashmap", src=include_folder) 34 | 35 | def package_id(self): 36 | self.info.header_only() 37 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # TODO: Should move these defs to be on specific targets 2 | add_definitions(-DNOMINMAX -DGLM_ENABLE_EXPERIMENTAL -DSDL_MAIN_HANDLED 3 | -DWIN32_LEAN_AND_MEAN) 4 | 5 | if (NOT WIN32) 6 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic") 7 | endif() 8 | 9 | add_subdirectory(crtl) 10 | 11 | option(CHAMELEONRT_LANG_COMPILER "Build the ChameleonRT-Language Offline Compiler" ON) 12 | if (CHAMELEONRT_LANG_COMPILER) 13 | add_subdirectory(chameleonrtc) 14 | endif() 15 | 16 | option(CHAMELEONRT_LANG_RENDERER "Build the ChameleonRT-Language Demo Renderer" OFF) 17 | if (CHAMELEONRT_LANG_RENDERER) 18 | add_subdirectory(renderer) 19 | endif() 20 | 21 | -------------------------------------------------------------------------------- /src/chameleonrtc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(chameleonrtc 2 | chameleonrtc.cpp) 3 | 4 | target_link_libraries(chameleonrtc PUBLIC 5 | crtl_compiler) 6 | 7 | if (WIN32) 8 | target_compile_definitions(chameleonrtc PRIVATE 9 | _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS=1) 10 | endif() 11 | 12 | -------------------------------------------------------------------------------- /src/chameleonrtc/chameleonrtc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "hlsl/crtl_to_hlsl.h" 6 | 7 | const std::string USAGE = 8 | R"(Usage: 9 | ./chameleonrtc [options] 10 | 11 | Options: 12 | -t (hlsl) Set the compilation target. Only HLSL for now 13 | -o Output filename 14 | -m Parameter metadata output filename, used by the ChameleonRT runtime 15 | -h Print this information 16 | )"; 17 | 18 | std::string get_file_content(const std::string &fname) 19 | { 20 | std::ifstream file{fname}; 21 | if (!file.is_open()) { 22 | std::cout << "Failed to open file: " << fname << std::endl; 23 | return ""; 24 | } 25 | return std::string{std::istreambuf_iterator{file}, std::istreambuf_iterator{}}; 26 | } 27 | 28 | int main(int argc, char **argv) 29 | { 30 | const std::vector args(argv + 1, argv + argc); 31 | if (args.empty() || std::find(args.begin(), args.end(), std::string("-h")) != args.end()) { 32 | std::cerr << USAGE << "\n"; 33 | } 34 | 35 | const std::string source_file = args[0]; 36 | std::string output_file; 37 | std::string param_data_output_file; 38 | for (size_t i = 1; i < args.size(); ++i) { 39 | if (args[i] == "-t") { 40 | if (args[++i] != "hlsl") { 41 | std::cout << "Only HLSL is supported right now\n"; 42 | } 43 | } else if (args[i] == "-o") { 44 | output_file = args[++i]; 45 | } else if (args[i] == "-m") { 46 | param_data_output_file = args[++i]; 47 | } else { 48 | std::cerr << "Unhandled argument ;" << args[i] << "'\n"; 49 | } 50 | } 51 | 52 | const std::string shader_text = get_file_content(source_file); 53 | if (shader_text.empty()) { 54 | std::cout << "Failed to read shader or file was empty\n"; 55 | return 1; 56 | } 57 | 58 | auto result = crtl::hlsl::compile_crtl(shader_text); 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /src/crtl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(grammar) 2 | add_subdirectory(compiler) 3 | add_subdirectory(core) 4 | 5 | -------------------------------------------------------------------------------- /src/crtl/compiler/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The device implementations will use GLM, so just build it here at the top level 2 | include(${PROJECT_SOURCE_DIR}/cmake/glm.cmake) 3 | 4 | add_library(crtl_compiler SHARED 5 | ast_builder_visitor.cpp 6 | ast_expr_builder_visitor.cpp 7 | ast_struct_array_access_builder_visitor.cpp 8 | error_listener.cpp 9 | json_visitor.cpp 10 | resolver_visitor.cpp 11 | builtins.cpp 12 | rename_entry_point_param_visitor.cpp 13 | global_struct_param_expansion_visitor.cpp 14 | parameter_transforms.cpp 15 | 16 | ast/node.cpp 17 | ast/symbol.cpp 18 | ast/type.cpp 19 | ast/declaration.cpp 20 | ast/statement.cpp 21 | ast/expression.cpp 22 | ast/visitor.cpp 23 | ast/modifying_visitor.cpp 24 | 25 | hlsl/shader_register_binding.cpp 26 | hlsl/shader_register_allocator.cpp 27 | hlsl/translate_builtin_type.cpp 28 | hlsl/translate_builtin_function_call.cpp 29 | hlsl/output_visitor.cpp 30 | hlsl/parameter_metadata_output_visitor.cpp 31 | hlsl/crtl_to_hlsl.cpp 32 | ) 33 | 34 | target_include_directories(crtl_compiler PUBLIC 35 | ${CMAKE_CURRENT_LIST_DIR} 36 | ${PROJECT_SOURCE_DIR}/external) 37 | 38 | target_link_libraries(crtl_compiler PRIVATE crtl_grammar) 39 | 40 | set_target_properties(crtl_compiler PROPERTIES 41 | WINDOWS_EXPORT_ALL_SYMBOLS ON) 42 | 43 | -------------------------------------------------------------------------------- /src/crtl/compiler/ast/declaration.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "expression.h" 4 | #include "node.h" 5 | #include "symbol.h" 6 | #include "type.h" 7 | 8 | namespace crtl { 9 | namespace ast { 10 | 11 | namespace stmt { 12 | class Block; 13 | } 14 | 15 | namespace decl { 16 | 17 | // A declaration introduces a symbol 18 | class Declaration : public Node { 19 | protected: 20 | std::shared_ptr symbol; 21 | 22 | public: 23 | Declaration(const std::string &name, 24 | antlr4::Token *token, 25 | const std::shared_ptr &type, 26 | NodeType decl_type); 27 | 28 | const std::shared_ptr &get_type() const; 29 | 30 | std::shared_ptr &get_type(); 31 | 32 | const std::shared_ptr &get_symbol() const; 33 | 34 | std::shared_ptr &get_symbol(); 35 | 36 | std::string get_text() const override; 37 | }; 38 | 39 | class Variable : public Declaration { 40 | public: 41 | std::shared_ptr expression; 42 | 43 | Variable(const std::string &name, 44 | antlr4::Token *token, 45 | const std::shared_ptr &type, 46 | const std::shared_ptr &expression = nullptr); 47 | 48 | std::vector> get_children() override; 49 | }; 50 | 51 | class Function : public Declaration { 52 | public: 53 | std::vector> parameters; 54 | std::shared_ptr block; 55 | 56 | // Create a declaration for a user/source code declared function 57 | Function(const std::string &name, 58 | antlr4::Token *token, 59 | const std::vector> ¶meters, 60 | const std::shared_ptr &block, 61 | const std::shared_ptr &return_type); 62 | 63 | // Create a declaration for a built in function 64 | Function(const std::string &name, 65 | const std::vector> ¶meters, 66 | const std::shared_ptr &return_type); 67 | 68 | std::vector> get_children() override; 69 | 70 | // If the function declaration is for a built-in "intrinsic" function, 71 | // or a user-declared function 72 | bool is_builtin() const; 73 | }; 74 | 75 | class EntryPoint : public Declaration { 76 | public: 77 | std::vector> parameters; 78 | std::shared_ptr block; 79 | 80 | EntryPoint(const std::string &name, 81 | antlr4::Token *token, 82 | const std::vector> ¶meters, 83 | const ty::EntryPointType type, 84 | const std::shared_ptr &block); 85 | 86 | std::vector> get_children() override; 87 | }; 88 | 89 | class GlobalParam : public Variable { 90 | public: 91 | GlobalParam(const std::string &name, 92 | antlr4::Token *token, 93 | const std::shared_ptr &type); 94 | 95 | std::vector> get_children() override; 96 | }; 97 | 98 | class StructMember : public Declaration { 99 | public: 100 | StructMember(const std::string &name, 101 | antlr4::Token *token, 102 | const std::shared_ptr &type); 103 | 104 | std::vector> get_children() override; 105 | }; 106 | 107 | class Struct : public Declaration { 108 | public: 109 | std::vector> members; 110 | 111 | Struct(const std::string &name, 112 | antlr4::Token *token, 113 | const std::vector> &members); 114 | 115 | std::shared_ptr get_member(const std::string &name); 116 | 117 | std::vector> get_children() override; 118 | }; 119 | 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/crtl/compiler/ast/node.cpp: -------------------------------------------------------------------------------- 1 | #include "node.h" 2 | 3 | namespace crtl { 4 | namespace ast { 5 | 6 | std::string to_string(const NodeType &nt) 7 | { 8 | switch (nt) { 9 | case NodeType::INVALID: 10 | return "INVALID"; 11 | case NodeType::DECL_FCN: 12 | return "DECL_FCN"; 13 | case NodeType::DECL_ENTRY_POINT: 14 | return "DECL_ENTRY_POINT"; 15 | case NodeType::DECL_GLOBAL_PARAM: 16 | return "DECL_GLOBAL_PARAM"; 17 | case NodeType::DECL_STRUCT: 18 | return "DECL_STRUCT"; 19 | case NodeType::DECL_STRUCT_MEMBER: 20 | return "DECL_STRUCT_MEMBER"; 21 | case NodeType::DECL_VAR: 22 | return "DECL_VAR"; 23 | case NodeType::STMT_BLOCK: 24 | return "STMT_BLOCK"; 25 | case NodeType::STMT_IF_ELSE: 26 | return "STMT_IF_ELSE"; 27 | case NodeType::STMT_WHILE: 28 | return "STMT_WHILE"; 29 | case NodeType::STMT_FOR: 30 | return "STMT_FOR"; 31 | case NodeType::STMT_RETURN: 32 | return "STMT_RETURN"; 33 | case NodeType::STMT_EXPR: 34 | return "STMT_EXPR"; 35 | case NodeType::STMT_VAR_DECL: 36 | return "STMT_VAR_DECL"; 37 | case NodeType::EXPR_NEGATE: 38 | return "EXPR_NEGATE"; 39 | case NodeType::EXPR_LOGIC_NOT: 40 | return "EXPR_LOGIC_NOT"; 41 | case NodeType::EXPR_MULT: 42 | return "EXPR_MULT"; 43 | case NodeType::EXPR_DIV: 44 | return "EXPR_DIV"; 45 | case NodeType::EXPR_ADD: 46 | return "EXPR_ADD"; 47 | case NodeType::EXPR_SUB: 48 | return "EXPR_SUB"; 49 | case NodeType::EXPR_CMP_LESS: 50 | return "EXPR_CMP_LESS"; 51 | case NodeType::EXPR_CMP_LESS_EQUAL: 52 | return "EXPR_CMP_LESS_EQUAL"; 53 | case NodeType::EXPR_CMP_GREATER: 54 | return "EXPR_CMP_GREATER"; 55 | case NodeType::EXPR_CMP_GREATER_EQUAL: 56 | return "EXPR_CMP_GREATER_EQUAL"; 57 | case NodeType::EXPR_CMP_NOT_EQUAL: 58 | return "EXPR_CMP_NOT_EQUAL"; 59 | case NodeType::EXPR_CMP_EQUAL: 60 | return "EXPR_CMP_EQUAL"; 61 | case NodeType::EXPR_LOGIC_AND: 62 | return "EXPR_LOGIC_AND"; 63 | case NodeType::EXPR_LOGIC_OR: 64 | return "EXPR_LOGIC_OR"; 65 | case NodeType::EXPR_LITERAL_VAR: 66 | return "EXPR_LITERAL_VAR"; 67 | case NodeType::EXPR_LITERAL_CONSTANT: 68 | return "EXPR_LITERAL_CONSTANT"; 69 | case NodeType::EXPR_FCN_CALL: 70 | return "EXPR_FCN_CALL"; 71 | case NodeType::EXPR_STRUCT_ARRAY_ACCESS: 72 | return "EXPR_STRUCT_ARRAY_ACCESS"; 73 | case NodeType::EXPR_ASSIGN: 74 | return "EXPR_ASSIGN"; 75 | default: 76 | return "INVALID"; 77 | } 78 | } 79 | 80 | Node::Node(antlr4::Token *token, NodeType type) : token(token), node_type(type) {} 81 | 82 | NodeType Node::get_node_type() const 83 | { 84 | return node_type; 85 | } 86 | 87 | antlr4::Token *Node::get_token() 88 | { 89 | return token; 90 | } 91 | 92 | const antlr4::Token *Node::get_token() const 93 | { 94 | return token; 95 | } 96 | 97 | bool Node::is_generated() const 98 | { 99 | return !token; 100 | } 101 | 102 | std::string Node::get_text() const 103 | { 104 | return token->getText(); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/crtl/compiler/ast/node.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ChameleonRTParser.h" 4 | #include "antlr4-common.h" 5 | #include "json.hpp" 6 | 7 | namespace crtl { 8 | namespace ast { 9 | 10 | enum class NodeType { 11 | INVALID, 12 | 13 | // Declarations 14 | DECL_FCN, 15 | DECL_ENTRY_POINT, 16 | DECL_GLOBAL_PARAM, 17 | DECL_STRUCT, 18 | DECL_STRUCT_MEMBER, 19 | DECL_VAR, 20 | 21 | // Statements 22 | STMT_BLOCK, 23 | STMT_IF_ELSE, 24 | STMT_WHILE, 25 | // TODO: do-while isn't in the lexer/parser 26 | // STMT_DO_WHILE, 27 | STMT_FOR, 28 | STMT_RETURN, 29 | STMT_EXPR, 30 | STMT_VAR_DECL, 31 | 32 | // Expressions 33 | // Unary expressions 34 | EXPR_NEGATE, 35 | EXPR_LOGIC_NOT, 36 | 37 | // Binary expressions 38 | EXPR_MULT, 39 | EXPR_DIV, 40 | EXPR_ADD, 41 | EXPR_SUB, 42 | EXPR_CMP_LESS, 43 | EXPR_CMP_LESS_EQUAL, 44 | EXPR_CMP_GREATER, 45 | EXPR_CMP_GREATER_EQUAL, 46 | EXPR_CMP_NOT_EQUAL, 47 | EXPR_CMP_EQUAL, 48 | EXPR_LOGIC_AND, 49 | EXPR_LOGIC_OR, 50 | 51 | // Literal expressions (vars, constants) 52 | EXPR_LITERAL_VAR, 53 | EXPR_LITERAL_CONSTANT, 54 | 55 | // Other expressions 56 | EXPR_FCN_CALL, 57 | EXPR_STRUCT_ARRAY_ACCESS, 58 | EXPR_ASSIGN, 59 | }; 60 | 61 | std::string to_string(const NodeType &nt); 62 | 63 | /* Node in the AST that is tied to a specific location in the source code 64 | */ 65 | class Node { 66 | protected: 67 | antlr4::Token *token = nullptr; 68 | NodeType node_type = NodeType::INVALID; 69 | 70 | public: 71 | Node() = default; 72 | 73 | Node(antlr4::Token *token, NodeType type); 74 | 75 | virtual ~Node() = default; 76 | 77 | NodeType get_node_type() const; 78 | 79 | antlr4::Token *get_token(); 80 | 81 | const antlr4::Token *get_token() const; 82 | 83 | // Generated nodes's tokens are null, as there's no source input they correspond too 84 | // TODO: Maybe this could refer to the original source token that caused their generation? 85 | // might get hard to track with more complex generation of nodes or not make much sense. 86 | // making it null will help catch bugs 87 | bool is_generated() const; 88 | 89 | virtual std::string get_text() const; 90 | 91 | virtual std::vector> get_children() = 0; 92 | }; 93 | 94 | class AST { 95 | public: 96 | // The top level declarations in the program 97 | std::vector> top_level_decls; 98 | }; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/crtl/compiler/ast/statement.cpp: -------------------------------------------------------------------------------- 1 | #include "statement.h" 2 | 3 | namespace crtl { 4 | namespace ast { 5 | namespace stmt { 6 | 7 | Statement::Statement(antlr4::Token *token, NodeType stmt_type) : Node(token, stmt_type) {} 8 | 9 | Block::Block(antlr4::Token *token, const std::vector> &statements) 10 | : Statement(token, NodeType::STMT_BLOCK), statements(statements) 11 | { 12 | } 13 | 14 | std::vector> Block::get_children() 15 | { 16 | std::vector> children; 17 | for (auto &s : statements) { 18 | children.push_back(s); 19 | } 20 | return children; 21 | } 22 | 23 | IfElse::IfElse(antlr4::Token *token, 24 | const std::shared_ptr &condition, 25 | const std::shared_ptr &if_branch, 26 | const std::shared_ptr &else_branch) 27 | : Statement(token, NodeType::STMT_IF_ELSE), 28 | condition(condition), 29 | if_branch(if_branch), 30 | else_branch(else_branch) 31 | { 32 | } 33 | 34 | std::vector> IfElse::get_children() 35 | { 36 | std::vector> children; 37 | children.push_back(condition); 38 | children.push_back(if_branch); 39 | if (else_branch) { 40 | children.push_back(else_branch); 41 | } 42 | return children; 43 | } 44 | 45 | While::While(antlr4::Token *token, 46 | const std::shared_ptr &condition, 47 | const std::shared_ptr &body) 48 | : Statement(token, NodeType::STMT_WHILE), condition(condition), body(body) 49 | { 50 | } 51 | 52 | std::vector> While::get_children() 53 | { 54 | std::vector> children; 55 | children.push_back(condition); 56 | if (body) { 57 | children.push_back(body); 58 | } 59 | return children; 60 | } 61 | 62 | For::For(antlr4::Token *token, 63 | const std::shared_ptr &init, 64 | const std::shared_ptr &condition, 65 | const std::shared_ptr &advance, 66 | const std::shared_ptr &body) 67 | : Statement(token, NodeType::STMT_FOR), 68 | init(init), 69 | condition(condition), 70 | advance(advance), 71 | body(body) 72 | { 73 | } 74 | 75 | std::vector> For::get_children() 76 | { 77 | std::vector> children; 78 | if (init) { 79 | children.push_back(init); 80 | } 81 | if (condition) { 82 | children.push_back(condition); 83 | } 84 | if (advance) { 85 | children.push_back(advance); 86 | } 87 | if (body) { 88 | children.push_back(body); 89 | } 90 | return children; 91 | } 92 | 93 | Return::Return(antlr4::Token *token, const std::shared_ptr &expr) 94 | : Statement(token, NodeType::STMT_RETURN), expression(expr) 95 | { 96 | } 97 | 98 | std::vector> Return::get_children() 99 | { 100 | std::vector> children; 101 | if (expression) { 102 | children.push_back(expression); 103 | } 104 | return children; 105 | } 106 | 107 | VariableDeclaration::VariableDeclaration(antlr4::Token *token, 108 | const std::shared_ptr &var_decl) 109 | : Statement(token, NodeType::STMT_VAR_DECL), var_decl(var_decl) 110 | { 111 | } 112 | 113 | std::vector> VariableDeclaration::get_children() 114 | { 115 | std::vector> children; 116 | children.push_back(var_decl); 117 | return children; 118 | } 119 | 120 | Expression::Expression(antlr4::Token *token, const std::shared_ptr &expr) 121 | : Statement(token, NodeType::STMT_EXPR), expr(expr) 122 | { 123 | } 124 | 125 | std::vector> Expression::get_children() 126 | { 127 | std::vector> children; 128 | children.push_back(expr); 129 | return children; 130 | } 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/crtl/compiler/ast/statement.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "declaration.h" 4 | #include "expression.h" 5 | #include "node.h" 6 | 7 | namespace crtl { 8 | namespace ast { 9 | namespace stmt { 10 | 11 | class Statement : public Node { 12 | public: 13 | Statement(antlr4::Token *token, NodeType stmt_type); 14 | }; 15 | 16 | class Block : public Statement { 17 | public: 18 | std::vector> statements; 19 | 20 | Block(antlr4::Token *token, const std::vector> &statements); 21 | 22 | std::vector> get_children() override; 23 | }; 24 | 25 | class IfElse : public Statement { 26 | public: 27 | std::shared_ptr condition; 28 | std::shared_ptr if_branch; 29 | std::shared_ptr else_branch; 30 | 31 | IfElse(antlr4::Token *token, 32 | const std::shared_ptr &condition, 33 | const std::shared_ptr &if_branch, 34 | const std::shared_ptr &else_branch); 35 | 36 | std::vector> get_children() override; 37 | }; 38 | 39 | class While : public Statement { 40 | public: 41 | std::shared_ptr condition; 42 | std::shared_ptr body; 43 | 44 | While(antlr4::Token *token, 45 | const std::shared_ptr &condition, 46 | const std::shared_ptr &body); 47 | 48 | std::vector> get_children() override; 49 | }; 50 | 51 | class For : public Statement { 52 | public: 53 | std::shared_ptr init; 54 | std::shared_ptr condition; 55 | std::shared_ptr advance; 56 | std::shared_ptr body; 57 | 58 | For(antlr4::Token *token, 59 | const std::shared_ptr &init, 60 | const std::shared_ptr &condition, 61 | const std::shared_ptr &advance, 62 | const std::shared_ptr &body); 63 | 64 | std::vector> get_children() override; 65 | }; 66 | 67 | class Return : public Statement { 68 | public: 69 | std::shared_ptr expression; 70 | 71 | Return(antlr4::Token *token, const std::shared_ptr &expr); 72 | 73 | std::vector> get_children() override; 74 | }; 75 | 76 | class VariableDeclaration : public Statement { 77 | public: 78 | std::shared_ptr var_decl; 79 | 80 | VariableDeclaration(antlr4::Token *token, const std::shared_ptr &var_decl); 81 | 82 | std::vector> get_children() override; 83 | }; 84 | 85 | class Expression : public Statement { 86 | public: 87 | std::shared_ptr expr; 88 | 89 | Expression(antlr4::Token *token, const std::shared_ptr &expr); 90 | 91 | std::vector> get_children() override; 92 | }; 93 | 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/crtl/compiler/ast/symbol.cpp: -------------------------------------------------------------------------------- 1 | #include "symbol.h" 2 | 3 | namespace crtl { 4 | namespace ast { 5 | 6 | Symbol::Symbol(const std::string &name, antlr4::Token *token) : name(name), token(token) {} 7 | 8 | bool Symbol::is_generated() const 9 | { 10 | return !token; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/crtl/compiler/ast/symbol.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "node.h" 4 | #include "type.h" 5 | 6 | namespace crtl { 7 | namespace ast { 8 | 9 | struct Symbol { 10 | std::string name; 11 | antlr4::Token *token = nullptr; 12 | std::shared_ptr type; 13 | 14 | Symbol(const std::string &name, antlr4::Token *token); 15 | 16 | // Generated symbol's tokens are null, as there's no source input they correspond too 17 | // TODO: Maybe this could refer to the original source token that caused their generation? 18 | // might get hard to track with more complex generation of nodes or not make much sense. 19 | // making it null will help catch bugs 20 | bool is_generated() const; 21 | }; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/crtl/compiler/ast/visitor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "declaration.h" 6 | #include "error_listener.h" 7 | #include "expression.h" 8 | #include "node.h" 9 | #include "statement.h" 10 | 11 | namespace crtl { 12 | namespace ast { 13 | 14 | class Visitor : public ErrorReporter { 15 | private: 16 | size_t trace_depth = 0; 17 | 18 | public: 19 | bool trace_visitor = false; 20 | 21 | virtual ~Visitor() = default; 22 | 23 | virtual std::any visit_ast(const std::shared_ptr &ast); 24 | 25 | std::any visit(const std::shared_ptr &n); 26 | 27 | // Visit the node's children and return a vector of their return values 28 | std::any visit_children(const std::shared_ptr &n); 29 | 30 | // Declarations 31 | virtual std::any visit_decl_function(const std::shared_ptr &d); 32 | virtual std::any visit_decl_entry_point(const std::shared_ptr &d); 33 | virtual std::any visit_decl_global_param(const std::shared_ptr &d); 34 | virtual std::any visit_decl_struct(const std::shared_ptr &d); 35 | virtual std::any visit_decl_struct_member(const std::shared_ptr &d); 36 | virtual std::any visit_decl_variable(const std::shared_ptr &d); 37 | 38 | // Statements 39 | virtual std::any visit_stmt_block(const std::shared_ptr &s); 40 | virtual std::any visit_stmt_if_else(const std::shared_ptr &s); 41 | virtual std::any visit_stmt_while(const std::shared_ptr &s); 42 | virtual std::any visit_stmt_for(const std::shared_ptr &s); 43 | virtual std::any visit_stmt_return(const std::shared_ptr &s); 44 | virtual std::any visit_stmt_variable_declaration( 45 | const std::shared_ptr &s); 46 | virtual std::any visit_stmt_expression(const std::shared_ptr &s); 47 | 48 | // Expressions 49 | virtual std::any visit_expr_unary(const std::shared_ptr &e); 50 | virtual std::any visit_expr_binary(const std::shared_ptr &e); 51 | virtual std::any visit_expr_variable(const std::shared_ptr &e); 52 | virtual std::any visit_expr_constant(const std::shared_ptr &e); 53 | virtual std::any visit_expr_function_call(const std::shared_ptr &e); 54 | virtual std::any visit_struct_array_access( 55 | const std::shared_ptr &e); 56 | virtual std::any visit_expr_assignment(const std::shared_ptr &e); 57 | 58 | private: 59 | void report_enter_node(const Node *n); 60 | void report_exit_node(const Node *n); 61 | }; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/crtl/compiler/ast_builder_visitor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "ChameleonRTParserBaseVisitor.h" 7 | #include "antlr4-runtime.h" 8 | #include "ast/node.h" 9 | #include "ast/type.h" 10 | #include "error_listener.h" 11 | 12 | namespace crtl { 13 | class ASTBuilderVisitor : public crtg::ChameleonRTParserBaseVisitor, public ErrorReporter { 14 | public: 15 | std::shared_ptr ast = std::make_shared(); 16 | 17 | virtual std::any visitTopLevelDeclaration( 18 | crtg::ChameleonRTParser::TopLevelDeclarationContext *ctx) override; 19 | 20 | virtual std::any visitFunctionDecl( 21 | crtg::ChameleonRTParser::FunctionDeclContext *ctx) override; 22 | 23 | virtual std::any visitStructDecl(crtg::ChameleonRTParser::StructDeclContext *ctx) override; 24 | 25 | virtual std::any visitStructMember( 26 | crtg::ChameleonRTParser::StructMemberContext *ctx) override; 27 | 28 | virtual std::any visitParameterList( 29 | crtg::ChameleonRTParser::ParameterListContext *ctx) override; 30 | 31 | virtual std::any visitParameter(crtg::ChameleonRTParser::ParameterContext *ctx) override; 32 | 33 | virtual std::any visitBlock(crtg::ChameleonRTParser::BlockContext *ctx) override; 34 | 35 | virtual std::any visitVarDecl(crtg::ChameleonRTParser::VarDeclContext *ctx) override; 36 | 37 | virtual std::any visitVarDeclStmt( 38 | crtg::ChameleonRTParser::VarDeclStmtContext *ctx) override; 39 | 40 | virtual std::any visitGlobalParamDecl( 41 | crtg::ChameleonRTParser::GlobalParamDeclContext *ctx) override; 42 | 43 | virtual std::any visitIfStmt(crtg::ChameleonRTParser::IfStmtContext *ctx) override; 44 | 45 | virtual std::any visitWhileStmt(crtg::ChameleonRTParser::WhileStmtContext *ctx) override; 46 | 47 | virtual std::any visitForStmt(crtg::ChameleonRTParser::ForStmtContext *ctx) override; 48 | 49 | virtual std::any visitReturnStmt(crtg::ChameleonRTParser::ReturnStmtContext *ctx) override; 50 | 51 | virtual std::any visitExprStmt(crtg::ChameleonRTParser::ExprStmtContext *ctx) override; 52 | 53 | virtual std::any visitTypeName(crtg::ChameleonRTParser::TypeNameContext *ctx) override; 54 | 55 | virtual std::any visitTemplateParameters( 56 | crtg::ChameleonRTParser::TemplateParametersContext *ctx) override; 57 | 58 | std::set parse_modifiers( 59 | antlr4::Token *token, 60 | const std::vector &modifier_list); 61 | 62 | // Expression visitors are overriden for convenience, but all forward on to the 63 | // ASTExprBuilderVisitor 64 | virtual std::any visitUnary(crtg::ChameleonRTParser::UnaryContext *ctx) override; 65 | virtual std::any visitCall(crtg::ChameleonRTParser::CallContext *ctx) override; 66 | virtual std::any visitStructArray( 67 | crtg::ChameleonRTParser::StructArrayContext *ctx) override; 68 | virtual std::any visitMult(crtg::ChameleonRTParser::MultContext *ctx) override; 69 | virtual std::any visitDiv(crtg::ChameleonRTParser::DivContext *ctx) override; 70 | virtual std::any visitAddSub(crtg::ChameleonRTParser::AddSubContext *ctx) override; 71 | virtual std::any visitComparison(crtg::ChameleonRTParser::ComparisonContext *ctx) override; 72 | virtual std::any visitEquality(crtg::ChameleonRTParser::EqualityContext *ctx) override; 73 | virtual std::any visitLogicAnd(crtg::ChameleonRTParser::LogicAndContext *ctx) override; 74 | virtual std::any visitLogicOr(crtg::ChameleonRTParser::LogicOrContext *ctx) override; 75 | virtual std::any visitAssign(crtg::ChameleonRTParser::AssignContext *ctx) override; 76 | virtual std::any visitParens(crtg::ChameleonRTParser::ParensContext *ctx) override; 77 | virtual std::any visitPrimary(crtg::ChameleonRTParser::PrimaryContext *ctx) override; 78 | 79 | std::any visit_expr(crtg::ChameleonRTParser::ExprContext *ctx); 80 | }; 81 | } 82 | -------------------------------------------------------------------------------- /src/crtl/compiler/ast_expr_builder_visitor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "ChameleonRTParserBaseVisitor.h" 7 | #include "antlr4-runtime.h" 8 | #include "ast/expression.h" 9 | #include "ast/type.h" 10 | #include "error_listener.h" 11 | 12 | namespace crtl { 13 | 14 | /* The ASTExprBuilderVisitor visits the passed expression and constructs the AST expression 15 | * node corresponding to the expression and any subexpressions. The root of the expression tree 16 | * is returned in the std::any as a std::shared_ptr 17 | */ 18 | class ASTExprBuilderVisitor : public crtg::ChameleonRTParserBaseVisitor, public ErrorReporter { 19 | public: 20 | virtual std::any visitCall(crtg::ChameleonRTParser::CallContext *ctx) override; 21 | 22 | virtual std::any visitLogicOr(crtg::ChameleonRTParser::LogicOrContext *ctx) override; 23 | 24 | virtual std::any visitAddSub(crtg::ChameleonRTParser::AddSubContext *ctx) override; 25 | 26 | virtual std::any visitParens(crtg::ChameleonRTParser::ParensContext *ctx) override; 27 | 28 | virtual std::any visitUnary(crtg::ChameleonRTParser::UnaryContext *ctx) override; 29 | 30 | virtual std::any visitStructArray( 31 | crtg::ChameleonRTParser::StructArrayContext *ctx) override; 32 | 33 | virtual std::any visitDiv(crtg::ChameleonRTParser::DivContext *ctx) override; 34 | 35 | virtual std::any visitMult(crtg::ChameleonRTParser::MultContext *ctx) override; 36 | 37 | virtual std::any visitComparison(crtg::ChameleonRTParser::ComparisonContext *ctx) override; 38 | 39 | virtual std::any visitPrimary(crtg::ChameleonRTParser::PrimaryContext *ctx) override; 40 | 41 | virtual std::any visitAssign(crtg::ChameleonRTParser::AssignContext *ctx) override; 42 | 43 | virtual std::any visitEquality(crtg::ChameleonRTParser::EqualityContext *ctx) override; 44 | 45 | virtual std::any visitLogicAnd(crtg::ChameleonRTParser::LogicAndContext *ctx) override; 46 | 47 | virtual std::any visitFunctionCall( 48 | crtg::ChameleonRTParser::FunctionCallContext *ctx) override; 49 | }; 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/crtl/compiler/ast_struct_array_access_builder_visitor.cpp: -------------------------------------------------------------------------------- 1 | #include "ast_struct_array_access_builder_visitor.h" 2 | #include "ast_expr_builder_visitor.h" 3 | 4 | namespace crtl { 5 | 6 | using namespace ast; 7 | 8 | std::any ASTStructArrayAccessBuilderVisitor::visitStructAccess( 9 | crtg::ChameleonRTParser::StructAccessContext *ctx) 10 | { 11 | struct_array_chain.push_back( 12 | std::make_shared(ctx->IDENTIFIER()->getSymbol())); 13 | return std::any(); 14 | } 15 | 16 | std::any ASTStructArrayAccessBuilderVisitor::visitArrayAccess( 17 | crtg::ChameleonRTParser::ArrayAccessContext *ctx) 18 | { 19 | ASTExprBuilderVisitor expr_visitor; 20 | auto index = 21 | std::any_cast>(expr_visitor.visit(ctx->expr())); 22 | struct_array_chain.push_back(std::make_shared(index)); 23 | return std::any(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/crtl/compiler/ast_struct_array_access_builder_visitor.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ChameleonRTParserBaseVisitor.h" 4 | #include "antlr4-runtime.h" 5 | #include "ast/expression.h" 6 | #include "ast/type.h" 7 | #include "error_listener.h" 8 | 9 | namespace crtl { 10 | /* The ASTStructArrayAccessBuilderVisitor takes a node with some chain of structAccess and/or 11 | * arrayAccess child nodes and visits them all to construct a vector containing this list of 12 | * expressions 13 | */ 14 | class ASTStructArrayAccessBuilderVisitor : public crtg::ChameleonRTParserBaseVisitor, 15 | public ErrorReporter { 16 | public: 17 | std::vector> struct_array_chain; 18 | 19 | virtual std::any visitStructAccess( 20 | crtg::ChameleonRTParser::StructAccessContext *ctx) override; 21 | 22 | virtual std::any visitArrayAccess( 23 | crtg::ChameleonRTParser::ArrayAccessContext *ctx) override; 24 | }; 25 | 26 | } -------------------------------------------------------------------------------- /src/crtl/compiler/builtins.cpp: -------------------------------------------------------------------------------- 1 | #include "builtins.h" 2 | 3 | namespace crtl { 4 | std::vector> get_builtin_decls() 5 | { 6 | using namespace ast; 7 | std::vector> builtins; 8 | 9 | // ray_index 10 | { 11 | auto ret_type = std::make_shared( 12 | std::make_shared(ty::PrimitiveType::UINT), 2); 13 | auto decl = std::make_shared( 14 | "ray_index", std::vector>(), ret_type); 15 | builtins.push_back(std::dynamic_pointer_cast(decl)); 16 | } 17 | 18 | return builtins; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/crtl/compiler/builtins.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "ast/declaration.h" 6 | 7 | namespace crtl { 8 | std::vector> get_builtin_decls(); 9 | } 10 | -------------------------------------------------------------------------------- /src/crtl/compiler/error_listener.cpp: -------------------------------------------------------------------------------- 1 | #include "error_listener.h" 2 | #include 3 | 4 | using namespace antlr4; 5 | 6 | namespace crtl { 7 | 8 | void ErrorReporter::report_error(const antlr4::Token *token, const std::string &msg) 9 | { 10 | had_error = true; 11 | report(token, "Error", msg); 12 | } 13 | 14 | void ErrorReporter::report_warning(const antlr4::Token *token, const std::string &msg) 15 | { 16 | report(token, "Warning", msg); 17 | } 18 | 19 | void ErrorReporter::report(const antlr4::Token *token, 20 | const std::string &prefix, 21 | const std::string &msg) 22 | { 23 | std::cerr << prefix << " at " << token->getLine() << ":" << token->getCharPositionInLine() 24 | << " '" << token->getText() << "' > " << msg << "\n" 25 | << std::flush; 26 | } 27 | 28 | void ErrorListener::syntaxError( 29 | Recognizer *, Token *, size_t, size_t, const std::string &, std::exception_ptr) 30 | { 31 | // It looks like there's a default error handler attached 32 | // that prints out errors (the console error listener) 33 | // So here just flag an error happened. 34 | had_syntax_error = true; 35 | } 36 | 37 | bool ErrorListener::had_error() const 38 | { 39 | return had_syntax_error; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/crtl/compiler/error_listener.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "antlr4-runtime.h" 4 | 5 | namespace crtl { 6 | 7 | class ErrorReporter { 8 | public: 9 | bool had_error = false; 10 | 11 | virtual ~ErrorReporter() = default; 12 | 13 | void report_error(const antlr4::Token *token, const std::string &msg); 14 | 15 | void report_warning(const antlr4::Token *token, const std::string &msg); 16 | 17 | private: 18 | void report(const antlr4::Token *token, const std::string &prefix, const std::string &msg); 19 | }; 20 | 21 | class ErrorListener : public antlr4::BaseErrorListener { 22 | bool had_syntax_error = false; 23 | 24 | public: 25 | void syntaxError(antlr4::Recognizer *recognizer, 26 | antlr4::Token *offendingSymbol, 27 | size_t line, 28 | size_t charPositionInLine, 29 | const std::string &msg, 30 | std::exception_ptr e) override; 31 | 32 | bool had_error() const; 33 | }; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/crtl/compiler/global_struct_param_expansion_visitor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ast/modifying_visitor.h" 4 | #include "resolver_visitor.h" 5 | 6 | namespace crtl { 7 | 8 | struct ExpandedGlobalParam { 9 | // The former members of the global struct parameter that have been expanded to global 10 | // parameters 11 | phmap::parallel_flat_hash_map> 12 | members; 13 | }; 14 | 15 | // TODO: Need to not split up a struct of all constants into individual constant parameters 16 | // Maybe this should become more backend-specific because what we want to split or not split 17 | // depends on our compile target 18 | class GlobalStructParamExpansionVisitor : public ast::ModifyingVisitor { 19 | std::shared_ptr resolver_result; 20 | 21 | public: 22 | phmap::parallel_flat_hash_map, 23 | std::shared_ptr> 24 | expanded_global_params; 25 | 26 | GlobalStructParamExpansionVisitor( 27 | const std::shared_ptr &resolver_result); 28 | 29 | std::any visit_decl_global_param( 30 | const std::shared_ptr &d) override; 31 | 32 | /* We don't actually rewrite plain variable expressions, but need to visit them to check if 33 | * a global struct parameter was passed directly to a function, which the current design of 34 | * this pass turns into invalid code by replacing the struct param with its members 35 | */ 36 | std::any visit_expr_variable(const std::shared_ptr &e) override; 37 | 38 | std::any visit_struct_array_access( 39 | const std::shared_ptr &e) override; 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /src/crtl/compiler/hlsl/crtl_to_hlsl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "json.hpp" 6 | 7 | namespace crtl { 8 | namespace hlsl { 9 | 10 | struct ShaderCompilationResult { 11 | std::string hlsl_src; 12 | nlohmann::json shader_info; 13 | 14 | ShaderCompilationResult() = default; 15 | 16 | ShaderCompilationResult(const std::string &hlsl_src, nlohmann::json &shader_info); 17 | }; 18 | 19 | std::shared_ptr compile_crtl(const std::string &crtl_src); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/crtl/compiler/hlsl/output_visitor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ast/visitor.h" 4 | #include "resolver_visitor.h" 5 | #include "shader_register_allocator.h" 6 | 7 | namespace crtl { 8 | namespace hlsl { 9 | 10 | // TODO: Later can have a parent for all langage output visitors that will hold the generated 11 | // source, metadata, etc. 12 | class OutputVisitor : public ast::Visitor { 13 | std::shared_ptr resolver_result; 14 | 15 | ShaderRegisterAllocator register_allocator; 16 | 17 | public: 18 | // Map of global and entry point parameter names to their register binding information 19 | phmap::parallel_flat_hash_map, 20 | std::shared_ptr> 21 | parameter_bindings; 22 | 23 | OutputVisitor(const std::shared_ptr &resolver_result); 24 | 25 | // NOTE: Most statements don't need any rewriting but we do still need to visit 26 | // everything to build the HLSL source code 27 | 28 | /* Visit the AST and translate it to HLSL. The std::any returned contains a std::string 29 | * with the translated source code 30 | */ 31 | std::any visit_ast(const std::shared_ptr &ast) override; 32 | 33 | // Declarations 34 | std::any visit_decl_function(const std::shared_ptr &d) override; 35 | std::any visit_decl_entry_point(const std::shared_ptr &d) override; 36 | std::any visit_decl_global_param( 37 | const std::shared_ptr &d) override; 38 | std::any visit_decl_struct(const std::shared_ptr &d) override; 39 | std::any visit_decl_struct_member( 40 | const std::shared_ptr &d) override; 41 | std::any visit_decl_variable(const std::shared_ptr &d) override; 42 | 43 | // Statements 44 | std::any visit_stmt_block(const std::shared_ptr &s) override; 45 | std::any visit_stmt_if_else(const std::shared_ptr &s) override; 46 | std::any visit_stmt_while(const std::shared_ptr &s) override; 47 | std::any visit_stmt_for(const std::shared_ptr &s) override; 48 | std::any visit_stmt_return(const std::shared_ptr &s) override; 49 | std::any visit_stmt_variable_declaration( 50 | const std::shared_ptr &s) override; 51 | std::any visit_stmt_expression(const std::shared_ptr &s) override; 52 | 53 | // Expressions 54 | std::any visit_expr_unary(const std::shared_ptr &e) override; 55 | std::any visit_expr_binary(const std::shared_ptr &e) override; 56 | std::any visit_expr_variable(const std::shared_ptr &e) override; 57 | std::any visit_expr_constant(const std::shared_ptr &e) override; 58 | std::any visit_expr_function_call( 59 | const std::shared_ptr &e) override; 60 | std::any visit_struct_array_access( 61 | const std::shared_ptr &e) override; 62 | std::any visit_expr_assignment(const std::shared_ptr &e) override; 63 | 64 | private: 65 | /* Bind the passed global or entry point parameter to registers and return the HLSL source 66 | * for the binding. The ParameterRegisterBinding metadata will be stored in the 67 | * parameter_binding map 68 | */ 69 | std::string bind_parameter(const std::shared_ptr ¶m); 70 | 71 | /* Bind the passed built in parameter type (i.e. not a struct) to a shader register. 72 | */ 73 | ShaderRegisterBinding bind_builtin_type_parameter( 74 | const std::shared_ptr &type); 75 | }; 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /src/crtl/compiler/hlsl/parameter_metadata_output_visitor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "ast/visitor.h" 5 | #include "parameter_transforms.h" 6 | #include "resolver_visitor.h" 7 | #include "shader_register_allocator.h" 8 | 9 | namespace crtl { 10 | namespace hlsl { 11 | 12 | class ParameterMetadataOutputVisitor : public ast::Visitor { 13 | std::shared_ptr resolver_result; 14 | 15 | std::shared_ptr param_transforms; 16 | 17 | // Map of global and entry point parameter names to their register binding information 18 | phmap::parallel_flat_hash_map, 19 | std::shared_ptr> 20 | parameter_bindings; 21 | 22 | public: 23 | ParameterMetadataOutputVisitor( 24 | const std::shared_ptr &resolver_result, 25 | const std::shared_ptr ¶m_transforms, 26 | const phmap::parallel_flat_hash_map, 27 | std::shared_ptr> 28 | ¶m_bindings); 29 | 30 | /* Visit the AST and build the parameter binding metadata JSON info for use at runtime. 31 | * Returns the nlohmann::json containing the parameter binding information for use by the 32 | * DXR runtime 33 | */ 34 | std::any visit_ast(const std::shared_ptr &ast) override; 35 | 36 | /* We just need to visit entry point and global param declarations to output their 37 | * parameters to JSON 38 | */ 39 | std::any visit_decl_entry_point(const std::shared_ptr &d) override; 40 | std::any visit_decl_global_param( 41 | const std::shared_ptr &d) override; 42 | }; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/crtl/compiler/hlsl/shader_register_allocator.cpp: -------------------------------------------------------------------------------- 1 | #include "shader_register_allocator.h" 2 | 3 | namespace crtl { 4 | namespace hlsl { 5 | 6 | ShaderRegisterBinding ShaderRegisterAllocator::bind_srv(int count) 7 | { 8 | ShaderRegisterBinding binding(next_srv_reg, count); 9 | next_srv_reg.slot += count; 10 | return binding; 11 | } 12 | 13 | ShaderRegisterBinding ShaderRegisterAllocator::bind_srv_unsized() 14 | { 15 | ShaderRegisterBinding binding(next_srv_reg, -1); 16 | next_srv_reg.space++; 17 | next_srv_reg.slot = 0; 18 | return binding; 19 | } 20 | 21 | ShaderRegisterBinding ShaderRegisterAllocator::bind_sampler(int count) 22 | { 23 | ShaderRegisterBinding binding(next_sampler_reg, count); 24 | next_sampler_reg.slot += count; 25 | return binding; 26 | } 27 | 28 | ShaderRegisterBinding ShaderRegisterAllocator::bind_sampler_unsized() 29 | { 30 | ShaderRegisterBinding binding(next_sampler_reg, -1); 31 | next_sampler_reg.space++; 32 | next_sampler_reg.slot = 0; 33 | return binding; 34 | } 35 | 36 | ShaderRegisterBinding ShaderRegisterAllocator::bind_uav(int count) 37 | { 38 | ShaderRegisterBinding binding(next_uav_reg, count); 39 | next_uav_reg.slot += count; 40 | return binding; 41 | } 42 | 43 | ShaderRegisterBinding ShaderRegisterAllocator::bind_uav_unsized() 44 | { 45 | ShaderRegisterBinding binding(next_uav_reg, -1); 46 | next_uav_reg.space++; 47 | next_uav_reg.slot = 0; 48 | return binding; 49 | } 50 | 51 | ShaderRegisterBinding ShaderRegisterAllocator::bind_cbv(int count) 52 | { 53 | ShaderRegisterBinding binding(next_cbv_reg, count); 54 | next_cbv_reg.slot += count; 55 | return binding; 56 | } 57 | 58 | ShaderRegisterBinding ShaderRegisterAllocator::bind_cbv_unsized() 59 | { 60 | ShaderRegisterBinding binding(next_cbv_reg, -1); 61 | next_cbv_reg.space++; 62 | next_cbv_reg.slot = 0; 63 | return binding; 64 | } 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/crtl/compiler/hlsl/shader_register_allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "ast/type.h" 6 | #include "shader_register_binding.h" 7 | 8 | namespace crtl { 9 | namespace hlsl { 10 | 11 | /* The ShaderRegisterAllocator tracks which is the next shader slot and space available for 12 | * each type of shader register, and can bind numbers of items to these registers. Binding 13 | * items advances the register state 14 | */ 15 | struct ShaderRegisterAllocator { 16 | private: 17 | ShaderRegister next_srv_reg = 18 | ShaderRegister(ShaderRegisterType::SHADER_RESOURCE_VIEW, 0, 0); 19 | ShaderRegister next_sampler_reg = ShaderRegister(ShaderRegisterType::SAMPLER, 0, 0); 20 | ShaderRegister next_uav_reg = 21 | ShaderRegister(ShaderRegisterType::UNORDERED_ACCESS_VIEW, 0, 0); 22 | ShaderRegister next_cbv_reg = 23 | ShaderRegister(ShaderRegisterType::CONSTANT_BUFFER_VIEW, 0, 0); 24 | 25 | public: 26 | ShaderRegisterBinding bind_srv(int count); 27 | 28 | ShaderRegisterBinding bind_srv_unsized(); 29 | 30 | ShaderRegisterBinding bind_sampler(int count); 31 | 32 | ShaderRegisterBinding bind_sampler_unsized(); 33 | 34 | ShaderRegisterBinding bind_uav(int count); 35 | 36 | ShaderRegisterBinding bind_uav_unsized(); 37 | 38 | ShaderRegisterBinding bind_cbv(int count); 39 | 40 | ShaderRegisterBinding bind_cbv_unsized(); 41 | }; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/crtl/compiler/hlsl/shader_register_binding.cpp: -------------------------------------------------------------------------------- 1 | #include "shader_register_binding.h" 2 | #include 3 | 4 | namespace crtl { 5 | namespace hlsl { 6 | 7 | const std::string to_string(const ShaderRegisterType &sr_type) 8 | { 9 | switch (sr_type) { 10 | case ShaderRegisterType::SHADER_RESOURCE_VIEW: 11 | return "t"; 12 | case ShaderRegisterType::SAMPLER: 13 | return "s"; 14 | case ShaderRegisterType::UNORDERED_ACCESS_VIEW: 15 | return "u"; 16 | case ShaderRegisterType::CONSTANT_BUFFER_VIEW: 17 | return "b"; 18 | default: 19 | throw std::runtime_error("Cannot generate string for invalid register type"); 20 | return ""; 21 | } 22 | } 23 | 24 | ShaderRegister::ShaderRegister(ShaderRegisterType type, int slot, int space) 25 | : type(type), slot(slot), space(space) 26 | { 27 | } 28 | 29 | ShaderRegisterBinding::ShaderRegisterBinding(ShaderRegister shader_register, int count) 30 | : shader_register(shader_register), count(count) 31 | { 32 | } 33 | 34 | std::string ShaderRegister::to_string() const 35 | { 36 | if (slot == -1 || space == -1) { 37 | throw std::runtime_error("Cannot generate string for invalid register type"); 38 | } 39 | return "register(" + hlsl::to_string(type) + std::to_string(slot) + ", space" + 40 | std::to_string(space) + ")"; 41 | } 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/crtl/compiler/hlsl/shader_register_binding.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "parallel_hashmap/phmap.h" 6 | 7 | namespace crtl { 8 | namespace hlsl { 9 | enum class ShaderRegisterType { 10 | SHADER_RESOURCE_VIEW, 11 | SAMPLER, 12 | UNORDERED_ACCESS_VIEW, 13 | CONSTANT_BUFFER_VIEW, 14 | INVALID 15 | }; 16 | 17 | const std::string to_string(const ShaderRegisterType &sr_type); 18 | 19 | struct ShaderRegister { 20 | ShaderRegisterType type = ShaderRegisterType::INVALID; 21 | 22 | int slot = -1; 23 | // Register space that this register is within 24 | int space = -1; 25 | 26 | ShaderRegister(ShaderRegisterType type, int slot, int space); 27 | 28 | ShaderRegister() = default; 29 | 30 | std::string to_string() const; 31 | }; 32 | 33 | struct ParameterRegisterBinding { 34 | virtual ~ParameterRegisterBinding() = default; 35 | }; 36 | 37 | // The register binding assigned to an input parameter in HLSL 38 | struct ShaderRegisterBinding : ParameterRegisterBinding { 39 | ShaderRegister shader_register; 40 | // The number of registers following the starting slot that the binding occupies, 41 | // e.g. for arrays of resources. -1 indicates an unbounded size array 42 | int count = 0; 43 | 44 | ShaderRegisterBinding(ShaderRegister shader_register, int count); 45 | 46 | ShaderRegisterBinding() = default; 47 | }; 48 | 49 | /* The register binding for a struct parameter whose members may be split 50 | * over multiple different parameter types. All primitive/vector/matrix members 51 | * of the struct are packed into a constant buffer, while any buffers, textures, etc. 52 | * are bound to registers 53 | */ 54 | struct StructRegisterBinding : ParameterRegisterBinding { 55 | ShaderRegisterBinding constant_buffer_register; 56 | std::vector constant_buffer_contents; 57 | 58 | // Binding info for all non-constant buffer suitable data 59 | phmap::parallel_flat_hash_map members; 60 | }; 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/crtl/compiler/hlsl/translate_builtin_function_call.cpp: -------------------------------------------------------------------------------- 1 | #include "translate_builtin_function_call.h" 2 | 3 | namespace crtl { 4 | namespace hlsl { 5 | using namespace ast; 6 | std::string translate_builtin_function_call(ast::expr::FunctionCall *call, 7 | ast::decl::Function *callee) 8 | { 9 | if (callee->get_text() == "ray_index") { 10 | return "DispatchRaysIndex().xy"; 11 | } 12 | return ""; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/crtl/compiler/hlsl/translate_builtin_function_call.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ast/declaration.h" 4 | #include "ast/expression.h" 5 | 6 | namespace crtl { 7 | namespace hlsl { 8 | // Translate the call expression calling the builtin function callee 9 | std::string translate_builtin_function_call(ast::expr::FunctionCall *call, 10 | ast::decl::Function *callee); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/crtl/compiler/hlsl/translate_builtin_type.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "ast/type.h" 6 | 7 | namespace crtl { 8 | namespace hlsl { 9 | 10 | std::string translate_modifiers(const std::set &modifiers); 11 | 12 | /* Translate the passed built-in type to the corresponding HLSL type string. Types that can be 13 | * translated are 14 | * - Primitive 15 | * - Vector 16 | * - Matrix 17 | * - Buffer 18 | * - Texture 19 | * - AccelerationStructure 20 | * - Ray 21 | */ 22 | std::string translate_builtin_type(const std::shared_ptr &type); 23 | 24 | // Translate the passed built-in or user struct type to the corresponding HLSL type string. 25 | std::string translate_type(const std::shared_ptr &type); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/crtl/compiler/json_visitor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ast/visitor.h" 4 | #include "json.hpp" 5 | 6 | namespace crtl { 7 | 8 | class JSONVisitor : public ast::Visitor { 9 | public: 10 | /* Visit the AST to output it to a JSON representation. Returns the nlohmann::json object 11 | * containing the JSON representation of the AST 12 | */ 13 | std::any visit_ast(const std::shared_ptr &ast) override; 14 | 15 | std::any visit_decl_function(const std::shared_ptr &d) override; 16 | std::any visit_decl_entry_point(const std::shared_ptr &d) override; 17 | std::any visit_decl_global_param( 18 | const std::shared_ptr &d) override; 19 | std::any visit_decl_struct(const std::shared_ptr &d) override; 20 | std::any visit_decl_struct_member( 21 | const std::shared_ptr &d) override; 22 | std::any visit_decl_variable(const std::shared_ptr &d) override; 23 | 24 | std::any visit_stmt_block(const std::shared_ptr &s) override; 25 | std::any visit_stmt_if_else(const std::shared_ptr &s) override; 26 | std::any visit_stmt_while(const std::shared_ptr &s) override; 27 | std::any visit_stmt_for(const std::shared_ptr &s) override; 28 | std::any visit_stmt_return(const std::shared_ptr &s) override; 29 | std::any visit_stmt_variable_declaration( 30 | const std::shared_ptr &s) override; 31 | std::any visit_stmt_expression(const std::shared_ptr &s) override; 32 | 33 | std::any visit_expr_unary(const std::shared_ptr &e) override; 34 | std::any visit_expr_binary(const std::shared_ptr &e) override; 35 | std::any visit_expr_variable(const std::shared_ptr &e) override; 36 | std::any visit_expr_constant(const std::shared_ptr &e) override; 37 | std::any visit_expr_function_call( 38 | const std::shared_ptr &e) override; 39 | std::any visit_struct_array_access( 40 | const std::shared_ptr &e) override; 41 | std::any visit_expr_assignment(const std::shared_ptr &e) override; 42 | 43 | private: 44 | // Visit all the nodes in the vector and return their results as a vector of JSON elements 45 | std::vector visit_all( 46 | const std::vector> &nodes); 47 | 48 | // Visit all the struct/array access fragments and return them as an vector of JSON 49 | // elements 50 | std::vector visit_struct_array_fragments( 51 | const std::vector> &fragments); 52 | }; 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/crtl/compiler/parameter_transforms.cpp: -------------------------------------------------------------------------------- 1 | #include "parameter_transforms.h" 2 | 3 | namespace crtl { 4 | ParameterTransforms::ParameterTransforms( 5 | const phmap::parallel_flat_hash_map, 6 | std::shared_ptr> 7 | &in_expanded_global_params, 8 | const phmap::parallel_flat_hash_map, std::string> 9 | &in_renamed_vars) 10 | : expanded_global_params(in_expanded_global_params), renamed_vars(in_renamed_vars) 11 | { 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/crtl/compiler/parameter_transforms.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "ast/declaration.h" 5 | #include "global_struct_param_expansion_visitor.h" 6 | 7 | namespace crtl { 8 | using namespace ast; 9 | 10 | /* Struct that stores the various parameter transform info created in the different passes so 11 | * that the final output step can save the right metadata to map from the original source code 12 | * to the final output names or locations of the variables 13 | */ 14 | struct ParameterTransforms { 15 | /* Global struct parameters that were expanded to individual global parameters 16 | * in the global struct param expansion pass 17 | */ 18 | phmap::parallel_flat_hash_map, 19 | std::shared_ptr> 20 | expanded_global_params; 21 | 22 | /* Entry point parameters that were renamed to avoid name collisions in the 23 | * rename entry point param pass 24 | */ 25 | phmap::parallel_flat_hash_map, std::string> 26 | renamed_vars; 27 | 28 | ParameterTransforms( 29 | const phmap::parallel_flat_hash_map, 30 | std::shared_ptr> 31 | &expanded_global_params, 32 | const phmap::parallel_flat_hash_map, std::string> 33 | &renamed_vars); 34 | 35 | ParameterTransforms() = default; 36 | }; 37 | 38 | } 39 | 40 | -------------------------------------------------------------------------------- /src/crtl/compiler/rename_entry_point_param_visitor.cpp: -------------------------------------------------------------------------------- 1 | #include "rename_entry_point_param_visitor.h" 2 | 3 | namespace crtl { 4 | using namespace ast; 5 | 6 | RenameEntryPointParamVisitor::RenameEntryPointParamVisitor( 7 | const std::shared_ptr &resolver_result) 8 | : resolver_result(resolver_result) 9 | { 10 | } 11 | 12 | std::any RenameEntryPointParamVisitor::visit_decl_entry_point( 13 | const std::shared_ptr &d) 14 | { 15 | // Rename any parameters here 16 | const std::string prefix = d->get_text() + "_"; 17 | for (auto &p : d->parameters) { 18 | auto &symbol = p->get_symbol(); 19 | const std::string old_name = symbol->name; 20 | symbol->name = prefix + old_name; 21 | renamed_vars[p] = old_name; 22 | } 23 | 24 | // Visit the block of the entry point to rename any references 25 | visit(d->block); 26 | return std::any(); 27 | } 28 | 29 | std::any RenameEntryPointParamVisitor::visit_expr_variable( 30 | const std::shared_ptr &e) 31 | { 32 | // If this was a variable that got renamed in this past, update its text in the expression 33 | auto decl = resolver_result->var_expr[e]; 34 | if (renamed_vars.contains(decl)) { 35 | e->var_name = decl->get_text(); 36 | } 37 | 38 | return std::any(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/crtl/compiler/rename_entry_point_param_visitor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ast/visitor.h" 4 | #include "resolver_visitor.h" 5 | 6 | namespace crtl { 7 | 8 | /* The RenameEntryPointParamVisitor renames all entry point parameters to be prefixed by the 9 | * entry point function name to avoid name collisions when they are moved in to the global 10 | * scope for HLSL and GLSL targets 11 | * TODO: Just prefixing by the function name may not be quite enough to ensure we avoid 12 | * collisions, if that's the case can generate more unique names and/or do some checking to 13 | * make sure we don't make a collision. For my own use this simple approach is fine 14 | */ 15 | class RenameEntryPointParamVisitor : public ast::Visitor { 16 | std::shared_ptr resolver_result; 17 | 18 | public: 19 | // A map of renamed variable declarations to their old names 20 | phmap::parallel_flat_hash_map, std::string> renamed_vars; 21 | 22 | RenameEntryPointParamVisitor(const std::shared_ptr &resolver_result); 23 | 24 | std::any visit_decl_entry_point(const std::shared_ptr &d) override; 25 | 26 | std::any visit_expr_variable(const std::shared_ptr &e) override; 27 | }; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/crtl/compiler/target_api.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum class TargetAPI { DIRECTX, VULKAN, OPTIX, METAL, EMBREE }; 4 | -------------------------------------------------------------------------------- /src/crtl/core/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(GenerateExportHeader) 2 | 3 | add_library(crtl SHARED 4 | crtl_buffer.cpp 5 | crtl_device.cpp 6 | crtl_event.cpp 7 | crtl_geometry.cpp 8 | crtl_parameter_block.cpp 9 | crtl_queue.cpp 10 | crtl_rtpipeline.cpp 11 | crtl_shader.cpp 12 | crtl_texture.cpp 13 | 14 | backend_plugin.cpp 15 | device.cpp 16 | util.cpp 17 | error.cpp 18 | type.cpp 19 | ) 20 | 21 | set_target_properties(crtl PROPERTIES 22 | CXX_STANDARD 17 23 | CXX_STANDARD_REQUIRED ON) 24 | 25 | # TODO: need install include paths set up later 26 | target_include_directories(crtl PUBLIC 27 | $ 28 | $ 29 | $ 30 | $) 31 | 32 | target_link_libraries(crtl PUBLIC glm) 33 | 34 | generate_export_header(crtl) 35 | 36 | add_subdirectory(dxr) 37 | 38 | #install(FILES 39 | # ${PROJECT_BINARY_DIR}/crtl_export.h DESTINATION ${INCLUDE_INSTALL_DIR} 40 | #) 41 | -------------------------------------------------------------------------------- /src/crtl/core/api_object.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "crtl_export.h" 4 | 5 | namespace crtl { 6 | class CRTL_EXPORT APIObject { 7 | public: 8 | int app_ref_count = 0; 9 | 10 | virtual ~APIObject() = default; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/crtl/core/backend_plugin.cpp: -------------------------------------------------------------------------------- 1 | #include "backend_plugin.h" 2 | #include 3 | #include 4 | 5 | #ifdef _WIN32 6 | #define SHARED_LIBRARY_PREFIX "" 7 | #define SHARED_LIBRARY_SUFFIX ".dll" 8 | #else 9 | #define SHARED_LIBRARY_PREFIX "lib" 10 | #define SHARED_LIBRARY_SUFFIX ".so" 11 | #endif 12 | 13 | namespace crtl { 14 | 15 | const std::string device_api_to_string(const CRTL_DEVICE_API api) 16 | { 17 | switch (api) { 18 | case CRTL_DEVICE_API_DX12: 19 | return "dxr"; 20 | case CRTL_DEVICE_API_VULKAN: 21 | return "vulkan"; 22 | case CRTL_DEVICE_API_METAL: 23 | return "metal"; 24 | case CRTL_DEVICE_API_OPTIX: 25 | return "optix"; 26 | case CRTL_DEVICE_API_EMBREE: 27 | return "embree"; 28 | default: 29 | return "unknown"; 30 | } 31 | } 32 | 33 | BackendPlugin::BackendPlugin(CRTL_DEVICE_API api) : api(api) 34 | { 35 | const std::string backend_name = device_api_to_string(api); 36 | const std::string backend_file_name = std::string(SHARED_LIBRARY_PREFIX) + "crtl_" + 37 | backend_name + 38 | std::string(SHARED_LIBRARY_SUFFIX); 39 | std::string error_msg; 40 | #ifdef _WIN32 41 | module_handle = LoadLibrary(backend_file_name.c_str()); 42 | if (!module_handle) { 43 | auto err = GetLastError(); 44 | LPTSTR msg_buf; 45 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 46 | FORMAT_MESSAGE_IGNORE_INSERTS, 47 | NULL, 48 | err, 49 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 50 | (LPTSTR)&msg_buf, 51 | 0, 52 | NULL); 53 | error_msg = msg_buf; 54 | LocalFree(msg_buf); 55 | } 56 | #else 57 | module_handle = dlopen(backend_file_name.c_str(), RTLD_LAZY); 58 | if (!module_handle) { 59 | error_msg = dlerror(); 60 | } 61 | #endif 62 | 63 | const std::string base_error_message = "Failed to load backend '" + backend_name + 64 | "' (in " + backend_file_name + ") due to: "; 65 | if (!module_handle) { 66 | std::cerr << base_error_message << error_msg << "\n" << std::flush; 67 | throw std::runtime_error(base_error_message + error_msg); 68 | } 69 | 70 | const std::string create_device_fn_name = "crtl_" + backend_name + "_create_device"; 71 | create_device_fn = get_fn(create_device_fn_name); 72 | if (!create_device_fn) { 73 | std::cerr << base_error_message << "Library did not contain function '" 74 | << create_device_fn_name << "'\n" 75 | << std::flush; 76 | throw std::runtime_error(base_error_message + 77 | "Library did not contain function '" + 78 | create_device_fn_name + "'"); 79 | } 80 | 81 | const std::string retain_fn_name = "crtl_" + backend_name + "_retain"; 82 | retain_fn = get_fn(retain_fn_name); 83 | if (!retain_fn) { 84 | std::cerr << base_error_message << "Library did not contain function '" 85 | << retain_fn_name << "'\n" 86 | << std::flush; 87 | throw std::runtime_error(base_error_message + 88 | "Library did not contain function '" + retain_fn_name + 89 | "'"); 90 | } 91 | 92 | const std::string release_fn_name = "crtl_" + backend_name + "_release"; 93 | release_fn = get_fn(release_fn_name); 94 | if (!release_fn) { 95 | std::cerr << base_error_message << "Library did not contain function '" 96 | << release_fn_name << "'\n" 97 | << std::flush; 98 | throw std::runtime_error(base_error_message + 99 | "Library did not contain function '" + release_fn_name + 100 | "'"); 101 | } 102 | } 103 | 104 | BackendPlugin::~BackendPlugin() 105 | { 106 | #ifdef _WIN32 107 | FreeLibrary(module_handle); 108 | #else 109 | dlclose(module_handle); 110 | #endif 111 | } 112 | 113 | Device *BackendPlugin::create_device() const 114 | { 115 | return create_device_fn(); 116 | } 117 | 118 | CRTL_ERROR BackendPlugin::retain(Device *d, CRTLAPIObject o) const 119 | { 120 | return retain_fn(d, o); 121 | } 122 | 123 | CRTL_ERROR BackendPlugin::release(Device *d, CRTLAPIObject o) const 124 | { 125 | return release_fn(d, o); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/crtl/core/backend_plugin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef _WIN32 4 | #include 5 | #else 6 | #include 7 | #endif 8 | 9 | #include 10 | #include "crtl/crtl.h" 11 | #include "device.h" 12 | 13 | namespace crtl { 14 | class CRTL_EXPORT BackendPlugin { 15 | using CreateDeviceFn = Device *(*)(); 16 | using RetainFn = CRTL_ERROR (*)(Device *, CRTLAPIObject); 17 | using ReleaseFn = CRTL_ERROR (*)(Device *, CRTLAPIObject); 18 | 19 | CRTL_DEVICE_API api = CRTL_DEVICE_API_UNKNOWN; 20 | 21 | #ifdef _WIN32 22 | HMODULE module_handle = 0; 23 | #else 24 | void *module_handle = nullptr; 25 | #endif 26 | 27 | CreateDeviceFn create_device_fn = nullptr; 28 | RetainFn retain_fn = nullptr; 29 | ReleaseFn release_fn = nullptr; 30 | 31 | public: 32 | BackendPlugin(CRTL_DEVICE_API api); 33 | 34 | ~BackendPlugin(); 35 | 36 | Device *create_device() const; 37 | 38 | // Retain/release not managed by the device so that we can also retain/release the 39 | // device 40 | CRTL_ERROR retain(Device *d, CRTLAPIObject o) const; 41 | 42 | CRTL_ERROR release(Device *d, CRTLAPIObject o) const; 43 | 44 | private: 45 | /* Load a function pointer from the shared library. Returns nullptr if the function 46 | * was not found 47 | */ 48 | template 49 | T get_fn(const std::string &fcn_name) 50 | { 51 | #ifdef _WIN32 52 | FARPROC fn = GetProcAddress(module_handle, fcn_name.c_str()); 53 | #else 54 | void *fn = dlsym(module_handle, fcn_name.c_str()); 55 | #endif 56 | return fn ? reinterpret_cast(fn) : nullptr; 57 | } 58 | }; 59 | } 60 | -------------------------------------------------------------------------------- /src/crtl/core/buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "api_object.h" 4 | #include "buffer_view.h" 5 | #include "crtl/crtl_enums.h" 6 | 7 | namespace crtl { 8 | 9 | /* A Buffer is a region of untyped memory allocated on the device or in 10 | * device-visible host memory. 11 | */ 12 | class Buffer : APIObject { 13 | CRTL_MEMORY_SPACE memory_space; 14 | size_t size_bytes; 15 | 16 | public: 17 | virtual ~Buffer() = default; 18 | 19 | std::shared_ptr make_view(); 20 | }; 21 | 22 | /* The BufferM template is a utility for backend implementations to enforce internal 23 | * compile time requirements about memory spaces 24 | */ 25 | template 26 | class BufferM : public Buffer { 27 | public: 28 | BufferM() = default; 29 | 30 | template 31 | std::shared_ptr> make_typed_view(); 32 | }; 33 | 34 | template 35 | template 36 | std::shared_ptr> BufferM::make_typed_view() 37 | { 38 | // TODO: validate the buffer memory space 39 | return nullptr; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/crtl/core/buffer_view.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "api_object.h" 5 | #include "crtl/crtl_enums.h" 6 | 7 | namespace crtl { 8 | 9 | class Buffer; 10 | 11 | /* A BufferView references a subregion of a buffer providing typed access to the memory. 12 | */ 13 | class BufferView : public APIObject { 14 | std::shared_ptr buffer; 15 | size_t offset_bytes = 0; 16 | size_t count = 0; 17 | CRTL_DATA_TYPE data_type = CRTL_TYPE_UNKNOWN; 18 | 19 | public: 20 | virtual ~BufferView() = default; 21 | }; 22 | 23 | /* The BufferViewT is a utility for backend implementations to provide typed access to the 24 | * view, templated on both the memory space and view type 25 | */ 26 | template 27 | class BufferViewT : public BufferView { 28 | public: 29 | // Doesn't make sense for device only memory 30 | // T* data(); 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/crtl/core/crtl_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "crtl/crtl_buffer.h" 2 | #include "device.h" 3 | 4 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_new_buffer(CRTLDevice device, 5 | CRTL_MEMORY_SPACE memory_space, 6 | CRTL_BUFFER_USAGE usages, 7 | size_t size_bytes, 8 | CRTLBuffer *buffer) 9 | { 10 | if (size_bytes == 0) { 11 | return CRTL_ERROR_INVALID_BUFFER_SIZE; 12 | } 13 | // TODO: need to filter invalid memory space/buffer usage combinations 14 | // Note: map write with readback and map read with upload heap should also be 15 | // considered invalid, device heap cannot be mapped,a buffer cannot be map read & map 16 | // write 17 | crtl::Device *d = reinterpret_cast(device); 18 | return d->new_buffer(memory_space, usages, size_bytes, buffer); 19 | } 20 | 21 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_new_buffer_view(CRTLDevice device, 22 | CRTLBuffer buffer, 23 | CRTL_DATA_TYPE type, 24 | size_t offset_bytes, 25 | size_t n_elements, 26 | CRTLBufferView *view) 27 | { 28 | crtl::Device *d = reinterpret_cast(device); 29 | return d->new_buffer_view(buffer, type, offset_bytes, n_elements, view); 30 | } 31 | 32 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_map_buffer_view(CRTLDevice device, 33 | CRTLBufferView view, 34 | CRTL_BUFFER_MAP_MODE map_mode, 35 | void **mapping) 36 | { 37 | // TODO: Buffer usage and map mode validation, cannot map a buffer that's not map 38 | // write for writing, can't map a non-map read one for reading 39 | // also have to check mapping isn't null 40 | crtl::Device *d = reinterpret_cast(device); 41 | return d->map_buffer_view(view, map_mode, mapping); 42 | } 43 | 44 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_unmap_buffer_view(CRTLDevice device, 45 | CRTLBufferView view) 46 | { 47 | crtl::Device *d = reinterpret_cast(device); 48 | return d->unmap_buffer_view(view); 49 | } 50 | -------------------------------------------------------------------------------- /src/crtl/core/crtl_device.cpp: -------------------------------------------------------------------------------- 1 | #include "crtl/crtl_device.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "backend_plugin.h" 7 | #include "device.h" 8 | 9 | std::array, CRTL_DEVICE_API_UNKNOWN> backends; 10 | 11 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_new_device(CRTL_DEVICE_API api, CRTLDevice *device) 12 | { 13 | if (!backends[api]) { 14 | try { 15 | backends[api] = std::make_unique(api); 16 | } catch (const std::runtime_error &e) { 17 | std::cerr << "Failed to load backend: " << e.what() << "\n"; 18 | // TODO: could return more specific errors from the backend plugin loader and 19 | // have more specific enums 20 | return CRTL_ERROR_BACKEND_LOADING_FAILED; 21 | } catch (...) { 22 | return CRTL_ERROR_BACKEND_LOADING_FAILED; 23 | } 24 | } 25 | *device = reinterpret_cast(backends[api]->create_device()); 26 | return CRTL_ERROR_NONE; 27 | } 28 | 29 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_get_device_api(CRTLDevice device, 30 | CRTL_DEVICE_API *api) 31 | { 32 | crtl::Device *d = reinterpret_cast(device); 33 | *api = d->device_api(); 34 | return CRTL_ERROR_NONE; 35 | } 36 | 37 | extern "C" CRTL_EXPORT CRTL_ERROR 38 | crtl_register_device_error_callback(CRTLDevice device, CRTLErrorCallback error_callback) 39 | { 40 | crtl::Device *d = reinterpret_cast(device); 41 | return d->register_error_callback(error_callback); 42 | } 43 | 44 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_retain(CRTLDevice device, CRTLAPIObject object) 45 | { 46 | crtl::Device *d = reinterpret_cast(device); 47 | return backends[d->device_api()]->retain(d, object); 48 | } 49 | 50 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_release(CRTLDevice device, CRTLAPIObject object) 51 | { 52 | crtl::Device *d = reinterpret_cast(device); 53 | return backends[d->device_api()]->release(d, object); 54 | } 55 | 56 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_get_native_handle(CRTLDevice device, 57 | CRTLAPIObject object, 58 | CRTLNativeHandle *native_handle) 59 | { 60 | crtl::Device *d = reinterpret_cast(device); 61 | return d->get_native_handle(object, native_handle); 62 | } 63 | -------------------------------------------------------------------------------- /src/crtl/core/crtl_event.cpp: -------------------------------------------------------------------------------- 1 | #include "crtl/crtl_event.h" 2 | #include "device.h" 3 | 4 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_new_event(CRTLDevice device, CRTLEvent *event) 5 | { 6 | crtl::Device *d = reinterpret_cast(device); 7 | return d->new_event(event); 8 | } 9 | 10 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_await_event(CRTLDevice device, CRTLEvent event) 11 | { 12 | crtl::Device *d = reinterpret_cast(device); 13 | return d->await_event(event); 14 | } 15 | -------------------------------------------------------------------------------- /src/crtl/core/crtl_geometry.cpp: -------------------------------------------------------------------------------- 1 | #include "crtl/crtl_geometry.h" 2 | #include "device.h" 3 | 4 | extern "C" CRTL_EXPORT CRTL_ERROR 5 | crtl_new_triangle_geometry(CRTLDevice device, 6 | CRTLBufferView vertices, 7 | CRTLBufferView indices, 8 | CRTL_GEOMETRY_FLAG flags, 9 | CRTLTriangleGeometry *geometry) 10 | { 11 | crtl::Device *d = reinterpret_cast(device); 12 | return d->new_triangle_geometry(vertices, indices, flags, geometry); 13 | } 14 | 15 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_new_renderable(CRTLDevice device, 16 | CRTLGeometry geometry, 17 | uint32_t n_ray_types, 18 | CRTLRenderable *renderable) 19 | { 20 | crtl::Device *d = reinterpret_cast(device); 21 | return d->new_renderable(geometry, n_ray_types, renderable); 22 | } 23 | 24 | extern "C" CRTL_EXPORT CRTL_ERROR 25 | crtl_set_renderable_shader_record(CRTLDevice device, 26 | CRTLRenderable renderable, 27 | uint32_t index, 28 | CRTLShaderRecord shader_record) 29 | { 30 | crtl::Device *d = reinterpret_cast(device); 31 | return d->set_renderable_shader_record(renderable, index, shader_record); 32 | } 33 | 34 | extern "C" CRTL_EXPORT CRTL_ERROR 35 | crtl_new_group(CRTLDevice device, 36 | uint32_t n_renderables, 37 | CRTL_ACCELERATION_STRUCTURE_BUILD_FLAG acceleration_structure_flags, 38 | CRTLGroup *group) 39 | { 40 | crtl::Device *d = reinterpret_cast(device); 41 | return d->new_group(n_renderables, acceleration_structure_flags, group); 42 | } 43 | 44 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_set_group_renderable(CRTLDevice device, 45 | CRTLGroup group, 46 | uint32_t index, 47 | CRTLRenderable renderable) 48 | { 49 | crtl::Device *d = reinterpret_cast(device); 50 | return d->set_group_renderable(group, index, renderable); 51 | } 52 | 53 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_new_instance(CRTLDevice device, 54 | CRTLGroup group, 55 | CRTL_INSTANCE_FLAG flags, 56 | CRTLInstance *instance) 57 | { 58 | crtl::Device *d = reinterpret_cast(device); 59 | return d->new_instance(group, flags, instance); 60 | } 61 | 62 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_set_instance_transform(CRTLDevice device, 63 | CRTLInstance instance, 64 | const float *transform_3x4) 65 | { 66 | crtl::Device *d = reinterpret_cast(device); 67 | return d->set_instance_transform(instance, transform_3x4); 68 | } 69 | 70 | extern "C" CRTL_EXPORT CRTL_ERROR 71 | crtl_new_scene(CRTLDevice device, 72 | uint32_t n_instances, 73 | uint32_t n_ray_types, 74 | CRTL_ACCELERATION_STRUCTURE_BUILD_FLAG acceleration_structure_flags, 75 | CRTLScene *scene) 76 | { 77 | crtl::Device *d = reinterpret_cast(device); 78 | return d->new_scene(n_instances, n_ray_types, acceleration_structure_flags, scene); 79 | } 80 | 81 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_set_scene_instance(CRTLDevice device, 82 | CRTLScene scene, 83 | uint32_t index, 84 | CRTLInstance instance) 85 | { 86 | crtl::Device *d = reinterpret_cast(device); 87 | return d->set_scene_instance(scene, index, instance); 88 | } 89 | -------------------------------------------------------------------------------- /src/crtl/core/crtl_parameter_block.cpp: -------------------------------------------------------------------------------- 1 | #include "crtl/crtl_parameter_block.h" 2 | #include "device.h" 3 | 4 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_set_parameter(CRTLDevice device, 5 | CRTLParameterBlock parameter_block, 6 | const char *name, 7 | CRTL_DATA_TYPE data_type, 8 | void *parameter) 9 | { 10 | crtl::Device *d = reinterpret_cast(device); 11 | return d->set_parameter(parameter_block, name, data_type, parameter); 12 | } 13 | -------------------------------------------------------------------------------- /src/crtl/core/crtl_rtpipeline.cpp: -------------------------------------------------------------------------------- 1 | #include "crtl/crtl_rtpipeline.h" 2 | #include "device.h" 3 | 4 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_new_rtpipeline(CRTLDevice device, 5 | CRTLShaderLibrary shader_library, 6 | uint32_t n_miss_records, 7 | CRTLRTPipeline *pipeline) 8 | { 9 | crtl::Device *d = reinterpret_cast(device); 10 | return d->new_rtpipeline(shader_library, n_miss_records, pipeline); 11 | } 12 | 13 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_set_raygen_record(CRTLDevice device, 14 | CRTLRTPipeline pipeline, 15 | CRTLShaderRecord raygen_record) 16 | { 17 | crtl::Device *d = reinterpret_cast(device); 18 | return d->set_raygen_record(pipeline, raygen_record); 19 | } 20 | 21 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_set_miss_record(CRTLDevice device, 22 | CRTLRTPipeline pipeline, 23 | uint32_t index, 24 | CRTLShaderRecord miss_record) 25 | { 26 | crtl::Device *d = reinterpret_cast(device); 27 | return d->set_miss_record(pipeline, index, miss_record); 28 | } 29 | 30 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_set_scene(CRTLDevice device, 31 | CRTLRTPipeline pipeline, 32 | CRTLScene scene) 33 | { 34 | crtl::Device *d = reinterpret_cast(device); 35 | return d->set_scene(pipeline, scene); 36 | } 37 | 38 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_build_shader_table(CRTLDevice device, 39 | CRTLRTPipeline pipeline) 40 | { 41 | crtl::Device *d = reinterpret_cast(device); 42 | return d->build_shader_table(pipeline); 43 | } 44 | -------------------------------------------------------------------------------- /src/crtl/core/crtl_shader.cpp: -------------------------------------------------------------------------------- 1 | #include "crtl/crtl_shader.h" 2 | #include "device.h" 3 | 4 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_new_shader_library( 5 | CRTLDevice device, const char *library_src, CRTLShaderLibrary *shader_library) 6 | { 7 | crtl::Device *d = reinterpret_cast(device); 8 | return d->new_shader_library(library_src, shader_library); 9 | } 10 | 11 | extern "C" CRTL_EXPORT CRTL_ERROR 12 | crtl_new_global_parameter_block(CRTLDevice device, 13 | CRTLShaderLibrary shader_library, 14 | CRTLGlobalParameterBlock *parameter_block) 15 | { 16 | crtl::Device *d = reinterpret_cast(device); 17 | return d->new_global_parameter_block(shader_library, parameter_block); 18 | } 19 | 20 | extern "C" CRTL_EXPORT CRTL_ERROR 21 | crtl_get_shader_entry_point(CRTLDevice device, 22 | CRTLShaderLibrary shader_library, 23 | const char *entry_point_name, 24 | CRTLShaderEntryPoint *entry_point) 25 | { 26 | crtl::Device *d = reinterpret_cast(device); 27 | return d->get_shader_entry_point(shader_library, entry_point_name, entry_point); 28 | } 29 | 30 | extern "C" CRTL_EXPORT CRTL_ERROR 31 | crtl_new_hitgroup_record(CRTLDevice device, 32 | CRTLShaderEntryPoint closest_hit, 33 | CRTLShaderEntryPoint intersection_optional, 34 | CRTLShaderEntryPoint any_hit_optional, 35 | CRTLHitGroupRecord *shader_record) 36 | { 37 | crtl::Device *d = reinterpret_cast(device); 38 | return d->new_hitgroup_record( 39 | closest_hit, intersection_optional, any_hit_optional, shader_record); 40 | } 41 | 42 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_new_miss_record(CRTLDevice device, 43 | CRTLShaderEntryPoint miss, 44 | CRTLMissRecord *shader_record) 45 | { 46 | crtl::Device *d = reinterpret_cast(device); 47 | return d->new_miss_record(miss, shader_record); 48 | } 49 | 50 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_new_raygen_record(CRTLDevice device, 51 | CRTLShaderEntryPoint raygen, 52 | CRTLRaygenRecord *shader_record) 53 | { 54 | crtl::Device *d = reinterpret_cast(device); 55 | return d->new_raygen_record(raygen, shader_record); 56 | } 57 | 58 | extern "C" CRTL_EXPORT CRTL_ERROR 59 | crtl_new_shader_record_parameter_block(CRTLDevice device, 60 | CRTLShaderRecord shader_record, 61 | CRTLShaderRecordParameterBlock *parameter_block) 62 | { 63 | crtl::Device *d = reinterpret_cast(device); 64 | return d->new_shader_record_parameter_block(shader_record, parameter_block); 65 | } 66 | 67 | extern "C" CRTL_EXPORT CRTL_ERROR 68 | crtl_set_shader_record_parameter_block(CRTLDevice device, 69 | CRTLShaderRecord shader_record, 70 | CRTLShaderRecordParameterBlock parameter_block) 71 | { 72 | crtl::Device *d = reinterpret_cast(device); 73 | return d->set_shader_record_parameter_block(shader_record, parameter_block); 74 | } 75 | -------------------------------------------------------------------------------- /src/crtl/core/crtl_texture.cpp: -------------------------------------------------------------------------------- 1 | #include "crtl/crtl_texture.h" 2 | #include "device.h" 3 | 4 | extern "C" CRTL_EXPORT CRTL_ERROR crtl_new_texture(CRTLDevice device, 5 | CRTL_TEXTURE_TYPE texture_type, 6 | CRTL_IMAGE_FORMAT format, 7 | CRTL_IMAGE_USAGE usages, 8 | const uint32_t dimensions[3], 9 | CRTLTexture *texture) 10 | { 11 | crtl::Device *d = reinterpret_cast(device); 12 | return d->new_texture(texture_type, format, usages, dimensions, texture); 13 | } 14 | -------------------------------------------------------------------------------- /src/crtl/core/device.cpp: -------------------------------------------------------------------------------- 1 | #include "device.h" 2 | 3 | namespace crtl { 4 | 5 | CRTL_ERROR Device::register_error_callback(CRTLErrorCallback ec) 6 | { 7 | error_callback = ec; 8 | return CRTL_ERROR_NONE; 9 | } 10 | 11 | void Device::report_error(CRTL_ERROR error, const std::string &message) 12 | { 13 | if (error_callback) { 14 | error_callback(error, message.c_str()); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (WIN32) 2 | option(CRTL_ENABLE_DXR "Enable the DXR backend for ChameleonRT-Lang" ON) 3 | else() 4 | option(CRTL_ENABLE_DXR "Enable the DXR backend for ChameleonRT-Lang" OFF) 5 | endif() 6 | 7 | if (NOT CRTL_ENABLE_DXR) 8 | return() 9 | endif() 10 | 11 | find_package(D3D12 REQUIRED) 12 | 13 | add_library(crtl_dxr SHARED 14 | crtl_dxr.cpp 15 | dxr_device.cpp 16 | 17 | #dxr_blas.cpp 18 | #dxr_tlas.cpp 19 | dxr_descriptor_heap.cpp 20 | dxr_resource.cpp 21 | dxr_root_parameter.cpp 22 | dxr_root_signature.cpp 23 | dxr_utils.cpp 24 | dxr_enums.cpp 25 | 26 | dxr_buffer.cpp 27 | dxr_buffer_view.cpp 28 | dxr_texture.cpp 29 | 30 | dxr_queue.cpp 31 | dxr_command_allocator.cpp 32 | dxr_command_buffer.cpp 33 | dxr_event.cpp 34 | 35 | dxr_triangle_geometry.cpp 36 | dxr_renderable.cpp 37 | dxr_group.cpp 38 | dxr_instance.cpp 39 | dxr_scene.cpp 40 | 41 | dxr_parameter_block.cpp 42 | dxr_global_parameter_block.cpp 43 | dxr_shader_record_parameter_block.cpp 44 | dxr_shader_library.cpp 45 | dxr_shader_entry_point.cpp 46 | dxr_shader_record.cpp 47 | dxr_shader_parameter_desc.cpp 48 | #dxr_rtpipeline.cpp 49 | 50 | # TODO: cross platform windowing interaction is a different 51 | # question, should allow getting native handles to objects in the API 52 | # The windowing stuff can be in a separate CRTL utility that uses 53 | # this native API handling 54 | #dxdisplay.cpp 55 | ) 56 | 57 | set_target_properties(crtl_dxr PROPERTIES 58 | CXX_STANDARD 17 59 | CXX_STANDARD_REQUIRED ON) 60 | 61 | target_include_directories(crtl_dxr PRIVATE 62 | ${D3D12_INCLUDE_DIRS} 63 | ${CMAKE_CURRENT_BINARY_DIR} 64 | ${CMAKE_CURRENT_LIST_DIR}) 65 | 66 | target_link_libraries(crtl_dxr PRIVATE 67 | crtl 68 | crtl_compiler 69 | ${D3D12_LIBRARIES}) 70 | 71 | generate_export_header(crtl_dxr) 72 | 73 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/crtl_dxr.cpp: -------------------------------------------------------------------------------- 1 | #include "crtl/crtl.h" 2 | #include "crtl_dxr_export.h" 3 | #include "dxr_device.h" 4 | 5 | extern "C" CRTL_DXR_EXPORT crtl::Device *crtl_dxr_create_device() 6 | { 7 | auto *d = new crtl::dxr::DXRDevice(); 8 | d->app_ref_count = 1; 9 | return d; 10 | } 11 | 12 | extern "C" CRTL_DXR_EXPORT CRTL_ERROR crtl_dxr_retain(crtl::Device *d, CRTLAPIObject o) 13 | { 14 | crtl::APIObject *obj = reinterpret_cast(o); 15 | if (!obj) { 16 | return CRTL_ERROR_OBJECT_NULL; 17 | } 18 | 19 | // Check if we're retaining/releasing a device 20 | { 21 | crtl::dxr::DXRDevice *obj_device = dynamic_cast(obj); 22 | if (obj_device) { 23 | obj_device->app_ref_count++; 24 | return CRTL_ERROR_NONE; 25 | } 26 | } 27 | 28 | // Regular API object's app ref counts are managed by their device 29 | crtl::dxr::DXRDevice *dxd = dynamic_cast(d); 30 | return dxd->retain(obj); 31 | } 32 | 33 | extern "C" CRTL_DXR_EXPORT CRTL_ERROR crtl_dxr_release(crtl::Device *d, CRTLAPIObject o) 34 | { 35 | crtl::APIObject *obj = reinterpret_cast(o); 36 | if (!obj) { 37 | return CRTL_ERROR_OBJECT_NULL; 38 | } 39 | 40 | // Check if we're retaining/releasing a device 41 | { 42 | crtl::dxr::DXRDevice *obj_device = dynamic_cast(obj); 43 | if (obj_device) { 44 | obj_device->app_ref_count--; 45 | if (obj_device->app_ref_count == 0) { 46 | delete obj_device; 47 | } 48 | return CRTL_ERROR_NONE; 49 | } 50 | } 51 | 52 | // Regular API object's app ref counts are managed by their device 53 | crtl::dxr::DXRDevice *dxd = dynamic_cast(d); 54 | return dxd->release(obj); 55 | } 56 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_blas.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "crtl_dxr_export.h" 6 | #include "dxr_buffer.h" 7 | #include "dxr_geometry.h" 8 | #include "dxr_utils.h" 9 | 10 | namespace crtl { 11 | namespace dxr { 12 | 13 | // TODO: This will be used by the group, needs to support mix of triangle geometries and 14 | // user geometries 15 | class CRTL_DXR_EXPORT BottomLevelBVH { 16 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS build_flags; 17 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC post_build_info_desc = { 18 | 0}; 19 | Buffer scratch, post_build_info, post_build_info_readback; 20 | 21 | std::vector geom_descs; 22 | 23 | public: 24 | std::vector geometries; 25 | Buffer bvh; 26 | 27 | BottomLevelBVH() = default; 28 | 29 | BottomLevelBVH( 30 | std::vector &geometries, 31 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS build_flags = 32 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE | 33 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_COMPACTION); 34 | 35 | /* After calling build the commands are placed in the command list, with a 36 | * UAV barrier to wait on the completion of the build before other commands are 37 | * run, but does not submit the command list. 38 | */ 39 | void enqeue_build(ID3D12Device5 *device, ID3D12GraphicsCommandList4 *cmd_list); 40 | 41 | /* Enqueue the BVH compaction copy if the BVH was built with compaction enabled. 42 | * The BVH build must have been enqueued and completed so that the post build info is 43 | * available 44 | */ 45 | void enqueue_compaction(ID3D12Device5 *device, ID3D12GraphicsCommandList4 *cmd_list); 46 | 47 | /* Finalize the BVH build structures to release any scratch space. 48 | * Must call after enqueue compaction if performing compaction, otherwise 49 | * this can be called after the work from enqueue build has been finished 50 | */ 51 | void finalize(); 52 | 53 | ID3D12Resource *operator->(); 54 | ID3D12Resource *get(); 55 | }; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "dxr_buffer.h" 2 | #include "dxr_enums.h" 3 | #include "dxr_utils.h" 4 | #include "error.h" 5 | 6 | namespace crtl { 7 | namespace dxr { 8 | 9 | Buffer::Buffer(DXRDevice *device, 10 | CRTL_MEMORY_SPACE memory_space, 11 | CRTL_BUFFER_USAGE usages, 12 | size_t sz_bytes) 13 | : size_bytes(sz_bytes), buffer_usages(usages) 14 | { 15 | if (size_bytes == 0) { 16 | throw Error("Buffer size must be > 0", CRTL_ERROR_INVALID_BUFFER_SIZE); 17 | } 18 | 19 | // Note: MAP_WRITE will require MEMORY_SPACE_UPLOAD at the higher API validation level 20 | // similarly, MAP_READ will require MEMORY_SPACE_READBACK 21 | const auto heap_props = memory_space_to_heap_properties(memory_space); 22 | heap_type = heap_props.Type; 23 | 24 | // TODO: for resource states: 25 | // this is a list of the states we want to use the resource in so it might contain 26 | // conflicting states (copy dst and src) so some filtering of the states needs to be 27 | // done here to pick which one we're going to make the resource in. Upload/readback 28 | // heaps also enforce requirements on the state the resource has to be created in 29 | if (heap_type == D3D12_HEAP_TYPE_UPLOAD) { 30 | res_state = D3D12_RESOURCE_STATE_GENERIC_READ; 31 | } else if (heap_type == D3D12_HEAP_TYPE_READBACK) { 32 | res_state = D3D12_RESOURCE_STATE_COPY_DEST; 33 | } else { 34 | if (usages & CRTL_BUFFER_USAGE_SHADER_READ_WRITE) { 35 | res_flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; 36 | res_state = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; 37 | } else if (usages & CRTL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { 38 | res_flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; 39 | res_state = D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE; 40 | } else if (usages & CRTL_BUFFER_USAGE_SHADER_READ) { 41 | res_state = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; 42 | } else if (usages & CRTL_BUFFER_USAGE_COPY_DST) { 43 | res_state = D3D12_RESOURCE_STATE_COPY_DEST; 44 | } else if (usages & CRTL_BUFFER_USAGE_COPY_DST) { 45 | res_state = D3D12_RESOURCE_STATE_COPY_SOURCE; 46 | } else { 47 | throw Error("Unhandled/supported buffer usage!?", CRTL_ERROR_UNKNOWN); 48 | } 49 | } 50 | const D3D12_RESOURCE_DESC desc = res_desc(); 51 | CHECK_ERR(device->get_d3d12_device()->CreateCommittedResource(&heap_props, 52 | D3D12_HEAP_FLAG_NONE, 53 | &desc, 54 | res_state, 55 | nullptr, 56 | IID_PPV_ARGS(&res))); 57 | } 58 | 59 | size_t Buffer::size() const 60 | { 61 | return size_bytes; 62 | } 63 | 64 | D3D12_GPU_VIRTUAL_ADDRESS Buffer::gpu_virtual_address() 65 | { 66 | return get()->GetGPUVirtualAddress(); 67 | } 68 | 69 | D3D12_RESOURCE_DESC Buffer::res_desc() 70 | { 71 | D3D12_RESOURCE_DESC desc = {}; 72 | desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; 73 | desc.Width = size_bytes; 74 | desc.Height = 1; 75 | desc.DepthOrArraySize = 1; 76 | desc.MipLevels = 1; 77 | desc.Format = DXGI_FORMAT_UNKNOWN; 78 | desc.SampleDesc.Count = 1; 79 | desc.SampleDesc.Quality = 0; 80 | desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; 81 | desc.Flags = res_flags; 82 | return desc; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "api_object.h" 4 | #include "crtl/crtl_enums.h" 5 | #include "crtl_dxr_export.h" 6 | #include "dxr_device.h" 7 | #include "dxr_resource.h" 8 | #include "dxr_utils.h" 9 | 10 | namespace crtl { 11 | namespace dxr { 12 | 13 | class CRTL_DXR_EXPORT Buffer : public crtl::APIObject, public Resource { 14 | size_t size_bytes = 0; 15 | D3D12_RESOURCE_FLAGS res_flags = D3D12_RESOURCE_FLAG_NONE; 16 | // The supported usages for this buffer 17 | CRTL_BUFFER_USAGE buffer_usages = CRTL_BUFFER_USAGE_SHADER_READ; 18 | 19 | public: 20 | Buffer(DXRDevice *device, 21 | CRTL_MEMORY_SPACE memory_space, 22 | CRTL_BUFFER_USAGE usages, 23 | size_t size_bytes); 24 | 25 | size_t size() const; 26 | 27 | D3D12_GPU_VIRTUAL_ADDRESS gpu_virtual_address(); 28 | 29 | private: 30 | D3D12_RESOURCE_DESC res_desc(); 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_buffer_view.cpp: -------------------------------------------------------------------------------- 1 | #include "dxr_buffer_view.h" 2 | #include "error.h" 3 | #include "util.h" 4 | 5 | namespace crtl { 6 | namespace dxr { 7 | 8 | BufferView::BufferView(std::shared_ptr buffer, 9 | CRTL_DATA_TYPE data_type, 10 | size_t offset_bytes, 11 | size_t size) 12 | : buffer(buffer), 13 | data_type(data_type), 14 | offset_bytes(offset_bytes), 15 | size(size), 16 | mapping(nullptr), 17 | mapped_mode(CRTL_BUFFER_MAP_MODE_READ) 18 | { 19 | } 20 | 21 | void *BufferView::map(CRTL_BUFFER_MAP_MODE map_mode) 22 | { 23 | if (mapping) { 24 | throw Error("Attempt to map a BufferView that is already mapped", 25 | CRTL_ERROR_BUFFER_VIEW_ALREADY_MAPPED); 26 | } 27 | 28 | // Note: map mode/buffer usage validation will be handled higher up in the API 29 | mapped_mode = map_mode; 30 | D3D12_RANGE read_range; 31 | if (map_mode == CRTL_BUFFER_MAP_MODE_READ) { 32 | read_range.Begin = offset_bytes; 33 | read_range.End = offset_bytes + size_bytes(); 34 | } else { 35 | read_range.Begin = 0; 36 | read_range.End = 0; 37 | } 38 | CHECK_ERR(buffer->get()->Map(0, &read_range, reinterpret_cast(&mapping))); 39 | 40 | // DX12 doesn't offset the mapping, so apply the offset now to return the 41 | // region the app expects 42 | mapping += offset_bytes; 43 | return mapping; 44 | } 45 | 46 | void BufferView::unmap() 47 | { 48 | if (!mapping) { 49 | throw Error("Attempt to unmap a BufferView that is not mapped", 50 | CRTL_ERROR_BUFFER_VIEW_NOT_MAPPED); 51 | } 52 | 53 | D3D12_RANGE written_range; 54 | if (mapped_mode == CRTL_BUFFER_MAP_MODE_WRITE) { 55 | written_range.Begin = offset_bytes; 56 | written_range.End = offset_bytes + size_bytes(); 57 | } else { 58 | written_range.Begin = 0; 59 | written_range.End = 0; 60 | } 61 | buffer->get()->Unmap(0, &written_range); 62 | mapping = nullptr; 63 | } 64 | 65 | size_t BufferView::size_bytes() 66 | { 67 | return size * crtl::data_type_size(data_type); 68 | } 69 | 70 | D3D12_GPU_VIRTUAL_ADDRESS BufferView::gpu_virtual_address() 71 | { 72 | return buffer->gpu_virtual_address() + offset_bytes; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_buffer_view.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "crtl_dxr_export.h" 5 | #include "dxr_buffer.h" 6 | 7 | namespace crtl { 8 | namespace dxr { 9 | 10 | class CRTL_DXR_EXPORT BufferView : public crtl::APIObject { 11 | std::shared_ptr buffer; 12 | CRTL_DATA_TYPE data_type; 13 | 14 | size_t offset_bytes; 15 | size_t size; 16 | 17 | uint8_t *mapping; 18 | CRTL_BUFFER_MAP_MODE mapped_mode; 19 | 20 | public: 21 | BufferView(std::shared_ptr buffer, 22 | CRTL_DATA_TYPE data_type, 23 | size_t offset_bytes, 24 | size_t size); 25 | 26 | void *map(CRTL_BUFFER_MAP_MODE map_mode); 27 | 28 | void unmap(); 29 | 30 | size_t size_bytes(); 31 | 32 | D3D12_GPU_VIRTUAL_ADDRESS gpu_virtual_address(); 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_command_allocator.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dxr_command_allocator.h" 4 | 5 | namespace crtl { 6 | namespace dxr { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_command_allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "api_object.h" 4 | #include "crtl_dxr_export.h" 5 | #include "dxr_utils.h" 6 | 7 | namespace crtl { 8 | namespace dxr { 9 | 10 | class CRTL_DXR_EXPORT CommandAllocator : public crtl::APIObject { 11 | public: 12 | // TODO 13 | }; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_command_buffer.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dxr_command_buffer.h" 4 | 5 | namespace crtl { 6 | namespace dxr { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_command_buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "api_object.h" 4 | #include "crtl_dxr_export.h" 5 | #include "dxr_utils.h" 6 | 7 | namespace crtl { 8 | namespace dxr { 9 | 10 | class CRTL_DXR_EXPORT CommandBuffer : public crtl::APIObject { 11 | public: 12 | // TODO 13 | }; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_descriptor_heap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "crtl_dxr_export.h" 6 | #include "dxr_root_parameter.h" 7 | #include "dxr_utils.h" 8 | 9 | namespace crtl { 10 | namespace dxr { 11 | 12 | class DescriptorHeap; 13 | 14 | class CRTL_DXR_EXPORT DescriptorHeapBuilder { 15 | std::vector ranges; 16 | 17 | void add_range(D3D12_DESCRIPTOR_RANGE_TYPE type, 18 | uint32_t size, 19 | uint32_t base_register, 20 | uint32_t space); 21 | 22 | bool contains_range_type(D3D12_DESCRIPTOR_RANGE_TYPE type); 23 | uint32_t num_descriptors(); 24 | 25 | public: 26 | // TODO: We can autocompute the table offsets based on the order that add_* is called 27 | // if we use the root sig to also guide the desc. heap write 28 | // TODO: Each range can be assigned a name 29 | DescriptorHeapBuilder &add_srv_range(uint32_t size, 30 | uint32_t base_register, 31 | uint32_t space); 32 | DescriptorHeapBuilder &add_uav_range(uint32_t size, 33 | uint32_t base_register, 34 | uint32_t space); 35 | DescriptorHeapBuilder &add_cbv_range(uint32_t size, 36 | uint32_t base_register, 37 | uint32_t space); 38 | DescriptorHeapBuilder &add_sampler_range(uint32_t size, 39 | uint32_t base_register, 40 | uint32_t space); 41 | 42 | DescriptorHeap create(ID3D12Device *device); 43 | }; 44 | 45 | class CRTL_DXR_EXPORT DescriptorHeap : public RootParam { 46 | D3D12_DESCRIPTOR_HEAP_DESC desc = {0}; 47 | std::vector ranges; 48 | Microsoft::WRL::ComPtr heap = nullptr; 49 | 50 | friend class DescriptorHeapBuilder; 51 | 52 | DescriptorHeap(D3D12_DESCRIPTOR_HEAP_DESC desc, 53 | std::vector ranges, 54 | Microsoft::WRL::ComPtr heap); 55 | 56 | public: 57 | DescriptorHeap() = default; 58 | 59 | // TODO: Root param should be separated from the descriptor heap, since here the root 60 | // param returned is just a view of the whole table 61 | D3D12_ROOT_PARAMETER root_param() const; 62 | D3D12_GPU_DESCRIPTOR_HANDLE gpu_desc_handle(); 63 | D3D12_CPU_DESCRIPTOR_HANDLE cpu_desc_handle(); 64 | 65 | ID3D12DescriptorHeap *operator->(); 66 | ID3D12DescriptorHeap *get(); 67 | }; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_enums.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dxr_enums.h" 4 | 5 | namespace crtl { 6 | namespace dxr { 7 | 8 | const D3D12_HEAP_PROPERTIES UPLOAD_HEAP_PROPS = { 9 | D3D12_HEAP_TYPE_UPLOAD, 10 | D3D12_CPU_PAGE_PROPERTY_UNKNOWN, 11 | D3D12_MEMORY_POOL_UNKNOWN, 12 | 0, 13 | 0, 14 | }; 15 | 16 | const D3D12_HEAP_PROPERTIES DEVICE_HEAP_PROPS = { 17 | D3D12_HEAP_TYPE_DEFAULT, 18 | D3D12_CPU_PAGE_PROPERTY_UNKNOWN, 19 | D3D12_MEMORY_POOL_UNKNOWN, 20 | 0, 21 | 0, 22 | }; 23 | 24 | const D3D12_HEAP_PROPERTIES READBACK_HEAP_PROPS = { 25 | D3D12_HEAP_TYPE_READBACK, 26 | D3D12_CPU_PAGE_PROPERTY_UNKNOWN, 27 | D3D12_MEMORY_POOL_UNKNOWN, 28 | 0, 29 | 0, 30 | }; 31 | 32 | CRTL_DXR_EXPORT D3D12_HEAP_PROPERTIES 33 | memory_space_to_heap_properties(CRTL_MEMORY_SPACE memory_space) 34 | { 35 | switch (memory_space) { 36 | case CRTL_MEMORY_SPACE_DEVICE: 37 | return DEVICE_HEAP_PROPS; 38 | case CRTL_MEMORY_SPACE_READBACK: 39 | return READBACK_HEAP_PROPS; 40 | case CRTL_MEMORY_SPACE_UPLOAD: 41 | return UPLOAD_HEAP_PROPS; 42 | default: 43 | return DEVICE_HEAP_PROPS; 44 | } 45 | } 46 | 47 | CRTL_DXR_EXPORT DXGI_FORMAT image_format_to_dxgi_format(CRTL_IMAGE_FORMAT image_format) 48 | { 49 | switch (image_format) { 50 | case CRTL_IMAGE_FORMAT_R8G8B8A8_UNORM: 51 | return DXGI_FORMAT_R8G8B8A8_UNORM; 52 | case CRTL_IMAGE_FORMAT_R8G8B8A8_UNORM_SRGB: 53 | return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; 54 | case CRTL_IMAGE_FORMAT_R32G32B32A32_FLOAT: 55 | return DXGI_FORMAT_R32G32B32A32_FLOAT; 56 | default: 57 | return DXGI_FORMAT_UNKNOWN; 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_enums.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "crtl/crtl_enums.h" 4 | #include "crtl_dxr_export.h" 5 | #include "dxr_utils.h" 6 | 7 | namespace crtl { 8 | namespace dxr { 9 | 10 | // TODO: Here a bunch of mappers from CRTL enum values to DXR 11 | 12 | CRTL_DXR_EXPORT D3D12_HEAP_PROPERTIES 13 | memory_space_to_heap_properties(CRTL_MEMORY_SPACE memory_space); 14 | 15 | CRTL_DXR_EXPORT DXGI_FORMAT image_format_to_dxgi_format(CRTL_IMAGE_FORMAT image_format); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_event.cpp: -------------------------------------------------------------------------------- 1 | #include "dxr_event.h" 2 | 3 | namespace crtl { 4 | namespace dxr { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_event.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "api_object.h" 4 | #include "crtl_dxr_export.h" 5 | #include "dxr_resource.h" 6 | #include "dxr_utils.h" 7 | 8 | namespace crtl { 9 | namespace dxr { 10 | class CRTL_DXR_EXPORT Event : public crtl::APIObject { 11 | // TODO 12 | }; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_geometry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "api_object.h" 4 | #include "crtl_dxr_export.h" 5 | #include "dxr_utils.h" 6 | 7 | namespace crtl { 8 | namespace dxr { 9 | 10 | class CRTL_DXR_EXPORT Geometry : public crtl::APIObject { 11 | public: 12 | D3D12_RAYTRACING_GEOMETRY_DESC desc = {}; 13 | 14 | virtual ~Geometry() = default; 15 | 16 | // num prims method, etc 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_global_parameter_block.cpp: -------------------------------------------------------------------------------- 1 | #include "dxr_global_parameter_block.h" 2 | 3 | namespace crtl { 4 | namespace dxr { 5 | 6 | // TODO 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_global_parameter_block.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "crtl_dxr_export.h" 4 | #include "dxr_parameter_block.h" 5 | 6 | namespace crtl { 7 | namespace dxr { 8 | 9 | class CRTL_DXR_EXPORT GlobalParameterBlock : public ParameterBlock { 10 | public: 11 | // TODO 12 | 13 | void set_parameter(const std::string &name, 14 | CRTL_DATA_TYPE data_type, 15 | void *parameter) override 16 | { 17 | } 18 | 19 | void set_parameter(const std::string &name, 20 | CRTL_DATA_TYPE data_type, 21 | const std::shared_ptr ¶meter) override 22 | { 23 | } 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_group.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dxr_group.h" 4 | 5 | namespace crtl { 6 | namespace dxr { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_group.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "api_object.h" 4 | #include "crtl_dxr_export.h" 5 | #include "dxr_utils.h" 6 | 7 | namespace crtl { 8 | namespace dxr { 9 | 10 | class CRTL_DXR_EXPORT Group : public crtl::APIObject { 11 | public: 12 | // TODO 13 | }; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_instance.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dxr_instance.h" 4 | 5 | namespace crtl { 6 | namespace dxr { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_instance.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "api_object.h" 4 | #include "crtl_dxr_export.h" 5 | #include "dxr_utils.h" 6 | 7 | namespace crtl { 8 | namespace dxr { 9 | 10 | class CRTL_DXR_EXPORT Instance : public crtl::APIObject { 11 | public: 12 | // TODO 13 | // the transform, the renderable 14 | }; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_parameter_block.cpp: -------------------------------------------------------------------------------- 1 | #include "dxr_parameter_block.h" 2 | 3 | namespace crtl { 4 | namespace dxr { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_parameter_block.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "api_object.h" 4 | #include "crtl/crtl_enums.h" 5 | #include "crtl_dxr_export.h" 6 | #include "dxr_buffer_view.h" 7 | #include "dxr_utils.h" 8 | 9 | namespace crtl { 10 | namespace dxr { 11 | 12 | class CRTL_DXR_EXPORT ParameterBlock : public crtl::APIObject { 13 | public: 14 | virtual ~ParameterBlock() = default; 15 | 16 | virtual void set_parameter(const std::string &name, 17 | CRTL_DATA_TYPE data_type, 18 | void *parameter) = 0; 19 | 20 | virtual void set_parameter(const std::string &name, 21 | CRTL_DATA_TYPE data_type, 22 | const std::shared_ptr ¶meter) = 0; 23 | }; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_queue.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dxr_queue.h" 4 | 5 | namespace crtl { 6 | namespace dxr { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_queue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "api_object.h" 4 | #include "crtl_dxr_export.h" 5 | #include "dxr_utils.h" 6 | 7 | namespace crtl { 8 | namespace dxr { 9 | 10 | class CRTL_DXR_EXPORT Queue : public crtl::APIObject { 11 | public: 12 | // TODO 13 | }; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_renderable.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dxr_renderable.h" 4 | 5 | namespace crtl { 6 | namespace dxr { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_renderable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "api_object.h" 4 | #include "crtl_dxr_export.h" 5 | #include "dxr_utils.h" 6 | 7 | namespace crtl { 8 | namespace dxr { 9 | 10 | class CRTL_DXR_EXPORT Renderable : public crtl::APIObject { 11 | public: 12 | // TODO 13 | }; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_resource.cpp: -------------------------------------------------------------------------------- 1 | #include "dxr_resource.h" 2 | 3 | namespace crtl { 4 | namespace dxr { 5 | 6 | Resource::~Resource() {} 7 | 8 | ID3D12Resource *Resource::operator->() 9 | { 10 | return get(); 11 | } 12 | const ID3D12Resource *Resource::operator->() const 13 | { 14 | return get(); 15 | } 16 | ID3D12Resource *Resource::get() 17 | { 18 | return res.Get(); 19 | } 20 | const ID3D12Resource *Resource::get() const 21 | { 22 | return res.Get(); 23 | } 24 | D3D12_HEAP_TYPE Resource::heap() const 25 | { 26 | return heap_type; 27 | } 28 | D3D12_RESOURCE_STATES Resource::state() const 29 | { 30 | return res_state; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_resource.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "crtl_dxr_export.h" 4 | #include "dxr_utils.h" 5 | 6 | namespace crtl { 7 | namespace dxr { 8 | 9 | class CRTL_DXR_EXPORT Resource { 10 | protected: 11 | Microsoft::WRL::ComPtr res = nullptr; 12 | D3D12_HEAP_TYPE heap_type; 13 | // TODO: Won't need to track these resource states with enhanced barriers, 14 | // but will need to track some usage info, or at least the supported usage info 15 | // that a resource was created with 16 | D3D12_RESOURCE_STATES res_state; 17 | 18 | friend D3D12_RESOURCE_BARRIER barrier_transition(Resource &res, 19 | D3D12_RESOURCE_STATES after); 20 | 21 | public: 22 | virtual ~Resource(); 23 | 24 | ID3D12Resource *operator->(); 25 | const ID3D12Resource *operator->() const; 26 | 27 | ID3D12Resource *get(); 28 | const ID3D12Resource *get() const; 29 | 30 | D3D12_HEAP_TYPE heap() const; 31 | 32 | D3D12_RESOURCE_STATES state() const; 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_root_parameter.cpp: -------------------------------------------------------------------------------- 1 | #include "dxr_root_parameter.h" 2 | #include "util.h" 3 | 4 | namespace crtl { 5 | namespace dxr { 6 | 7 | using Microsoft::WRL::ComPtr; 8 | RootParam::RootParam(D3D12_ROOT_PARAMETER param, const std::string &name) 9 | : param(param), name(name) 10 | { 11 | } 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_root_parameter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "crtl_dxr_export.h" 5 | #include "dxr_utils.h" 6 | 7 | namespace crtl { 8 | namespace dxr { 9 | 10 | class CRTL_DXR_EXPORT RootParam { 11 | public: 12 | D3D12_ROOT_PARAMETER param = {}; 13 | std::string name; 14 | size_t offset = 0; 15 | size_t size = 0; 16 | 17 | RootParam() = default; 18 | RootParam(D3D12_ROOT_PARAMETER param, const std::string &name); 19 | }; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_root_signature.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "crtl_dxr_export.h" 7 | #include "dxr_descriptor_heap.h" 8 | #include "dxr_root_parameter.h" 9 | #include "dxr_utils.h" 10 | #include "parallel_hashmap/phmap.h" 11 | 12 | namespace crtl { 13 | namespace dxr { 14 | 15 | class RootSignature; 16 | class RTPipelineBuilder; 17 | class RTPipeline; 18 | 19 | class CRTL_DXR_EXPORT RootSignatureBuilder { 20 | D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE; 21 | std::vector params; 22 | 23 | void add_descriptor(D3D12_ROOT_PARAMETER_TYPE desc_type, 24 | const std::string &name, 25 | uint32_t shader_register, 26 | uint32_t space); 27 | 28 | public: 29 | static RootSignatureBuilder global(); 30 | 31 | static RootSignatureBuilder local(); 32 | 33 | RootSignatureBuilder &add_constants(const std::string &name, 34 | uint32_t shader_register, 35 | uint32_t num_vals, 36 | uint32_t space); 37 | 38 | RootSignatureBuilder &add_srv(const std::string &name, 39 | uint32_t shader_register, 40 | uint32_t space); 41 | 42 | RootSignatureBuilder &add_uav(const std::string &name, 43 | uint32_t shader_register, 44 | uint32_t space); 45 | 46 | RootSignatureBuilder &add_cbv(const std::string &name, 47 | uint32_t shader_register, 48 | uint32_t space); 49 | 50 | // TODO: this is actually writing a descriptor table into the root signature that 51 | // views the entire heap. Need to add other APIs for writing just the descriptor table 52 | // views 53 | // RootSignatureBuilder &add_desc_heap(const std::string &name, 54 | // const DescriptorHeap &heap); 55 | 56 | std::shared_ptr build(ID3D12Device *device); 57 | }; 58 | 59 | class CRTL_DXR_EXPORT RootSignature { 60 | D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE; 61 | Microsoft::WRL::ComPtr sig; 62 | 63 | size_t total_size = 0; 64 | 65 | // The offsets of the parameters into the shader arguments part 66 | // of the shader record. The offsets returned account for the shader identifier size 67 | phmap::flat_hash_map param_offsets; 68 | 69 | friend class RootSignatureBuilder; 70 | friend class RTPipelineBuilder; 71 | friend class RTPipeline; 72 | 73 | public: 74 | RootSignature(D3D12_ROOT_SIGNATURE_FLAGS flags, 75 | Microsoft::WRL::ComPtr sig, 76 | const std::vector ¶ms); 77 | 78 | RootSignature() = default; 79 | 80 | // Returns size_t max if no such param, offsets include the shader identifier 81 | size_t offset(const std::string &name) const; 82 | 83 | size_t size(const std::string &name) const; 84 | 85 | // Return the total size of the shader record, including the shader identifier 86 | size_t get_total_size() const; 87 | 88 | ID3D12RootSignature *operator->(); 89 | ID3D12RootSignature *get(); 90 | }; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_rtpipeline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "crtl_dxr_export.h" 7 | #include "dxr_buffer.h" 8 | #include "dxr_root_signature.h" 9 | #include "dxr_shader_library.h" 10 | #include "dxr_shader_record.h" 11 | #include "dxr_texture.h" 12 | #include "dxr_utils.h" 13 | #include "parallel_hashmap/phmap.h" 14 | 15 | namespace crtl { 16 | namespace dxr { 17 | 18 | struct ShaderPayloadConfig { 19 | std::vector functions; 20 | D3D12_RAYTRACING_SHADER_CONFIG desc; 21 | 22 | ShaderPayloadConfig() = default; 23 | ShaderPayloadConfig(const std::vector &functions, 24 | uint32_t max_payload_size, 25 | uint32_t max_attrib_size); 26 | }; 27 | 28 | class RTPipeline; 29 | 30 | class CRTL_DXR_EXPORT RTPipelineBuilder { 31 | std::vector shader_libs; 32 | std::wstring ray_gen; 33 | std::vector miss_shaders; 34 | std::vector hit_groups; 35 | std::vector payload_configs; 36 | std::vector signature_associations; 37 | RootSignature global_sig; 38 | uint32_t recursion_depth = 1; 39 | 40 | public: 41 | RTPipelineBuilder &add_shader_library(const ShaderLibrary &library); 42 | 43 | RTPipelineBuilder &set_ray_gen(const std::wstring &ray_gen); 44 | 45 | // Add a miss shader to the pipeline 46 | RTPipelineBuilder &add_miss_shader(const std::wstring &miss_fn); 47 | 48 | // Add a hitgroup to the pipeline 49 | RTPipelineBuilder &add_hit_group(const HitGroup &hg); 50 | 51 | RTPipelineBuilder &configure_shader_payload( 52 | const std::vector &functions, 53 | uint32_t max_payload_size, 54 | uint32_t max_attrib_size); 55 | 56 | RTPipelineBuilder &set_max_recursion(uint32_t depth); 57 | 58 | RTPipelineBuilder &set_shader_root_sig(const std::vector &functions, 59 | const RootSignature &sig); 60 | 61 | RTPipelineBuilder &set_global_root_sig(const RootSignature &sig); 62 | 63 | RTPipeline create(ID3D12Device5 *device); 64 | 65 | private: 66 | bool has_global_root_sig() const; 67 | size_t compute_num_subobjects(size_t &num_export_associations, 68 | size_t &num_associated_fcns) const; 69 | }; 70 | 71 | class CRTL_DXR_EXPORT RTPipeline { 72 | RootSignature rt_global_sig; 73 | Microsoft::WRL::ComPtr state; 74 | ID3D12StateObjectProperties *pipeline_props = nullptr; 75 | 76 | std::wstring ray_gen; 77 | std::vector miss_shaders; 78 | std::vector hit_groups; 79 | std::vector signature_associations; 80 | 81 | D3D12_DISPATCH_RAYS_DESC dispatch_desc = {0}; 82 | Buffer cpu_shader_table, shader_table; 83 | phmap::flat_hash_map record_offsets; 84 | uint8_t *sbt_mapping = nullptr; 85 | 86 | friend class RTPipelineBuilder; 87 | 88 | RTPipeline(D3D12_STATE_OBJECT_DESC &desc, 89 | RootSignature &global_sig, 90 | const std::wstring &ray_gen, 91 | const std::vector &miss_shaders, 92 | const std::vector &hit_groups, 93 | const std::vector &signature_associations, 94 | ID3D12Device5 *device); 95 | 96 | public: 97 | RTPipeline() = default; 98 | 99 | void map_shader_table(); 100 | void unmap_shader_table(); 101 | // Upload the shader table contents to the default heap 102 | void upload_shader_table(ID3D12GraphicsCommandList4 *cmd_list); 103 | 104 | // Get the pointer in the table to a specific shader record. The table must be mapped 105 | uint8_t *shader_record(const std::wstring &shader); 106 | 107 | /* Get the local root signature assigned to the shader, if any. Returns null 108 | * if no local root signature was set for the shader 109 | */ 110 | const RootSignature *shader_signature(const std::wstring &shader) const; 111 | 112 | D3D12_DISPATCH_RAYS_DESC dispatch_rays(const glm::uvec2 &img_dims); 113 | 114 | bool has_global_root_sig() const; 115 | ID3D12RootSignature *global_sig(); 116 | 117 | ID3D12StateObject *operator->(); 118 | ID3D12StateObject *get(); 119 | 120 | private: 121 | size_t compute_shader_record_size(const std::wstring &shader) const; 122 | }; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_scene.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dxr_scene.h" 4 | 5 | namespace crtl { 6 | namespace dxr { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_scene.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "api_object.h" 4 | #include "crtl_dxr_export.h" 5 | #include "dxr_utils.h" 6 | 7 | namespace crtl { 8 | namespace dxr { 9 | 10 | class CRTL_DXR_EXPORT Scene : public crtl::APIObject { 11 | public: 12 | // TODO 13 | }; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_shader_entry_point.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include "api_object.h" 7 | #include "crtl_dxr_export.h" 8 | #include "dxr_device.h" 9 | #include "dxr_root_signature.h" 10 | #include "dxr_shader_library.h" 11 | #include "dxr_shader_parameter_desc.h" 12 | #include "dxr_utils.h" 13 | #include "hlsl/crtl_to_hlsl.h" 14 | #include "parallel_hashmap/phmap.h" 15 | 16 | #include 17 | 18 | namespace crtl { 19 | namespace dxr { 20 | 21 | enum class EntryPointType { 22 | RAY_GEN, 23 | CLOSEST_HIT, 24 | ANY_HIT, 25 | INTERSECTION, 26 | MISS, 27 | COMPUTE, 28 | // TODO: Callable shaders? 29 | INVALID 30 | }; 31 | 32 | class CRTL_DXR_EXPORT ShaderEntryPoint : public APIObject { 33 | std::shared_ptr shader_library; 34 | 35 | // TODO: Make this not JSON so it's not so expensive to access in hot code paths, 36 | // reduce string alloc & other ops 37 | // This also doesn't need to copy it from the shader library, it can just reference it 38 | // by ptr 39 | nlohmann::json entry_point_info = nullptr; 40 | EntryPointType entry_point_type = EntryPointType::INVALID; 41 | 42 | phmap::flat_hash_map parameter_info; 43 | 44 | // TODO: this would be lifted into the entry point metadata when I move off JSON for 45 | // storing it 46 | std::string entry_point_name; 47 | 48 | std::shared_ptr root_signature; 49 | 50 | public: 51 | ShaderEntryPoint(DXRDevice *dxrdevice, 52 | const std::string &entry_point_name, 53 | const std::shared_ptr &shader_library); 54 | 55 | EntryPointType type() const; 56 | 57 | const std::string &name() const; 58 | 59 | const phmap::flat_hash_map &get_parameter_info() 60 | const; 61 | 62 | const RootSignature *get_root_signature() const; 63 | 64 | private: 65 | // Builds the root signature and the parameter info 66 | void build_root_signature(DXRDevice *device); 67 | }; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_shader_library.cpp: -------------------------------------------------------------------------------- 1 | #include "dxr_shader_library.h" 2 | #include 3 | #include 4 | #include 5 | #include "error.h" 6 | #include "util.h" 7 | 8 | namespace crtl { 9 | namespace dxr { 10 | 11 | using Microsoft::WRL::ComPtr; 12 | 13 | ShaderLibrary::ShaderLibrary(const std::string &crtl_src) 14 | // TODO: CRTL Compiler library needs some way for us to get errors and report them 15 | // back up to the application 16 | : crtl_compilation_result(hlsl::compile_crtl(crtl_src)) 17 | { 18 | std::cout << "----\nInput CRTL shader:\n" << crtl_src << "\n"; 19 | std::cout << "Compiled HLSL src:\n" 20 | << crtl_compilation_result->hlsl_src << "\n----\n"; 21 | 22 | // Now compile the HLSL to DXIL 23 | compile_dxil(); 24 | 25 | bytecode.pShaderBytecode = shader_dxil->GetBufferPointer(); 26 | bytecode.BytecodeLength = shader_dxil->GetBufferSize(); 27 | 28 | // TODO: Should also build some intermediate struct here instead of working directly 29 | // on the JSON data in the rest of the code to reduce amount of string 30 | // manipulation/allocation on the hot code path 31 | 32 | // Build the list of shader entry points 33 | for (const auto &entry_pt : crtl_compilation_result->shader_info["entry_points"]) { 34 | std::cout << "entry pt name: " << entry_pt["name"].get() << "\n"; 35 | exported_functions.push_back(utf8_to_utf16(entry_pt["name"].get())); 36 | } 37 | 38 | // We need to get the export info translated over from the JSON metadata 39 | build_library_desc(); 40 | } 41 | 42 | const D3D12_DXIL_LIBRARY_DESC *ShaderLibrary::library_desc() const 43 | { 44 | return &dxil_library_desc; 45 | } 46 | 47 | void ShaderLibrary::compile_dxil() 48 | { 49 | ComPtr dxc; 50 | DxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&dxc)); 51 | 52 | std::array dxc_args = {L"-T", L"lib_6_3", L"-O3"}; 53 | 54 | DxcBuffer hlsl_src_buf = {}; 55 | hlsl_src_buf.Ptr = crtl_compilation_result->hlsl_src.c_str(); 56 | hlsl_src_buf.Size = crtl_compilation_result->hlsl_src.size(); 57 | hlsl_src_buf.Encoding = DXC_CP_UTF8; 58 | 59 | ComPtr dxc_results; 60 | dxc->Compile(&hlsl_src_buf, 61 | dxc_args.data(), 62 | dxc_args.size(), 63 | nullptr, 64 | IID_PPV_ARGS(&dxc_results)); 65 | 66 | // Check for compilation errors 67 | ComPtr error_log = nullptr; 68 | dxc_results->GetOutput(DXC_OUT_ERRORS, IID_PPV_ARGS(&error_log), nullptr); 69 | 70 | std::string error_log_utf8; 71 | if (error_log && error_log->GetStringLength() > 0) { 72 | error_log_utf8 = error_log->GetStringPointer(); 73 | // TODO : do need a way to report warnings in the native shader but probably just 74 | // for internal development/logging? 75 | std::cout << "DXC Warnings/Errors: " << error_log_utf8 << "\n"; 76 | } 77 | 78 | HRESULT compilation_status; 79 | dxc_results->GetStatus(&compilation_status); 80 | if (FAILED(compilation_status)) { 81 | throw Error(error_log_utf8, CRTL_ERROR_NATIVE_SHADER_COMPILATION_FAILED); 82 | } 83 | 84 | // Get the shader binary 85 | dxc_results->GetOutput(DXC_OUT_OBJECT, IID_PPV_ARGS(&shader_dxil), nullptr); 86 | if (!shader_dxil) { 87 | std::cout << "Somehow didn't get shader dxil!?"; 88 | throw Error("Didn't get DXIL?", CRTL_ERROR_NATIVE_SHADER_COMPILATION_FAILED); 89 | } 90 | } 91 | 92 | nlohmann::json ShaderLibrary::get_entry_point_info(const std::string &entry_point) const 93 | { 94 | const auto &entry_points = crtl_compilation_result->shader_info["entry_points"]; 95 | const auto fnd = entry_points.find(entry_point); 96 | if (fnd == entry_points.end()) { 97 | throw Error("ShaderLibrary does not contain entry point " + entry_point, 98 | CRTL_ERROR_ENTRY_POINT_NOT_FOUND); 99 | } 100 | return *fnd; 101 | } 102 | 103 | void ShaderLibrary::build_library_desc() 104 | { 105 | for (const auto &fn : exported_functions) { 106 | D3D12_EXPORT_DESC shader_export = {}; 107 | shader_export.ExportToRename = nullptr; 108 | shader_export.Flags = D3D12_EXPORT_FLAG_NONE; 109 | shader_export.Name = fn.c_str(); 110 | exports.push_back(shader_export); 111 | export_fcn_ptrs.push_back(fn.c_str()); 112 | } 113 | dxil_library_desc.DXILLibrary = bytecode; 114 | dxil_library_desc.NumExports = exports.size(); 115 | dxil_library_desc.pExports = exports.data(); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_shader_library.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "api_object.h" 6 | #include "crtl_dxr_export.h" 7 | #include "dxr_utils.h" 8 | #include "hlsl/crtl_to_hlsl.h" 9 | 10 | #include 11 | 12 | namespace crtl { 13 | namespace dxr { 14 | 15 | class CRTL_DXR_EXPORT ShaderLibrary : public APIObject { 16 | std::shared_ptr crtl_compilation_result; 17 | 18 | Microsoft::WRL::ComPtr shader_dxil = nullptr; 19 | 20 | D3D12_SHADER_BYTECODE bytecode = {}; 21 | D3D12_DXIL_LIBRARY_DESC dxil_library_desc = {}; 22 | 23 | std::vector exported_functions; 24 | // A bit annoying but we keep this around too b/c we need a contiguous 25 | // array of pointers for now to build the exports association in the pipeline 26 | std::vector export_fcn_ptrs; 27 | std::vector exports; 28 | 29 | public: 30 | ShaderLibrary(const std::string &crtl_src); 31 | 32 | ShaderLibrary(const ShaderLibrary &) = delete; 33 | ShaderLibrary &operator=(const ShaderLibrary &) = delete; 34 | 35 | // TODO: make this not work on JSON 36 | nlohmann::json get_entry_point_info(const std::string &entry_point) const; 37 | 38 | const D3D12_DXIL_LIBRARY_DESC *library_desc() const; 39 | 40 | private: 41 | void compile_dxil(); 42 | 43 | void build_library_desc(); 44 | }; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_shader_parameter_desc.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dxr_shader_parameter_desc.h" 4 | 5 | namespace crtl { 6 | namespace dxr { 7 | 8 | ShaderParameterDesc::ShaderParameterDesc(const ShaderParameterType param_type, 9 | const std::shared_ptr &type, 10 | uint32_t slot, 11 | uint32_t space, 12 | uint32_t constant_offset_bytes) 13 | : param_type(param_type), 14 | type(type), 15 | slot(slot), 16 | space(space), 17 | constant_offset_bytes(constant_offset_bytes) 18 | { 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_shader_parameter_desc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "api_object.h" 4 | #include "crtl_dxr_export.h" 5 | #include "dxr_utils.h" 6 | #include "type.h" 7 | 8 | namespace crtl { 9 | namespace dxr { 10 | 11 | enum class ShaderParameterType { 12 | INVALID, 13 | INLINE_CONSTANT, 14 | SHADER_RESOURCE_VIEW, 15 | UNORDERED_ACCESS_VIEW, 16 | // TODO: samplers, tables 17 | }; 18 | 19 | /* Describes a shader record parameter, which register type it maps too, 20 | * the slot/space for that register. Inline constants also specify their offset 21 | * within the inline constant buffer in bytes 22 | */ 23 | struct CRTL_DXR_EXPORT ShaderParameterDesc { 24 | ShaderParameterType param_type = ShaderParameterType::INVALID; 25 | std::shared_ptr type; 26 | 27 | uint32_t slot = -1; 28 | uint32_t space = -1; 29 | uint32_t constant_offset_bytes = -1; 30 | 31 | ShaderParameterDesc() = default; 32 | 33 | ShaderParameterDesc(const ShaderParameterType param_type, 34 | const std::shared_ptr &type, 35 | uint32_t slot, 36 | uint32_t space, 37 | uint32_t constant_offset_bytes = -1); 38 | }; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_shader_record.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "api_object.h" 6 | #include "crtl_dxr_export.h" 7 | #include "dxr_root_signature.h" 8 | #include "dxr_shader_entry_point.h" 9 | #include "dxr_utils.h" 10 | 11 | namespace crtl { 12 | namespace dxr { 13 | 14 | class ShaderRecordParameterBlock; 15 | 16 | class CRTL_DXR_EXPORT ShaderRecord : public APIObject { 17 | protected: 18 | std::string shader_record_name; 19 | 20 | std::shared_ptr bound_parameter_block; 21 | 22 | public: 23 | virtual ~ShaderRecord() = default; 24 | 25 | // TODO: Some method should be provided here to get the local root signature and root 26 | // signature association object for a shader record renderables/pipelines etc. this 27 | // will also provide info to the parameter block. 28 | // Note that the layout doesn't need to match the order they appear in the shader 29 | // record list, constants should be packed up front to minimize padding 30 | // so different constants accessed by different entry points in a hit group can be put 31 | // together, and the local root signature ordered to map them to the right registers 32 | // TODO: Later on do not use JSON for this 33 | // What it needs is a parameter descriptor, the block takes a list of these in a map 34 | // by their name so that set param can map to the right location 35 | // or really, a vector of the param info + a map of name -> index 36 | 37 | virtual const phmap::flat_hash_map 38 | &get_parameter_info() const = 0; 39 | 40 | virtual const RootSignature *get_root_signature() const = 0; 41 | 42 | size_t get_parameter_block_size() const; 43 | 44 | void set_parameter_block( 45 | const std::shared_ptr ¶meter_block); 46 | }; 47 | 48 | // TODO WILL: Hit Group records will be changed in the language/compiler/API to 49 | // better express the SBT -> shaders mapping 50 | class CRTL_DXR_EXPORT HitGroupRecord : public ShaderRecord { 51 | // TODO: Maybe make it atomic? for some thread safe support of creating records/etc? 52 | // IDs are tracked per record type rather than globally 53 | inline static uint32_t next_record_id = 0; 54 | 55 | std::shared_ptr closest_hit, any_hit, intersection; 56 | 57 | D3D12_HIT_GROUP_TYPE hg_type; 58 | 59 | public: 60 | // Intersection and any hit are optional, can pass nullptr to not have them 61 | // TODO: After code syntax for HG changes this will not take a bunch of entry points 62 | // but a "hit group definition" or somethign that has the root sig/params/etc. 63 | HitGroupRecord(const std::shared_ptr &closest_hit, 64 | const std::shared_ptr &intersection, 65 | const std::shared_ptr &any_hit); 66 | 67 | virtual const phmap::flat_hash_map 68 | &get_parameter_info() const override; 69 | 70 | virtual const RootSignature *get_root_signature() const override; 71 | }; 72 | 73 | class CRTL_DXR_EXPORT MissRecord : public ShaderRecord { 74 | inline static uint32_t next_record_id = 0; 75 | 76 | std::shared_ptr entry_point; 77 | 78 | public: 79 | MissRecord(const std::shared_ptr &entry_point); 80 | 81 | virtual const phmap::flat_hash_map 82 | &get_parameter_info() const override; 83 | 84 | virtual const RootSignature *get_root_signature() const override; 85 | }; 86 | 87 | class CRTL_DXR_EXPORT RaygenRecord : public ShaderRecord { 88 | inline static uint32_t next_record_id = 0; 89 | 90 | std::shared_ptr entry_point; 91 | 92 | public: 93 | RaygenRecord(const std::shared_ptr &entry_point); 94 | 95 | virtual const phmap::flat_hash_map 96 | &get_parameter_info() const override; 97 | 98 | virtual const RootSignature *get_root_signature() const override; 99 | }; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_shader_record_parameter_block.cpp: -------------------------------------------------------------------------------- 1 | #include "dxr_shader_record_parameter_block.h" 2 | #include "util.h" 3 | 4 | namespace crtl { 5 | namespace dxr { 6 | ShaderRecordParameterBlock::ShaderRecordParameterBlock( 7 | const std::shared_ptr &shader_record) 8 | : shader_record(shader_record) 9 | { 10 | parameter_block.resize(shader_record->get_parameter_block_size()); 11 | std::cout << "Parameter block size: " << parameter_block.size() << "\n"; 12 | } 13 | 14 | void ShaderRecordParameterBlock::set_parameter(const std::string &name, 15 | CRTL_DATA_TYPE data_type, 16 | void *parameter) 17 | { 18 | const auto ¶meter_info = shader_record->get_parameter_info(); 19 | auto param_info = parameter_info.find(name); 20 | if (param_info == parameter_info.end()) { 21 | throw Error("Parameter " + name + " does not exist in parameter block.", 22 | CRTL_ERROR_INVALID_PARAMETER_NAME); 23 | } 24 | 25 | try { 26 | // offset will throw if there's no sbt_constants. The root signature offsets 27 | // include the shader identifier size, which we don't need to account for when 28 | // building the parameter block 29 | // TODO: Would make sense to move the ident size subtraction off higher up (to the 30 | // shader record?) 31 | const size_t sbt_constants_offset = 32 | shader_record->get_root_signature()->offset("sbt_constants") - 33 | D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; 34 | const size_t param_offset = 35 | sbt_constants_offset + param_info->second.constant_offset_bytes; 36 | std::cout << "Write param of size " << crtl::data_type_size(data_type) << " " 37 | << name << " at offset " << param_offset << " in SBT\n"; 38 | std::memcpy(parameter_block.data() + param_offset, 39 | parameter, 40 | crtl::data_type_size(data_type)); 41 | } catch (const std::runtime_error &e) { 42 | throw Error("Parameter " + name + " does not exist in the parameter block.", 43 | CRTL_ERROR_INVALID_PARAMETER_NAME); 44 | } 45 | } 46 | 47 | void ShaderRecordParameterBlock::set_parameter( 48 | const std::string &name, 49 | CRTL_DATA_TYPE data_type, 50 | const std::shared_ptr ¶meter) 51 | { 52 | try { 53 | // offset will throw if the parameter doesn't exist. The root signature offsets 54 | // include the shader identifier size, which we don't need to account for when 55 | // building the parameter block 56 | const size_t param_offset = shader_record->get_root_signature()->offset(name) - 57 | D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; 58 | D3D12_GPU_VIRTUAL_ADDRESS gpu_virtual_addr = parameter->gpu_virtual_address(); 59 | std::cout << "Write buffer view param " << name << " at offset " << param_offset 60 | << " in SBT\n"; 61 | std::memcpy(parameter_block.data() + param_offset, 62 | &gpu_virtual_addr, 63 | sizeof(D3D12_GPU_VIRTUAL_ADDRESS)); 64 | } catch (const std::runtime_error &e) { 65 | throw Error("Parameter " + name + " does not exist in the parameter block.", 66 | CRTL_ERROR_INVALID_PARAMETER_NAME); 67 | } 68 | } 69 | 70 | size_t ShaderRecordParameterBlock::size() const 71 | { 72 | return parameter_block.size(); 73 | } 74 | 75 | const ShaderRecord *ShaderRecordParameterBlock::get_shader_record() const 76 | { 77 | return shader_record.get(); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_shader_record_parameter_block.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "crtl_dxr_export.h" 7 | #include "dxr_blas.h" 8 | #include "dxr_buffer_view.h" 9 | #include "dxr_parameter_block.h" 10 | #include "dxr_shader_record.h" 11 | #include "dxr_texture.h" 12 | #include "dxr_tlas.h" 13 | #include "error.h" 14 | 15 | namespace crtl { 16 | namespace dxr { 17 | 18 | class CRTL_DXR_EXPORT ShaderRecordParameterBlock : public ParameterBlock { 19 | std::shared_ptr shader_record; 20 | 21 | // The parameter block data is populated here and just memcpy'd into the SBT 22 | std::vector parameter_block; 23 | 24 | public: 25 | // TODO: This will basically just provide a way to set values for the elements in 26 | // the shader entry point's phmap::flat_hash_map 27 | // parameter_info; 28 | ShaderRecordParameterBlock(const std::shared_ptr &shader_record); 29 | 30 | void set_parameter(const std::string &name, 31 | CRTL_DATA_TYPE data_type, 32 | void *parameter) override; 33 | 34 | void set_parameter(const std::string &name, 35 | CRTL_DATA_TYPE data_type, 36 | const std::shared_ptr ¶meter) override; 37 | /* 38 | * TODO: acceleration structures as parameters as well 39 | */ 40 | 41 | size_t size() const; 42 | 43 | const ShaderRecord *get_shader_record() const; 44 | }; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_texture.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "api_object.h" 4 | #include "crtl_dxr_export.h" 5 | #include "dxr_buffer.h" 6 | #include "dxr_resource.h" 7 | #include "dxr_utils.h" 8 | 9 | namespace crtl { 10 | namespace dxr { 11 | 12 | class CRTL_DXR_EXPORT Texture : public crtl::APIObject, public Resource { 13 | glm::uvec3 tdims = glm::uvec3(0); 14 | DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; 15 | // The supported usages for this image 16 | CRTL_IMAGE_USAGE image_usages; 17 | 18 | public: 19 | Texture(DXRDevice *device, 20 | CRTL_TEXTURE_TYPE texture_type, 21 | CRTL_IMAGE_FORMAT format, 22 | CRTL_IMAGE_USAGE usages, 23 | glm::uvec3 dimensions); 24 | 25 | size_t linear_row_pitch() const; 26 | 27 | // Size of one pixel, in bytes 28 | size_t pixel_size() const; 29 | 30 | DXGI_FORMAT pixel_format() const; 31 | 32 | glm::uvec3 dims() const; 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_tlas.cpp: -------------------------------------------------------------------------------- 1 | #include "dxr_tlas.h" 2 | #include 3 | #include 4 | #include "dxr_utils.h" 5 | #include "util.h" 6 | 7 | namespace crtl { 8 | namespace dxr { 9 | 10 | using Microsoft::WRL::ComPtr; 11 | 12 | #if 0 13 | TopLevelBVH::TopLevelBVH(Buffer instance_buf, 14 | const std::vector &instances, 15 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS build_flags) 16 | : instances(instances), instance_buf(instance_buf), build_flags(build_flags) 17 | { 18 | } 19 | 20 | void TopLevelBVH::enqeue_build(ID3D12Device5 *device, ID3D12GraphicsCommandList4 *cmd_list) 21 | { 22 | // Determine bound of much memory the accel builder may need and allocate it 23 | D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS bvh_inputs = {0}; 24 | bvh_inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; 25 | bvh_inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; 26 | bvh_inputs.NumDescs = instances.size(); 27 | bvh_inputs.InstanceDescs = instance_buf->GetGPUVirtualAddress(); 28 | bvh_inputs.Flags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE; 29 | 30 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO prebuild_info = {0}; 31 | device->GetRaytracingAccelerationStructurePrebuildInfo(&bvh_inputs, &prebuild_info); 32 | 33 | // The buffer sizes must be aligned to 256 bytes 34 | prebuild_info.ResultDataMaxSizeInBytes = 35 | align_to(prebuild_info.ResultDataMaxSizeInBytes, 36 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT); 37 | prebuild_info.ScratchDataSizeInBytes = 38 | align_to(prebuild_info.ScratchDataSizeInBytes, 39 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT); 40 | 41 | bvh = Buffer::device(device, 42 | prebuild_info.ResultDataMaxSizeInBytes, 43 | D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, 44 | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); 45 | scratch = Buffer::device(device, 46 | prebuild_info.ScratchDataSizeInBytes, 47 | D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 48 | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); 49 | 50 | D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC build_desc = {0}; 51 | build_desc.Inputs = bvh_inputs; 52 | build_desc.DestAccelerationStructureData = bvh->GetGPUVirtualAddress(); 53 | build_desc.ScratchAccelerationStructureData = scratch->GetGPUVirtualAddress(); 54 | cmd_list->BuildRaytracingAccelerationStructure(&build_desc, 0, nullptr); 55 | 56 | // Insert a barrier to wait for the build to complete 57 | D3D12_RESOURCE_BARRIER barrier = barrier_uav(bvh); 58 | cmd_list->ResourceBarrier(1, &barrier); 59 | } 60 | 61 | void TopLevelBVH::finalize() 62 | { 63 | // Release the buffers we don't need anymore 64 | scratch = Buffer(); 65 | } 66 | 67 | size_t TopLevelBVH::num_instances() const 68 | { 69 | return instances.size(); 70 | } 71 | 72 | ID3D12Resource *TopLevelBVH::operator->() 73 | { 74 | return get(); 75 | } 76 | 77 | ID3D12Resource *TopLevelBVH::get() 78 | { 79 | return bvh.get(); 80 | } 81 | #endif 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_tlas.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "crtl_dxr_export.h" 6 | #include "dxr_buffer.h" 7 | #include "dxr_geometry.h" 8 | #include "dxr_utils.h" 9 | 10 | namespace crtl { 11 | namespace dxr { 12 | 13 | #if 0 14 | // TODO: Will be used by the Scene 15 | class CRTL_DXR_EXPORT TopLevelBVH { 16 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS build_flags = 17 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_NONE; 18 | Buffer scratch; 19 | 20 | public: 21 | // TODO: Need instance for dxr 22 | //std::vector instances; 23 | Buffer instance_buf, bvh; 24 | 25 | TopLevelBVH() = default; 26 | 27 | TopLevelBVH(Buffer instance_buf, 28 | const std::vector &instances, 29 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS build_flags = 30 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE); 31 | 32 | /* After calling build the commands are placed in the command list, with a 33 | * UAV barrier to wait on the completion of the build before other commands are 34 | * run, but does not submit the command list. 35 | */ 36 | void enqeue_build(ID3D12Device5 *device, ID3D12GraphicsCommandList4 *cmd_list); 37 | 38 | // Free the BVH build scratch space 39 | void finalize(); 40 | 41 | size_t num_instances() const; 42 | 43 | ID3D12Resource *operator->(); 44 | ID3D12Resource *get(); 45 | }; 46 | #endif 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_triangle_geometry.cpp: -------------------------------------------------------------------------------- 1 | #include "dxr_triangle_geometry.h" 2 | 3 | namespace crtl { 4 | namespace dxr { 5 | 6 | TriangleGeometry::TriangleGeometry(Buffer verts, 7 | Buffer indices, 8 | Buffer normals, 9 | Buffer uvs, 10 | D3D12_RAYTRACING_GEOMETRY_FLAGS geom_flags) 11 | : vertex_buf(verts), index_buf(indices), normal_buf(normals), uv_buf(uvs) 12 | { 13 | desc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; 14 | desc.Triangles.VertexBuffer.StartAddress = vertex_buf->GetGPUVirtualAddress(); 15 | desc.Triangles.VertexBuffer.StrideInBytes = sizeof(float) * 3; 16 | desc.Triangles.VertexCount = 17 | vertex_buf.size() / desc.Triangles.VertexBuffer.StrideInBytes; 18 | desc.Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT; 19 | 20 | desc.Triangles.IndexBuffer = index_buf->GetGPUVirtualAddress(); 21 | desc.Triangles.IndexFormat = DXGI_FORMAT_R32_UINT; 22 | desc.Triangles.IndexCount = index_buf.size() / sizeof(uint32_t); 23 | desc.Triangles.Transform3x4 = 0; 24 | desc.Flags = geom_flags; 25 | } 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_triangle_geometry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "crtl_dxr_export.h" 4 | #include "dxr_buffer.h" 5 | #include "dxr_geometry.h" 6 | 7 | namespace crtl { 8 | namespace dxr { 9 | 10 | class CRTL_DXR_EXPORT TriangleGeometry : public Geometry { 11 | public: 12 | Buffer vertex_buf, index_buf, normal_buf, uv_buf; 13 | 14 | // TODO: Allow other vertex and index formats? Right now this 15 | // assumes vec3f verts and uint3 indices 16 | TriangleGeometry(Buffer vertex_buf, 17 | Buffer index_buf, 18 | Buffer normal_buf, 19 | Buffer uv_buf, 20 | D3D12_RAYTRACING_GEOMETRY_FLAGS geom_flags = 21 | D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE); 22 | }; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "dxr_utils.h" 2 | #include 3 | #include 4 | #include 5 | #include "dxr_resource.h" 6 | #include "util.h" 7 | 8 | namespace crtl { 9 | namespace dxr { 10 | 11 | using Microsoft::WRL::ComPtr; 12 | 13 | CRTL_DXR_EXPORT ComPtr create_dxr_device(ComPtr &factory) 14 | { 15 | IDXGIAdapter1 *adapter; 16 | for (uint32_t i = 0; factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND; 17 | ++i) { 18 | ComPtr device; 19 | auto err = 20 | D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_12_1, IID_PPV_ARGS(&device)); 21 | if (FAILED(err)) { 22 | std::cout << "Failed to make D3D12 device\n"; 23 | throw std::runtime_error("failed to make d3d12 device\n"); 24 | } 25 | 26 | D3D12_FEATURE_DATA_D3D12_OPTIONS5 feature_data = {0}; 27 | CHECK_ERR(device->CheckFeatureSupport( 28 | D3D12_FEATURE_D3D12_OPTIONS5, &feature_data, sizeof(feature_data))); 29 | 30 | if (feature_data.RaytracingTier >= D3D12_RAYTRACING_TIER_1_0) { 31 | DXGI_ADAPTER_DESC1 desc; 32 | adapter->GetDesc1(&desc); 33 | std::wstring_convert> conv; 34 | const std::string name = conv.to_bytes(desc.Description); 35 | return device; 36 | } 37 | } 38 | return nullptr; 39 | } 40 | 41 | CRTL_DXR_EXPORT D3D12_RESOURCE_BARRIER barrier_transition(ID3D12Resource *res, 42 | D3D12_RESOURCE_STATES before, 43 | D3D12_RESOURCE_STATES after) 44 | { 45 | D3D12_RESOURCE_BARRIER b = {0}; 46 | b.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; 47 | b.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; 48 | b.Transition.StateBefore = before; 49 | b.Transition.StateAfter = after; 50 | b.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; 51 | b.Transition.pResource = res; 52 | return b; 53 | } 54 | 55 | CRTL_DXR_EXPORT D3D12_RESOURCE_BARRIER 56 | barrier_transition(Microsoft::WRL::ComPtr &res, 57 | D3D12_RESOURCE_STATES before, 58 | D3D12_RESOURCE_STATES after) 59 | { 60 | return barrier_transition(res.Get(), before, after); 61 | } 62 | 63 | CRTL_DXR_EXPORT D3D12_RESOURCE_BARRIER barrier_transition(Resource &res, 64 | D3D12_RESOURCE_STATES after) 65 | { 66 | D3D12_RESOURCE_BARRIER b = barrier_transition(res.get(), res.state(), after); 67 | res.res_state = after; 68 | return b; 69 | } 70 | 71 | CRTL_DXR_EXPORT D3D12_RESOURCE_BARRIER barrier_uav(ID3D12Resource *res) 72 | { 73 | D3D12_RESOURCE_BARRIER b = {0}; 74 | b.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; 75 | b.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; 76 | b.UAV.pResource = res; 77 | return b; 78 | } 79 | 80 | CRTL_DXR_EXPORT D3D12_RESOURCE_BARRIER 81 | barrier_uav(Microsoft::WRL::ComPtr &res) 82 | { 83 | return barrier_uav(res.Get()); 84 | } 85 | 86 | CRTL_DXR_EXPORT D3D12_RESOURCE_BARRIER barrier_uav(Resource &res) 87 | { 88 | return barrier_uav(res.get()); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/crtl/core/dxr/dxr_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "crtl_dxr_export.h" 9 | 10 | // Utilities for general DX12 ease of use 11 | #define CHECK_ERR(FN) \ 12 | { \ 13 | auto fn_err = FN; \ 14 | if (FAILED(fn_err)) { \ 15 | std::cout << #FN << " failed due to " << std::hex << fn_err << std::endl \ 16 | << std::flush; \ 17 | throw std::runtime_error(#FN); \ 18 | } \ 19 | } 20 | 21 | namespace crtl { 22 | namespace dxr { 23 | 24 | /* Find the first DXR capable adapter and create a device for it, 25 | * returns null if no DXR capable adapter is found 26 | */ 27 | CRTL_DXR_EXPORT Microsoft::WRL::ComPtr create_dxr_device( 28 | Microsoft::WRL::ComPtr &factory); 29 | 30 | // Convenience for making resource transition barriers 31 | // TODO: Won't be needed after moving to enhanced barriers 32 | CRTL_DXR_EXPORT D3D12_RESOURCE_BARRIER barrier_transition(ID3D12Resource *res, 33 | D3D12_RESOURCE_STATES before, 34 | D3D12_RESOURCE_STATES after); 35 | CRTL_DXR_EXPORT D3D12_RESOURCE_BARRIER 36 | barrier_transition(Microsoft::WRL::ComPtr &res, 37 | D3D12_RESOURCE_STATES before, 38 | D3D12_RESOURCE_STATES after); 39 | 40 | // Convenience for making UAV transition barriers 41 | CRTL_DXR_EXPORT D3D12_RESOURCE_BARRIER barrier_uav(ID3D12Resource *res); 42 | CRTL_DXR_EXPORT D3D12_RESOURCE_BARRIER 43 | barrier_uav(Microsoft::WRL::ComPtr &res); 44 | 45 | class Resource; 46 | 47 | CRTL_DXR_EXPORT D3D12_RESOURCE_BARRIER barrier_transition(Resource &res, 48 | D3D12_RESOURCE_STATES after); 49 | CRTL_DXR_EXPORT D3D12_RESOURCE_BARRIER barrier_uav(Resource &res); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/crtl/core/error.cpp: -------------------------------------------------------------------------------- 1 | #include "error.h" 2 | 3 | namespace crtl { 4 | 5 | Error::Error(const std::string &what, CRTL_ERROR error) 6 | : std::runtime_error(what), error(error) 7 | { 8 | } 9 | 10 | CRTL_ERROR Error::get_error() const 11 | { 12 | return error; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/crtl/core/error.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "crtl/crtl_enums.h" 6 | #include "crtl_export.h" 7 | 8 | namespace crtl { 9 | class CRTL_EXPORT Error : public std::runtime_error { 10 | CRTL_ERROR error; 11 | 12 | public: 13 | Error(const std::string &what, CRTL_ERROR error); 14 | 15 | CRTL_ERROR get_error() const; 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /src/crtl/core/include/crtl/crtl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "crtl_buffer.h" 4 | #include "crtl_core.h" 5 | #include "crtl_device.h" 6 | #include "crtl_enums.h" 7 | #include "crtl_event.h" 8 | #include "crtl_geometry.h" 9 | #include "crtl_parameter_block.h" 10 | #include "crtl_queue.h" 11 | #include "crtl_rtpipeline.h" 12 | #include "crtl_shader.h" 13 | #include "crtl_texture.h" 14 | -------------------------------------------------------------------------------- /src/crtl/core/include/crtl/crtl_buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "crtl_device.h" 4 | #include "crtl_enums.h" 5 | 6 | #ifdef __cplusplus 7 | namespace crtl_rhi { 8 | struct Buffer : APIObject {}; 9 | struct BufferView : APIObject {}; 10 | } 11 | typedef crtl_rhi::Buffer *CRTLBuffer; 12 | typedef crtl_rhi::BufferView *CRTLBufferView; 13 | #else 14 | typedef CRTLAPIObject CRTLBuffer; 15 | typedef CRTLAPIObject CRTLBufferView; 16 | #endif 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | /* Allocate a buffer of the specified size in the desired memory location. 23 | * Buffers represent untyped blocks of device or host memory. 24 | */ 25 | CRTL_EXPORT CRTL_ERROR crtl_new_buffer(CRTLDevice device, 26 | CRTL_MEMORY_SPACE memory_space, 27 | CRTL_BUFFER_USAGE usages, 28 | size_t size_bytes, 29 | CRTLBuffer *buffer); 30 | 31 | /* Create a typed view of the specified buffer. The view can be created at a desired 32 | * offset in bytes from the start of the buffer, and will contain n_elements elements of 33 | * the specified type. Strides of views must always be compact 34 | * 35 | * TODO: struct views should also be supported but the backend needs to dictate the struct 36 | * size and stride in the view, because it may have to be padded or aligned in some way 37 | * for the target API? What needs to be avoided is making a buffer with some stride 38 | * between the primitive types, because that would need additional handling in the shader 39 | * to support accessing it. If all backends can be made to use a C struct layout that 40 | * would be best Vulkan can (scalar layout extension) ISPC: maybe if can use pragma pack? 41 | * Or just avoid using the builtin short vector types. DX12: probably? CUDA: I think it is 42 | * by default Metal: Also might be by default? 43 | */ 44 | CRTL_EXPORT CRTL_ERROR crtl_new_buffer_view(CRTLDevice device, 45 | CRTLBuffer buffer, 46 | CRTL_DATA_TYPE type, 47 | size_t offset_bytes, 48 | size_t n_elements, 49 | CRTLBufferView *view); 50 | 51 | /* Map the view to read or write data on the host. Only buffers created in the upload 52 | * or readback memory space can be mapped 53 | */ 54 | CRTL_EXPORT CRTL_ERROR crtl_map_buffer_view(CRTLDevice device, 55 | CRTLBufferView view, 56 | CRTL_BUFFER_MAP_MODE map_mode, 57 | void **mapping); 58 | 59 | CRTL_EXPORT CRTL_ERROR crtl_unmap_buffer_view(CRTLDevice device, CRTLBufferView view); 60 | 61 | #ifdef __cplusplus 62 | } 63 | #endif 64 | -------------------------------------------------------------------------------- /src/crtl/core/include/crtl/crtl_core.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "crtl_enums.h" 5 | #include "crtl_export.h" 6 | 7 | #ifdef __cplusplus 8 | namespace crtl_rhi { 9 | struct APIObject {}; 10 | } 11 | typedef crtl_rhi::APIObject *CRTLAPIObject; 12 | #else 13 | typedef void *CRTLAPIObject; 14 | #endif 15 | -------------------------------------------------------------------------------- /src/crtl/core/include/crtl/crtl_device.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "crtl_core.h" 4 | #include "crtl_enums.h" 5 | 6 | #ifdef __cplusplus 7 | namespace crtl_rhi { 8 | struct Device : APIObject {}; 9 | } 10 | typedef crtl_rhi::Device *CRTLDevice; 11 | #else 12 | typedef CRTLAPIObject CRTLDevice; 13 | #endif 14 | 15 | typedef void *CRTLNativeHandle; 16 | typedef void (*CRTLErrorCallback)(CRTL_ERROR error, const char *message); 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | /* Create a device for the desired API. Will load the backend for the device if not 23 | * already loaded 24 | */ 25 | CRTL_EXPORT CRTL_ERROR crtl_new_device(CRTL_DEVICE_API api, CRTLDevice *device); 26 | 27 | CRTL_EXPORT CRTL_ERROR crtl_get_device_api(CRTLDevice device, CRTL_DEVICE_API *api); 28 | 29 | /* Register a callback to be called each time an error occurs to receive a more detailed 30 | * error message from the device 31 | */ 32 | CRTL_EXPORT CRTL_ERROR 33 | crtl_register_device_error_callback(CRTLDevice device, CRTLErrorCallback error_callback); 34 | 35 | // Increase the application refcount for the specified object 36 | CRTL_EXPORT CRTL_ERROR crtl_retain(CRTLDevice device, CRTLAPIObject object); 37 | 38 | /* Decrement the application refcount for the specified object. 39 | * Objects are released when their app refcount reaches 0 and they are no longer 40 | * referenced by any internal objects 41 | */ 42 | CRTL_EXPORT CRTL_ERROR crtl_release(CRTLDevice device, CRTLAPIObject object); 43 | 44 | /* Get the native handle for buffers or textures, the CRTLNativeHandle can then 45 | * be reinterpret_cast'd to a pointer to the native API type 46 | */ 47 | CRTL_EXPORT CRTL_ERROR crtl_get_native_handle(CRTLDevice device, 48 | CRTLAPIObject object, 49 | CRTLNativeHandle *native_handle); 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | -------------------------------------------------------------------------------- /src/crtl/core/include/crtl/crtl_event.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "crtl_device.h" 4 | 5 | #ifdef __cplusplus 6 | namespace crtl_rhi { 7 | struct Event : APIObject {}; 8 | } 9 | typedef crtl_rhi::Event *CRTLEvent; 10 | #else 11 | typedef CRTLAPIObject CRTLEvent; 12 | #endif 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | CRTL_EXPORT CRTL_ERROR crtl_new_event(CRTLDevice device, CRTLEvent *event); 19 | 20 | CRTL_EXPORT CRTL_ERROR crtl_await_event(CRTLDevice device, CRTLEvent event); 21 | 22 | #ifdef __cplusplus 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /src/crtl/core/include/crtl/crtl_geometry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "crtl_buffer.h" 5 | #include "crtl_device.h" 6 | #include "crtl_shader.h" 7 | 8 | #ifdef __cplusplus 9 | namespace crtl_rhi { 10 | struct Geometry : APIObject {}; 11 | struct TriangleGeometry : Geometry {}; 12 | struct Renderable : APIObject {}; 13 | struct Group : APIObject {}; 14 | struct Instance : APIObject {}; 15 | struct Scene : APIObject {}; 16 | } 17 | typedef crtl_rhi::Geometry *CRTLGeometry; 18 | typedef crtl_rhi::TriangleGeometry *CRTLTriangleGeometry; 19 | typedef crtl_rhi::Renderable *CRTLRenderable; 20 | typedef crtl_rhi::Group *CRTLGroup; 21 | typedef crtl_rhi::Instance *CRTLInstance; 22 | typedef crtl_rhi::Scene *CRTLScene; 23 | #else 24 | typedef CRTLAPIObject CRTLGeometry; 25 | typedef CRTLGeometry CRTLTriangleGeometry; 26 | typedef CRTLAPIObject CRTLRenderable; 27 | typedef CRTLAPIObject CRTLGroup; 28 | typedef CRTLAPIObject CRTLInstance; 29 | typedef CRTLAPIObject CRTLScene; 30 | #endif 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | // TODO: Also will need to take some flags for enabling any hit, dynamic geom, etc. 37 | // Some of these flags (any hit or not) will make more sense on the renderable. 38 | CRTL_EXPORT CRTL_ERROR crtl_new_triangle_geometry(CRTLDevice device, 39 | CRTLBufferView vertices, 40 | CRTLBufferView indices, 41 | CRTL_GEOMETRY_FLAG flags, 42 | CRTLTriangleGeometry *geometry); 43 | 44 | CRTL_EXPORT CRTL_ERROR crtl_new_renderable(CRTLDevice device, 45 | CRTLGeometry geometry, 46 | uint32_t n_ray_types, 47 | CRTLRenderable *renderable); 48 | 49 | // TODO: Can also have an API that takes an array of records for convenience 50 | CRTL_EXPORT CRTL_ERROR crtl_set_renderable_shader_record(CRTLDevice device, 51 | CRTLRenderable renderable, 52 | uint32_t index, 53 | CRTLShaderRecord shader_record); 54 | 55 | // TODO: Group vs BLAS name? 56 | CRTL_EXPORT CRTL_ERROR 57 | crtl_new_group(CRTLDevice device, 58 | uint32_t n_renderables, 59 | CRTL_ACCELERATION_STRUCTURE_BUILD_FLAG acceleration_structure_flags, 60 | CRTLGroup *group); 61 | 62 | // TODO: Can also have an API that takes an array of renderables for convenience 63 | CRTL_EXPORT CRTL_ERROR crtl_set_group_renderable(CRTLDevice device, 64 | CRTLGroup group, 65 | uint32_t index, 66 | CRTLRenderable renderable); 67 | 68 | CRTL_EXPORT CRTL_ERROR crtl_new_instance(CRTLDevice device, 69 | CRTLGroup group, 70 | CRTL_INSTANCE_FLAG flags, 71 | CRTLInstance *instance); 72 | 73 | /* Set the instance transformation matrix. transform_3x4 should be a 3x4 row-major matrix 74 | */ 75 | CRTL_EXPORT CRTL_ERROR crtl_set_instance_transform(CRTLDevice device, 76 | CRTLInstance instance, 77 | const float *transform_3x4); 78 | 79 | // TODO: Also need to take some flags about dynamic scene etc. 80 | // Does taking the n_instances and n_shader_records flags make sense here? 81 | CRTL_EXPORT CRTL_ERROR 82 | crtl_new_scene(CRTLDevice device, 83 | uint32_t n_instances, 84 | uint32_t n_ray_types, 85 | CRTL_ACCELERATION_STRUCTURE_BUILD_FLAG acceleration_structure_flags, 86 | CRTLScene *scene); 87 | 88 | // TODO: Can also have API that takes an array for convenience 89 | CRTL_EXPORT CRTL_ERROR crtl_set_scene_instance(CRTLDevice device, 90 | CRTLScene scene, 91 | uint32_t index, 92 | CRTLInstance instance); 93 | 94 | #ifdef __cplusplus 95 | } 96 | #endif 97 | -------------------------------------------------------------------------------- /src/crtl/core/include/crtl/crtl_parameter_block.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "crtl_buffer.h" 4 | #include "crtl_core.h" 5 | #include "crtl_device.h" 6 | 7 | #ifdef __cplusplus 8 | namespace crtl_rhi { 9 | struct ParameterBlock : APIObject {}; 10 | struct ShaderRecordParameterBlock : ParameterBlock {}; 11 | struct GlobalParameterBlock : ParameterBlock {}; 12 | } 13 | typedef crtl_rhi::ParameterBlock *CRTLParameterBlock; 14 | typedef crtl_rhi::ShaderRecordParameterBlock *CRTLShaderRecordParameterBlock; 15 | typedef crtl_rhi::GlobalParameterBlock *CRTLGlobalParameterBlock; 16 | #else 17 | typedef CRTLAPIObject CRTLParameterBlock; 18 | typedef CRTLAPIObject CRTLShaderRecordParameterBlock; 19 | typedef CRTLAPIObject CRTLGlobalParameterBlock; 20 | #endif 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | CRTL_EXPORT CRTL_ERROR crtl_set_parameter(CRTLDevice device, 27 | CRTLParameterBlock parameter_block, 28 | const char *name, 29 | CRTL_DATA_TYPE data_type, 30 | void *parameter); 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | -------------------------------------------------------------------------------- /src/crtl/core/include/crtl/crtl_rtpipeline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "crtl_buffer.h" 5 | #include "crtl_device.h" 6 | #include "crtl_geometry.h" 7 | #include "crtl_parameter_block.h" 8 | #include "crtl_shader.h" 9 | 10 | #ifdef __cplusplus 11 | namespace crtl_rhi { 12 | struct RTPipeline : APIObject {}; 13 | } 14 | typedef crtl_rhi::RTPipeline *CRTLRTPipeline; 15 | #else 16 | typedef CRTLAPIObject CRTLRTPipeline; 17 | #endif 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | // TODO: Alternative to passing the shader_library to get global params would be to 24 | // perform a "link" step in crtl_build_shader_table where we merge globals from different 25 | // shader libraries by matching their variable names? This would allow separate files to 26 | // be passed to make individual shader libraries that are linked together, at least 27 | // "linked" in the global parameter passing sense. Right now this is a bit error prone, 28 | // it's easy to pass raygen record/miss record/scene using different shader libraries than 29 | // this one or each other to the pipeline 30 | // Error checking can be done using the shader library of the entry point though to 31 | // validate that all shaders in the pipeline are from the same shader library 32 | CRTL_EXPORT CRTL_ERROR crtl_new_rtpipeline(CRTLDevice device, 33 | CRTLShaderLibrary shader_library, 34 | uint32_t n_miss_records, 35 | CRTLRTPipeline *pipeline); 36 | 37 | // Some limitations/things to check here: the raygen record has to come from the shader 38 | // library 39 | CRTL_EXPORT CRTL_ERROR crtl_set_raygen_record(CRTLDevice device, 40 | CRTLRTPipeline pipeline, 41 | CRTLShaderRecord raygen_record); 42 | 43 | // Some limitations/things to check here: the miss record has to come from the shader 44 | // library 45 | CRTL_EXPORT CRTL_ERROR crtl_set_miss_record(CRTLDevice device, 46 | CRTLRTPipeline pipeline, 47 | uint32_t index, 48 | CRTLShaderRecord miss_record); 49 | 50 | // Some limitations/things to check here: the scene has to use shaders all from 51 | // the shader library passed 52 | CRTL_EXPORT CRTL_ERROR crtl_set_scene(CRTLDevice device, 53 | CRTLRTPipeline pipeline, 54 | CRTLScene scene); 55 | 56 | // TODO: Also support for callable shaders? 57 | 58 | // Will note: build SBT is separate step on host, then uploading it happens on the queue 59 | // so apps can control when the actual GPU upload step happens 60 | CRTL_EXPORT CRTL_ERROR crtl_build_shader_table(CRTLDevice device, 61 | CRTLRTPipeline pipeline); 62 | 63 | #ifdef __cplusplus 64 | } 65 | #endif 66 | -------------------------------------------------------------------------------- /src/crtl/core/include/crtl/crtl_shader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "crtl_core.h" 4 | #include "crtl_device.h" 5 | #include "crtl_parameter_block.h" 6 | 7 | #ifdef __cplusplus 8 | namespace crtl_rhi { 9 | struct ShaderLibrary : APIObject {}; 10 | struct ShaderEntryPoint : APIObject {}; 11 | struct ShaderRecord : APIObject {}; 12 | struct HitGroupRecord : ShaderRecord {}; 13 | struct MissRecord : ShaderRecord {}; 14 | struct RaygenRecord : ShaderRecord {}; 15 | } 16 | typedef crtl_rhi::ShaderLibrary *CRTLShaderLibrary; 17 | typedef crtl_rhi::ShaderEntryPoint *CRTLShaderEntryPoint; 18 | typedef crtl_rhi::ShaderRecord *CRTLShaderRecord; 19 | typedef crtl_rhi::HitGroupRecord *CRTLHitGroupRecord; 20 | typedef crtl_rhi::MissRecord *CRTLMissRecord; 21 | typedef crtl_rhi::RaygenRecord *CRTLRaygenRecord; 22 | #else 23 | typedef CRTLAPIObject CRTLShaderLibrary; 24 | typedef CRTLAPIObject CRTLShaderEntryPoint; 25 | typedef CRTLAPIObject CRTLShaderRecord; 26 | typedef CRTLShaderRecord CRTLHitGroupRecord; 27 | typedef CRTLShaderRecord CRTLMissRecord; 28 | typedef CRTLShaderRecord CRTLRaygenRecord; 29 | #endif 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | CRTL_EXPORT CRTL_ERROR crtl_new_shader_library(CRTLDevice device, 36 | const char *library_src, 37 | CRTLShaderLibrary *shader_library); 38 | 39 | CRTL_EXPORT CRTL_ERROR 40 | crtl_new_global_parameter_block(CRTLDevice device, 41 | CRTLShaderLibrary shader_library, 42 | CRTLGlobalParameterBlock *parameter_block); 43 | 44 | CRTL_EXPORT CRTL_ERROR crtl_get_shader_entry_point(CRTLDevice device, 45 | CRTLShaderLibrary shader_library, 46 | const char *entry_point_name, 47 | CRTLShaderEntryPoint *entry_point); 48 | 49 | CRTL_EXPORT CRTL_ERROR 50 | crtl_new_hitgroup_record(CRTLDevice device, 51 | CRTLShaderEntryPoint closest_hit, 52 | CRTLShaderEntryPoint intersection_optional, 53 | CRTLShaderEntryPoint any_hit_optional, 54 | CRTLHitGroupRecord *shader_record); 55 | 56 | CRTL_EXPORT CRTL_ERROR crtl_new_miss_record(CRTLDevice device, 57 | CRTLShaderEntryPoint miss, 58 | CRTLMissRecord *shader_record); 59 | 60 | CRTL_EXPORT CRTL_ERROR crtl_new_raygen_record(CRTLDevice device, 61 | CRTLShaderEntryPoint raygen, 62 | CRTLRaygenRecord *shader_record); 63 | 64 | CRTL_EXPORT CRTL_ERROR 65 | crtl_new_shader_record_parameter_block(CRTLDevice device, 66 | CRTLShaderRecord shader_record, 67 | CRTLShaderRecordParameterBlock *parameter_block); 68 | 69 | CRTL_EXPORT CRTL_ERROR 70 | crtl_set_shader_record_parameter_block(CRTLDevice device, 71 | CRTLShaderRecord shader_record, 72 | CRTLShaderRecordParameterBlock parameter_block); 73 | 74 | #ifdef __cplusplus 75 | } 76 | #endif 77 | -------------------------------------------------------------------------------- /src/crtl/core/include/crtl/crtl_texture.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "crtl_device.h" 5 | #include "crtl_enums.h" 6 | 7 | #ifdef __cplusplus 8 | namespace crtl_rhi { 9 | struct Texture : APIObject {}; 10 | } 11 | typedef crtl_rhi::Texture *CRTLTexture; 12 | #else 13 | typedef CRTLAPIObject CRTLTexture; 14 | #endif 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | /* Allocate a new texture with the desired format and dimensionality 21 | * TODO: Also need to pass usage modes here, for vulkan/dx12 22 | */ 23 | CRTL_EXPORT CRTL_ERROR crtl_new_texture(CRTLDevice device, 24 | CRTL_TEXTURE_TYPE texture_type, 25 | CRTL_IMAGE_FORMAT format, 26 | CRTL_IMAGE_USAGE usages, 27 | const uint32_t dimensions[3], 28 | CRTLTexture *texture); 29 | 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | -------------------------------------------------------------------------------- /src/crtl/core/shader_entry_point.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace crtl { 4 | /* A ShaderEntryPoint is a single callable shader function that can be called during 5 | * rendering or as a compute shader (depending on the entry point type). E.g., a raygen 6 | * function, closesthit function, or compute kernel. 7 | */ 8 | class ShaderEntryPoint { 9 | public: 10 | virtual ~ShaderEntryPoint() = default; 11 | 12 | // TODO: An API to get the layout for the parameters. 13 | // Some parameters will be pushed up to be global scope by necessity, 14 | // e.g. we cannot pass textures through the SBT 15 | // Alternatively: CRTL can enforce the same restriction on apps, textures and samplers 16 | // cannot be passed in the SBT. That would be easiest for a first prototype 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /src/crtl/core/shader_library.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "shader_entry_point.h" 7 | 8 | namespace crtl { 9 | 10 | /* A ShaderLibrary stores the entire set of entry points that may be called within a given 11 | * RayTracingPipeline. 12 | * 13 | * A future TODO is to allow this library to be created from multiple source files and 14 | * perform some form of name-based linking for global parameters and etc. 15 | */ 16 | class ShaderLibrary { 17 | public: 18 | virtual ~ShaderLibrary() = default; 19 | 20 | // TODO: Maybe a free-function that takes the shader lib shared ptr to keep it alive? 21 | // May need to ref data from it for setting params that are pushed to be globals 22 | virtual std::shared_ptr entry_point(const std::string &name) = 0; 23 | 24 | // TODO: Here API to get global param layout 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /src/crtl/core/type.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "crtl/crtl.h" 7 | 8 | namespace crtl { 9 | namespace ty { 10 | // Note a huge fan of the inheritance setup + allocations pushed by this design, 11 | // but need to work on general types set at runtime 12 | 13 | // Similar to CRTL AST side, but we only care about types that can be sent as parameters 14 | enum class BaseType { 15 | INVALID, 16 | PRIMITIVE, 17 | VECTOR, 18 | MATRIX, 19 | // TODO: struct is more challenging to handle b/c of alignment differences.. 20 | // STRUCT, 21 | BUFFER_VIEW, 22 | TEXTURE, 23 | ACCELERATION_STRUCTURE, 24 | }; 25 | 26 | enum class PrimitiveType { 27 | INVALID, 28 | // TODO: Maybe don't support bool as a shader parameter type? 29 | // also alignment issues C++ vs shader lang, it will just be a 4-byte size object in 30 | // the shader 31 | // BOOL, 32 | INT, 33 | UINT, 34 | FLOAT, 35 | DOUBLE, 36 | }; 37 | 38 | enum class Access { 39 | READ_ONLY, 40 | READ_WRITE, 41 | }; 42 | 43 | class CRTL_EXPORT Type { 44 | public: 45 | BaseType base_type = BaseType::INVALID; 46 | 47 | Type(const BaseType base_type); 48 | 49 | virtual ~Type() = default; 50 | 51 | virtual CRTL_DATA_TYPE data_type() const = 0; 52 | 53 | // Get the size in bytes of the type 54 | virtual size_t size() const = 0; 55 | }; 56 | 57 | // Parse the type info out of the compiler JSON type string output 58 | std::shared_ptr CRTL_EXPORT parse_type(const std::string &type_str); 59 | 60 | class CRTL_EXPORT Primitive : public Type { 61 | public: 62 | PrimitiveType primitive_type; 63 | 64 | Primitive(const PrimitiveType primitive_type); 65 | 66 | CRTL_DATA_TYPE data_type() const override; 67 | 68 | size_t size() const override; 69 | }; 70 | 71 | class CRTL_EXPORT Vector : public Type { 72 | public: 73 | Primitive element_type = PrimitiveType::INVALID; 74 | uint32_t dimensionality = 0; 75 | 76 | Vector(const Primitive element_type, const uint32_t dimensionality); 77 | 78 | CRTL_DATA_TYPE data_type() const override; 79 | 80 | size_t size() const override; 81 | }; 82 | 83 | class CRTL_EXPORT Matrix : public Type { 84 | public: 85 | Primitive element_type = PrimitiveType::INVALID; 86 | uint32_t dim_0 = 0; 87 | uint32_t dim_1 = 0; 88 | 89 | Matrix(const Primitive element_type, const uint32_t dim_0, const uint32_t dim_1); 90 | 91 | CRTL_DATA_TYPE data_type() const override; 92 | 93 | size_t size() const override; 94 | }; 95 | 96 | class CRTL_EXPORT BufferView : public Type { 97 | public: 98 | // TODO: Maybe some struct in buffer support? Handling the alignment may be tricky, 99 | // could use the scalar buffer in Vulkan and maybe byte address buffer in DXR? 100 | std::shared_ptr element_type; 101 | Access access; 102 | 103 | BufferView(const std::shared_ptr &element_type, const Access &access); 104 | 105 | CRTL_DATA_TYPE data_type() const override; 106 | 107 | size_t size() const override; 108 | }; 109 | 110 | class CRTL_EXPORT Texture : public Type { 111 | public: 112 | std::shared_ptr texel_type; 113 | Access access; 114 | uint32_t dimensionality = 0; 115 | 116 | Texture(const std::shared_ptr texel_type, 117 | const Access &access, 118 | const uint32_t dimensionality); 119 | 120 | CRTL_DATA_TYPE data_type() const override; 121 | 122 | CRTL_TEXTURE_TYPE texture_type() const; 123 | 124 | size_t size() const override; 125 | }; 126 | 127 | class CRTL_EXPORT AccelerationStructure : public Type { 128 | public: 129 | AccelerationStructure(); 130 | 131 | CRTL_DATA_TYPE data_type() const override; 132 | 133 | size_t size() const override; 134 | }; 135 | 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/crtl/core/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "crtl/crtl_enums.h" 6 | #include "crtl_export.h" 7 | 8 | namespace crtl { 9 | 10 | // Format the count as #G, #M, #K, depending on its magnitude 11 | CRTL_EXPORT std::string pretty_print_count(const double count); 12 | 13 | CRTL_EXPORT uint64_t align_to(uint64_t val, uint64_t align); 14 | 15 | CRTL_EXPORT void ortho_basis(glm::vec3 &v_x, glm::vec3 &v_y, const glm::vec3 &n); 16 | 17 | CRTL_EXPORT void canonicalize_path(std::string &path); 18 | 19 | CRTL_EXPORT std::string get_file_extension(const std::string &fname); 20 | 21 | CRTL_EXPORT std::string get_cpu_brand(); 22 | 23 | CRTL_EXPORT float srgb_to_linear(const float x); 24 | 25 | CRTL_EXPORT float linear_to_srgb(const float x); 26 | 27 | CRTL_EXPORT float luminance(const glm::vec3 &c); 28 | 29 | CRTL_EXPORT std::wstring utf8_to_utf16(const std::string &utf8); 30 | 31 | CRTL_EXPORT std::string utf16_to_utf8(const std::wstring &utf16); 32 | 33 | CRTL_EXPORT size_t data_type_size(CRTL_DATA_TYPE type); 34 | } 35 | -------------------------------------------------------------------------------- /src/crtl/grammar/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Setup ANTLR 2 | set(ANTLR4_WITH_STATIC_CRT OFF) 3 | include(ExternalAntlr4Cpp) 4 | find_package(ANTLR REQUIRED) 5 | 6 | include(ANTLRGrammarUtil) 7 | 8 | # Add the ChameleonRT Grammar 9 | antlr_target(crtl_grammar 10 | PACKAGE crtg 11 | LEXER ChameleonRTLexer.g4 12 | PARSER ChameleonRTParser.g4 13 | VISITOR) 14 | 15 | antlr_grammar_util(ChameleonRTGrammarUtil 16 | LEXER ChameleonRTLexer.g4 17 | PARSER ChameleonRTParser.g4) 18 | 19 | target_include_directories(crtl_grammar PUBLIC 20 | ${CMAKE_CURRENT_BINARY_DIR}/antlr4java_generated_src/ 21 | ${ANTLR4_INCLUDE_DIRS}) 22 | 23 | target_compile_definitions(crtl_grammar PUBLIC 24 | -DANTLR4CPP_STATIC) 25 | 26 | set_target_properties(crtl_grammar PROPERTIES 27 | WINDOWS_EXPORT_ALL_SYMBOLS ON) 28 | 29 | -------------------------------------------------------------------------------- /src/crtl/grammar/ChameleonRTLexer.g4: -------------------------------------------------------------------------------- 1 | lexer grammar ChameleonRTLexer; 2 | 3 | // Control flow 4 | 5 | IF: 'if'; 6 | ELSE: 'else'; 7 | FOR: 'for'; 8 | WHILE: 'while'; 9 | DO: 'do'; 10 | CONTINUE: 'continue'; 11 | BREAK: 'break'; 12 | SWITCH: 'switch'; 13 | CASE: 'case'; 14 | DEFAULT: 'default'; 15 | 16 | // Types 17 | 18 | BOOL: 'bool'; 19 | 20 | BOOL2: 'bool2'; 21 | BOOL3: 'bool3'; 22 | BOOL4: 'bool4'; 23 | 24 | BOOL2X1: 'bool2x1'; 25 | BOOL3X1: 'bool3x1'; 26 | BOOL4X1: 'bool4x1'; 27 | 28 | BOOL1X2: 'bool1x2'; 29 | BOOL2X2: 'bool2x2'; 30 | BOOL3X2: 'bool3x2'; 31 | BOOL4X2: 'bool4x2'; 32 | 33 | BOOL1X3: 'bool1x3'; 34 | BOOL2X3: 'bool2x3'; 35 | BOOL3X3: 'bool3x3'; 36 | BOOL4X3: 'bool4x3'; 37 | 38 | BOOL1X4: 'bool1x4'; 39 | BOOL2X4: 'bool2x4'; 40 | BOOL3X4: 'bool3x4'; 41 | BOOL4X4: 'bool4x4'; 42 | 43 | INT: 'int'; 44 | 45 | INT2: 'int2'; 46 | INT3: 'int3'; 47 | INT4: 'int4'; 48 | 49 | INT2X1: 'int2x1'; 50 | INT3X1: 'int3x1'; 51 | INT4X1: 'int4x1'; 52 | 53 | INT1X2: 'int1x2'; 54 | INT2X2: 'int2x2'; 55 | INT3X2: 'int3x2'; 56 | INT4X2: 'int4x2'; 57 | 58 | INT1X3: 'int1x3'; 59 | INT2X3: 'int2x3'; 60 | INT3X3: 'int3x3'; 61 | INT4X3: 'int4x3'; 62 | 63 | INT1X4: 'int1x4'; 64 | INT2X4: 'int2x4'; 65 | INT3X4: 'int3x4'; 66 | INT4X4: 'int4x4'; 67 | 68 | UINT: 'uint'; 69 | 70 | UINT2: 'uint2'; 71 | UINT3: 'uint3'; 72 | UINT4: 'uint4'; 73 | 74 | UINT2X1: 'uint2x1'; 75 | UINT3X1: 'uint3x1'; 76 | UINT4X1: 'uint4x1'; 77 | 78 | UINT1X2: 'uint1x2'; 79 | UINT2X2: 'uint2x2'; 80 | UINT3X2: 'uint3x2'; 81 | UINT4X2: 'uint4x2'; 82 | 83 | UINT1X3: 'uint1x3'; 84 | UINT2X3: 'uint2x3'; 85 | UINT3X3: 'uint3x3'; 86 | UINT4X3: 'uint4x3'; 87 | 88 | UINT1X4: 'uint1x4'; 89 | UINT2X4: 'uint2x4'; 90 | UINT3X4: 'uint3x4'; 91 | UINT4X4: 'uint4x4'; 92 | 93 | FLOAT: 'float'; 94 | 95 | FLOAT2: 'float2'; 96 | FLOAT3: 'float3'; 97 | FLOAT4: 'float4'; 98 | 99 | FLOAT2X1: 'float2x1'; 100 | FLOAT3X1: 'float3x1'; 101 | FLOAT4X1: 'float4x1'; 102 | 103 | FLOAT1X2: 'float1x2'; 104 | FLOAT2X2: 'float2x2'; 105 | FLOAT3X2: 'float3x2'; 106 | FLOAT4X2: 'float4x2'; 107 | 108 | FLOAT1X3: 'float1x3'; 109 | FLOAT2X3: 'float2x3'; 110 | FLOAT3X3: 'float3x3'; 111 | FLOAT4X3: 'float4x3'; 112 | 113 | FLOAT1X4: 'float1x4'; 114 | FLOAT2X4: 'float2x4'; 115 | FLOAT3X4: 'float3x4'; 116 | FLOAT4X4: 'float4x4'; 117 | 118 | DOUBLE: 'double'; 119 | 120 | DOUBLE2: 'double2'; 121 | DOUBLE3: 'double3'; 122 | DOUBLE4: 'double4'; 123 | 124 | DOUBLE2X1: 'double2x1'; 125 | DOUBLE3X1: 'double3x1'; 126 | DOUBLE4X1: 'double4x1'; 127 | 128 | DOUBLE1X2: 'double1x2'; 129 | DOUBLE2X2: 'double2x2'; 130 | DOUBLE3X2: 'double3x2'; 131 | DOUBLE4X2: 'double4x2'; 132 | 133 | DOUBLE1X3: 'double1x3'; 134 | DOUBLE2X3: 'double2x3'; 135 | DOUBLE3X3: 'double3x3'; 136 | DOUBLE4X3: 'double4x3'; 137 | 138 | DOUBLE1X4: 'double1x4'; 139 | DOUBLE2X4: 'double2x4'; 140 | DOUBLE3X4: 'double3x4'; 141 | DOUBLE4X4: 'double4x4'; 142 | 143 | BUFFER: 'Buffer'; 144 | RWBUFFER: 'RWBuffer'; 145 | 146 | TEXTURE: 'Texture' [1-3] 'D'; 147 | RWTEXTURE: 'RWTexture' [1-3] 'D'; 148 | 149 | ACCELERATION_STRUCTURE: 'AccelerationStructure'; 150 | RAY: 'Ray'; 151 | 152 | VOID: 'void'; 153 | 154 | STRUCT: 'struct'; 155 | 156 | TRUE: 'true'; 157 | FALSE: 'false'; 158 | 159 | // Other keywords 160 | 161 | RAY_GEN: 'ray_gen'; 162 | CLOSEST_HIT: 'closest_hit'; 163 | ANY_HIT: 'any_hit'; 164 | INTERSECTION: 'intersection'; 165 | MISS: 'miss'; 166 | COMPUTE: 'compute'; 167 | 168 | CONST: 'const'; 169 | OUT: 'out'; 170 | IN: 'in'; 171 | IN_OUT: 'inout'; 172 | 173 | RETURN: 'return'; 174 | 175 | // Operators 176 | 177 | MINUS: '-'; 178 | BANG: '!'; 179 | PLUS: '+'; 180 | STAR: '*'; 181 | SLASH: '/'; 182 | PLUS_PLUS: '++'; 183 | LESS: '<'; 184 | LESS_EQUAL: '<='; 185 | GREATER: '>'; 186 | GREATER_EQUAL: '>='; 187 | NOT_EQUAL: '!='; 188 | EQUAL_EQUAL: '=='; 189 | EQUAL: '='; 190 | 191 | BOOL_AND: '&&'; 192 | BOOL_OR: '||'; 193 | 194 | SEMICOLON: ';'; 195 | COMMA: ','; 196 | PERIOD: '.'; 197 | 198 | // Identifiers and primitives 199 | 200 | INTEGER_LITERAL: ('0' | '-'? [1-9]) [0-9]* 201 | | ('0x' | '0X') [0-9a-fA-F]+ 202 | ; 203 | 204 | // TODO: Exponent parsing 205 | FLOAT_LITERAL: ('0' | '-'? [1-9]) [0-9]* (PERIOD [0-9]+ | PERIOD)? [fF]?; 206 | 207 | IDENTIFIER: [a-zA-Z_] [a-zA-Z0-9_]*; 208 | 209 | // Other 210 | 211 | LEFT_PAREN: '('; 212 | RIGHT_PAREN: ')'; 213 | 214 | LEFT_BRACE: '{'; 215 | RIGHT_BRACE: '}'; 216 | 217 | LEFT_BRACKET: '['; 218 | RIGHT_BRACKET: ']'; 219 | 220 | // TODO: It would be nice to preserve these in the translated source code 221 | LINE_COMMENT: '//' .*? '\r'? '\n' -> skip; 222 | BLOCK_COMMENT: '/*' .*? '*/' -> skip; 223 | WHITESPACE: [ \t\n\r]+ -> skip; 224 | -------------------------------------------------------------------------------- /src/renderer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(Threads REQUIRED) 2 | 3 | find_package(SDL2 CONFIG REQUIRED) 4 | if (NOT TARGET SDL2::SDL2) 5 | # Assume SDL2 is in the default library path and create 6 | # imported targets for it, we re-find the library since 7 | # SDL2_LIBRARIES might just be -lSDL2 8 | find_library(SDL2_SHARED_LIBRARY SDL2 REQUIRED) 9 | 10 | add_library(SDL2::SDL2 SHARED IMPORTED) 11 | set_target_properties(SDL2::SDL2 PROPERTIES 12 | IMPORTED_LOCATION ${SDL2_SHARED_LIBRARY}) 13 | target_include_directories(SDL2::SDL2 INTERFACE 14 | ${SDL2_INCLUDE_DIRS}) 15 | 16 | # Same for SDL2main 17 | find_library(SDL2MAIN_SHARED_LIBRARY SDL2main REQUIRED) 18 | add_library(SDL2::SDL2main SHARED IMPORTED) 19 | set_target_properties(SDL2::SDL2main PROPERTIES 20 | IMPORTED_LOCATION ${SDL2MAIN_SHARED_LIBRARY}) 21 | endif() 22 | 23 | 24 | # Include glm as an external project 25 | if (NOT TARGET glm) 26 | include(${PROJECT_SOURCE_DIR}/cmake/glm.cmake) 27 | endif() 28 | 29 | add_executable(crtl_test_renderer main.cpp) 30 | 31 | set_target_properties(crtl_test_renderer PROPERTIES 32 | CXX_STANDARD 17 33 | CXX_STANDARD_REQUIRED ON) 34 | 35 | target_link_libraries(crtl_test_renderer PUBLIC 36 | glm 37 | SDL2::SDL2 38 | SDL2::SDL2main 39 | crtl) 40 | 41 | # Set the debugger command for visual studio so it's easier 42 | # to launch the debugger 43 | set_target_properties(crtl_test_renderer PROPERTIES 44 | VS_DEBUGGER_COMMAND ${PROJECT_BINARY_DIR}/$/crtl_test_renderer.exe) 45 | 46 | -------------------------------------------------------------------------------- /tests/sketch.crtl: -------------------------------------------------------------------------------- 1 | struct HitInfo { 2 | float3 color; 3 | }; 4 | 5 | struct CameraParams { 6 | // Constants for global params would be packed into a UBO or SBO 7 | float3 cam_pos; 8 | float3 cam_du; 9 | float3 cam_dv; 10 | float3 cam_dir_top_left; 11 | }; 12 | 13 | struct SceneParams { 14 | // AS's, textures, buffers, would be passed through as global params 15 | AccelerationStructure scene; 16 | // It looks like HLSL doesn't distinguish writeonly/readonly vs. readwrite, 17 | // so it's simplest to adopt the HLSL naming here and do either RWTexture2D 18 | // or RWBuffer, meaning readwrite, or Texture2D, Buffer, meaning read only. 19 | RWTexture2D image; 20 | }; 21 | 22 | // TODO: User defined structs passed through globals or 23 | // SBT params will need some thought to support 24 | struct RayGenParams { 25 | uint num_lights; 26 | }; 27 | 28 | // Raygen and global params can be put into a uniform or storage buffer for GLSL, 29 | // and similar in HLSL to make these into globally accessible parameters. 30 | // Also generate a struct that corresponds to the global params to make it 31 | // easier to set them. 32 | // There can be multiple global params, and they can be a mix of constants and 33 | // AS's, textures, buffers. 34 | in SceneParams scene; 35 | in CameraParams camera; 36 | 37 | const int x = 5; 38 | 39 | ray_gen RayGen(RayGenParams params) 40 | { 41 | // TODO: Do need to know the type the built in functions return in case 42 | // a conversion is needed here for example. 43 | uint2 pixel = ray_index(); 44 | Ray ray; 45 | // ray set up 46 | HitInfo hit_info; 47 | // Params are: accel struct, ray, payload, flags, mask, hit group ray offset, 48 | // hit group ray stride, miss group offset 49 | trace_ray(scene.scene, ray, hit_info, RAY_FLAG_FORCE_OPAQUE, 0xff, 0, 1, 0); 50 | scene.image[pixel] = hit_info.color; 51 | } 52 | 53 | // A test standalone shader function that takes a buffer 54 | float3 get_value(in Buffer b, const int i) 55 | { 56 | return b[i]; 57 | } 58 | 59 | // Params to closest_hit/any_hit/miss shaders would be put into SBT 60 | // Need C struct generated to match these up for convenience in setting 61 | // params on the host, need to know size this struct will be. 62 | struct ClosestHitParams { 63 | Buffer indices; 64 | Buffer positions; 65 | }; 66 | 67 | closest_hit ClosestHit(HitInfo hit_info, Attributes attribs, ClosestHitParams params) 68 | { 69 | const uint3 idx = params.indices[primitive_index()]; 70 | const float3 va = get_value(params.positions, idx.x); 71 | const float3 vb = get_value(params.positions, idx.y); 72 | const float3 vc = get_value(params.positions, idx.z); 73 | const float3 normal = normalize(cross(vb - va, vc - va)); 74 | hit_info.color = (normal + 1.f) * 0.5f; 75 | } 76 | 77 | struct MissParams { 78 | float3 background_color; 79 | }; 80 | 81 | miss Miss(HitInfo hit_info, MissParams params) 82 | { 83 | hit_info.color = params.background_color; 84 | } 85 | -------------------------------------------------------------------------------- /tests/sketch.glsl: -------------------------------------------------------------------------------- 1 | // TODO: Note: Each entry point would be output to separate files with some 2 | // repetition of the shared types in the top of the file in each 3 | 4 | // Shared definitions: 5 | struct HitInfo { 6 | float3 color; 7 | }; 8 | 9 | struct CameraParams { 10 | // Constants for global params would be packed into a UBO or SBO 11 | vec3 cam_pos; 12 | vec3 cam_du; 13 | vec3 cam_dv; 14 | vec3 cam_dir_top_left; 15 | }; 16 | 17 | /* 18 | struct SceneParams { 19 | // AS's, textures, buffers, would be passed through as global params 20 | AccelerationStructure scene; 21 | // It looks like HLSL doesn't distinguish writeonly/readonly vs. readwrite, 22 | // so it's simplest to adopt the HLSL naming here and do either RWTexture2D 23 | // or RWBuffer, meaning readwrite, or Texture2D, Buffer, meaning read only. 24 | RWTexture2D image; 25 | }; 26 | */ 27 | 28 | // Raygen and global params can be put into a uniform or storage buffer for GLSL, 29 | // and similar in HLSL to make these into globally accessible parameters. 30 | // Also generate a struct that corresponds to the global params to make it 31 | // easier to set them. 32 | // There can be multiple global params, and they can be a mix of constants and 33 | // AS's, textures, buffers. 34 | // in SceneParams scene; 35 | layout(binding = 0, set = 0) uniform accelerationStructureEXT scene_scene; 36 | layout(binding = 1, set = 0) uniform image2D scene_image; 37 | 38 | // in CameraParams camera; 39 | layout(binding = 2, set = 0, scalar) uniform CameraParams_b2_s0 40 | { 41 | CameraParams camera; 42 | }; 43 | 44 | const int x = 5; 45 | 46 | // Shared buffer reference types 47 | layout(buffer_reference, buffer_reference_align = 8, scalar) buffer Buffer_uint3 48 | { 49 | uvec3 data[]; 50 | }; 51 | 52 | layout(buffer_reference, buffer_reference_align = 8, scalar) buffer Buffer_float3 53 | { 54 | vec3 data[]; 55 | }; 56 | 57 | // And the ray payloads which must be globally visible here 58 | layout(location = 0) rayPayloadInEXT HitInfo hit_info; 59 | 60 | // A test standalone shader function that takes a buffer 61 | vec3 get_value(in Buffer_float3 b, const int i) 62 | { 63 | return b.data[i]; 64 | } 65 | 66 | // --- end shared definitions ----- 67 | 68 | // ------ 69 | // Output raygen shader file 70 | // ------ 71 | layout(shaderRecordEXT, std430) buffer RayGen_SBT_Data 72 | { 73 | uint RayGen_params_num_lights; 74 | }; 75 | 76 | void main() 77 | { 78 | uvec2 pixel = gl_LaunchIDEXT.xy; 79 | Ray ray; 80 | traceRayEXT(scene_scene, 81 | gl_RayFlagsOpaqueEXT, 82 | 0xff, 83 | 0, 84 | 1, 85 | 0, 86 | ray.origin, 87 | ray.t_min, 88 | ray.dir, 89 | ray.t_max, 90 | 0); 91 | 92 | // Note: I think a conversion is needed here to ivec2 for imageStore 93 | imageStore(scene_image, pixel, hit_info.color); 94 | } 95 | 96 | // ------ 97 | // Output hit shader file 98 | // ------ 99 | layout(shaderRecordEXT, std430) buffer ClosestHit_SBT_Data 100 | { 101 | Buffer_uint3 params_indices; 102 | Buffer_float3 params_positions; 103 | }; 104 | 105 | void main() 106 | { 107 | ClosestHitParams params; 108 | params.indices = indices; 109 | params.positions = positions; 110 | 111 | const uvec3 idx = params.indices[gl_PrimitiveID]; 112 | const vec3 va = get_value(params.positions, idx.x); 113 | const vec3 vb = get_value(params.positions, idx.y); 114 | const vec3 vc = get_value(params.positions, idx.z); 115 | const vec3 normal = normalize(cross(vb - va, vc - va)); 116 | hit_info.color = (normal + 1.f) * 0.5f; 117 | } 118 | 119 | // ------ 120 | // Output miss shader file 121 | // ------ 122 | layout(shaderRecordEXT, std430) buffer Miss_SBT_Data 123 | { 124 | vec3 params_background_color; 125 | }; 126 | 127 | void main() 128 | { 129 | MissParams params; 130 | params.background_color = params_background_color; 131 | 132 | hit_info.color = params.background_color; 133 | } 134 | 135 | -------------------------------------------------------------------------------- /tests/sketch.hlsl: -------------------------------------------------------------------------------- 1 | struct HitInfo { 2 | float3 color; 3 | }; 4 | 5 | struct CameraParams { 6 | // Constants for global params would be packed into a UBO or SBO 7 | float3 cam_pos; 8 | float3 cam_du; 9 | float3 cam_dv; 10 | float3 cam_dir_top_left; 11 | }; 12 | 13 | /* 14 | struct SceneParams { 15 | // AS's, textures, buffers, would be passed through as global params 16 | AccelerationStructure scene; 17 | // It looks like HLSL doesn't distinguish writeonly/readonly vs. readwrite, 18 | // so it's simplest to adopt the HLSL naming here and do either RWTexture2D 19 | // or RWBuffer, meaning readwrite, or Texture2D, Buffer, meaning read only. 20 | RWTexture2D image; 21 | }; 22 | */ 23 | 24 | // SBT params will need some thought to support 25 | /* 26 | struct RayGenParams { 27 | uint num_lights; 28 | }; 29 | */ 30 | 31 | // Raygen and global params can be put into a uniform or storage buffer for GLSL, 32 | // and similar in HLSL to make these into globally accessible parameters. 33 | // Also generate a struct that corresponds to the global params to make it 34 | // easier to set them. 35 | // There can be multiple global params, and they can be a mix of constants and 36 | // AS's, textures, buffers. 37 | // in SceneParams scene; 38 | RayTracingAccelerationStructure scene_scene : register(t0); 39 | RWTexture2D scene_image : register(u0); 40 | 41 | // in CameraParams camera; 42 | cbuffer CameraParams_b0_s0 : register(b0) 43 | { 44 | CameraParams camera; 45 | } 46 | 47 | const int x = 5; 48 | 49 | // TODO change this to match small.hlsl 50 | cbuffer RayGenParams : register(b0, space1) 51 | { 52 | uint32_t RayGen_params_num_lights; 53 | } 54 | 55 | [shader("raygeneration")] 56 | void RayGen() { 57 | uint2 pixel = DispatchRaysIndex().xy; 58 | RayDesc ray; 59 | // ray set up 60 | HitInfo hit_info; 61 | TraceRay( 62 | scene_scene, RAY_FLAG_FORCE_OPAQUE, 0xff, 0, 1, 0, ray, hit_info); 63 | scene_image[pixel] = hit_info.color; 64 | } 65 | 66 | // A test standalone shader function that takes a buffer 67 | float3 get_value(in StructuredBuffer b, const int i) 68 | { 69 | // TODO: would be better to not be so pessimistic about putting this marker in 70 | return b[NonUniformResourceIndex(i)]; 71 | } 72 | 73 | // Params to closest_hit/any_hit/miss shaders would be put into SBT 74 | // Need C struct generated to match these up for convenience in setting 75 | // params on the host, need to know size this struct will be. 76 | struct ClosestHitParams { 77 | StructuredBuffer indices; 78 | StructuredBuffer positions; 79 | }; 80 | 81 | StructuredBuffer ClosestHit_hit_info_indices : register(t0, space2); 82 | StructuredBuffer ClosestHit_hit_info_positions : register(t1, space2); 83 | 84 | [shader("closesthit")] 85 | void ClosestHit(inout HitInfo hit_info : SV_RayPayload, Attributes attribs) { 86 | ClosestHitParams params; 87 | params.indices = ClosestHit_hit_info_indices; 88 | params.positions = ClosestHit_hit_info_positions; 89 | 90 | const uint3 idx = params.indices[NonUniformResourceIndex(PrimitiveIndex())]; 91 | const float3 va = get_value(params.positions, idx.x); 92 | const float3 vb = get_value(params.positions, idx.y); 93 | const float3 vc = get_value(params.positions, idx.z); 94 | const float3 normal = normalize(cross(vb - va, vc - va)); 95 | hit_info.color = (normal + 1.f) * 0.5f; 96 | } 97 | 98 | struct MissParams { 99 | float3 background_color; 100 | }; 101 | 102 | cbuffer MissConstants : register(b0, space3) { 103 | float3 Miss_params_background_color; 104 | } 105 | 106 | [shader("miss")] 107 | void Miss(inout HitInfo hit_info : SV_RayPayload) 108 | { 109 | MissParams params; 110 | params.background_color = Miss_params_background_color; 111 | 112 | hit_info.color = params.background_color; 113 | } 114 | 115 | -------------------------------------------------------------------------------- /tests/small.crtl: -------------------------------------------------------------------------------- 1 | struct SceneParams { 2 | RWTexture2D image; 3 | float test_constant; 4 | }; 5 | 6 | in SceneParams scene; 7 | 8 | struct RayGenParams { 9 | float4 color; 10 | Buffer data; 11 | }; 12 | 13 | ray_gen RayGen(RayGenParams params, float scale_factor) 14 | { 15 | // TODO: Do need to know the type the built in functions return in case 16 | // a conversion is needed here for example. 17 | uint2 pixel = ray_index(); 18 | float4 c; 19 | c = params.color * scene.test_constant + params.data[0]; 20 | scene.image[pixel] = params.color * scale_factor * c; 21 | } 22 | -------------------------------------------------------------------------------- /tests/small.hlsl: -------------------------------------------------------------------------------- 1 | /* 2 | struct SceneParams { 3 | RWTexture2D image; 4 | float test_constant; 5 | }; 6 | */ 7 | 8 | // in SceneParams scene; 9 | RWTexture2D scene_image : register(u0, space0); 10 | cbuffer scene_cbv : register(b0, space0) 11 | { 12 | float scene_test_constant; 13 | } 14 | 15 | struct RayGenParams { 16 | float4 color; 17 | }; 18 | 19 | cbuffer RayGen_params_cbv : register(b1, space0) 20 | { 21 | float4 RayGen_params_color; 22 | } 23 | 24 | cbuffer scale_factor_cbv : register(b2, space0) 25 | { 26 | float scale_factor; 27 | } 28 | 29 | [shader("raygeneration")] 30 | void RayGen() { 31 | RayGenParams params; 32 | params.color = RayGen_params_color; 33 | { 34 | uint2 pixel = DispatchRaysIndex().xy; 35 | float4 c; 36 | c = params.color; 37 | scene_image[pixel] = params.color * scale_factor; 38 | } 39 | } 40 | 41 | --------------------------------------------------------------------------------