diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..a4d71bc --- /dev/null +++ b/.clang-format @@ -0,0 +1,358 @@ +--- +Language: Cpp +AlignAfterOpenBracket: true +AccessModifierOffset: -1 +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: true + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveShortCaseStatements: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCaseArrows: false + AlignCaseColons: false +AlignConsecutiveTableGenBreakingDAGArgColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveTableGenCondOperatorColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveTableGenDefinitionColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignEscapedNewlines: Left +AlignOperands: Align +AlignTrailingComments: + AlignPPAndNotPP: true + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowBreakBeforeNoexceptSpecifier: Never +AllowBreakBeforeQtProperty: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseExpressionOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortCompoundRequirementOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: true +AllowShortNamespacesOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AttributeMacros: + - __capability + - absl_nonnull + - absl_nullable + - absl_nullability_unknown +BinPackArguments: true +BinPackLongBracedList: true +BinPackParameters: BinPack +BitFieldColonSpacing: Both +BracedInitializerIndentWidth: -1 +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAdjacentStringLiterals: true +BreakAfterAttributes: Leave +BreakAfterJavaFieldAnnotations: false +BreakAfterOpenBracketBracedList: false +BreakAfterOpenBracketFunction: false +BreakAfterOpenBracketIf: false +BreakAfterOpenBracketLoop: false +BreakAfterOpenBracketSwitch: false +BreakAfterReturnType: None +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeCloseBracketBracedList: false +BreakBeforeCloseBracketFunction: false +BreakBeforeCloseBracketIf: false +BreakBeforeCloseBracketLoop: false +BreakBeforeCloseBracketSwitch: false +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Attach +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTemplateCloser: false +BreakBeforeTernaryOperators: true +BreakBinaryOperations: Never +BreakConstructorInitializers: BeforeColon +BreakFunctionDefinitionParameters: false +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +BreakTemplateDeclarations: Yes +ColumnLimit: 120 +CommentPragmas: "^ IWYU pragma:" +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: AlignFirstComment +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +EnumTrailingComma: Leave +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*\.h>' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: "^<.*" + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: ".*" + Priority: 3 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: "([-_](test|unittest))?$" +IncludeIsMainSourceRegex: "" +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: true +IndentExportBlock: true +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigitsInsert: 0 + BinaryMaxDigitsRemove: 0 + Decimal: 0 + DecimalMinDigitsInsert: 0 + DecimalMaxDigitsRemove: 0 + Hex: 0 + HexMinDigitsInsert: 0 + HexMaxDigitsRemove: 0 + BinaryMinDigits: 0 + DecimalMinDigits: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLines: + AtEndOfFile: false + AtStartOfBlock: false + AtStartOfFile: true +KeepFormFeed: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: "" +MacroBlockEnd: "" +MainIncludeChar: Quote +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +NumericLiteralCase: + ExponentLetter: Leave + HexDigit: Leave + Prefix: Leave + Suffix: Leave +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 4 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +OneLineFormatOffRegex: "" +PackConstructorInitializers: NextLine +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakBeforeMemberAccess: 150 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakScopeResolution: 500 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +PPIndentWidth: -1 +QualifierAlignment: Leave +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - "c++" + - "C++" + CanonicalDelimiter: "" + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + - ParseTestProto + - ParsePartialTestProto + CanonicalDelimiter: pb + BasedOnStyle: google +ReferenceAlignment: Pointer +ReflowComments: Always +RemoveBracesLLVM: false +RemoveEmptyLinesInUnwrappedLines: false +RemoveParentheses: Leave +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SkipMacroDefinitionBody: false +SortIncludes: + Enabled: true + IgnoreCase: false + IgnoreExtension: false +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterOperatorKeyword: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeJsonColon: false +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterNot: false + AfterOverloadedOperator: false + AfterPlacementOperator: true + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBraces: Never +SpacesBeforeTrailingComments: 2 +SpacesInAngles: Never +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParens: Never +SpacesInParensOptions: + ExceptDoubleParentheses: false + InCStyleCasts: false + InConditionalStatements: false + InEmptyParentheses: false + Other: false +SpacesInSquareBrackets: false +Standard: Auto +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TableGenBreakInsideDAGArg: DontBreak +TabWidth: 8 +UseTab: Never +VerilogBreakBetweenInstancePorts: true +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +WrapNamespaceBodyWithEmptyLines: Leave +... + diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..adedb95 --- /dev/null +++ b/.clangd @@ -0,0 +1,3 @@ +CompileFlags: + Add: -Wno-unknown-warning-option + Remove: [-m*, -f*] diff --git a/.gitignore b/.gitignore index 636bded..42f8799 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ build/ -.idea +.idea/ +bin/ +/bin/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e843cd..94ba8de 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,42 +1,51 @@ cmake_minimum_required(VERSION 4.1) project(triangle) set(CMAKE_CXX_STANDARD 20) +set(BINARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/bin/${CMAKE_BUILD_TYPE}/") +set(ASSETS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/assets") -##### Project settings ###### +set(BUILD_SHARED_LIBS OFF) -# Set the assets directory -set(ASSETS_DIR "assets") -set(SHADERS_DIR "assets/shaders") - -if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") - set(BUILD_SHARED_LIBS ON) -else() - set(BUILD_SHARED_LIBS OFF) -endif() - -##### Dependencies ##### set(CMAKE_POLICY_VERSION_MINIMUM 3.5) option(ENABLE_CPP20_MODULE "Enable C++ 20 module support for Vulkan" OFF) -file(GLOB CMAKE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/cmake/*.cmake") -foreach(cmake_file ${CMAKE_FILES}) - include(${cmake_file}) -endforeach() -##### Project actions ##### +set (CMAKE_FILES + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/CPM.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/compileCommands.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/platform.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/copy_files.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Vulkan.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/GLFW.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/spirv-headers.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/spirv-tools.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/slang-src.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/spirv-reflect.cmake" +) + +foreach (cmake_file ${CMAKE_FILES}) + include (${cmake_file}) +endforeach () + +create_copy_folder_target(copy_assets_folder ${ASSETS_DIR} "${BINARY_DIR}/assets") -# Define out executable file(GLOB SRC_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") file(GLOB HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h") add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEADER_FILES}) -# Add the shaders dependency -add_dependencies(${PROJECT_NAME} slang_shaders) -add_dependencies(${PROJECT_NAME} glsl_shaders) +set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${BINARY_DIR}") +add_dependencies(${PROJECT_NAME} copy_assets_folder) -target_include_directories(${PROJECT_NAME} PUBLIC "${glfw_SOURCE_DIR}/include") - -# Link with libs -target_link_libraries(${PROJECT_NAME} - glfw - Vulkan::cppm +target_include_directories(${PROJECT_NAME} PUBLIC + "${glfw_SOURCE_DIR}/include" + "${CMAKE_CURRENT_SOURCE_DIR}/src" +) + +target_link_libraries(${PROJECT_NAME} + slang + slang-rt + core # slang::core + SPIRV-Tools-opt + spirv-reflect-static + glfw + Vulkan::cppm ) diff --git a/cmake/GLFW.cmake b/cmake/GLFW.cmake index 5b76e39..3fcdcd1 100644 --- a/cmake/GLFW.cmake +++ b/cmake/GLFW.cmake @@ -6,6 +6,6 @@ CPMAddPackage ( OPTIONS "GLFW_BUILD_DOCS OFF" OPTIONS "GLFW_BUILD_TEST OFF" OPTIONS "GLFW_BUILD_EXAMPLES OFF" - OPTIONS "GLFW_BUILD_X11 OFF" + OPTIONS "GLFW_BUILD_X11 ON" OPTIONS "GLFW_BUILD_WAYLAND ON" ) diff --git a/cmake/copy_files.cmake b/cmake/copy_files.cmake new file mode 100644 index 0000000..8a29a49 --- /dev/null +++ b/cmake/copy_files.cmake @@ -0,0 +1,11 @@ + +function(create_copy_folder_target target_name src dst) + add_custom_target(${target_name} + COMMAND + ${CMAKE_COMMAND} + -E copy_directory + ${src} + ${dst} + COMMENT "Copying ${src} to ${dst}" +) +endfunction() diff --git a/cmake/glsl.cmake b/cmake/glsl.cmake deleted file mode 100755 index 6b89d39..0000000 --- a/cmake/glsl.cmake +++ /dev/null @@ -1,37 +0,0 @@ -option(SHADERS_DIR "Directory to look for GLSL shaders" "assets/shaders") - -find_program(GLSLC_EXECUTABLE NAMES glslc) -if(NOT GLSLC_EXECUTABLE) - message(FATAL_ERROR "glslc executable not found.") -else() - message(STATUS "Found glslc executable: ${GLSLC_EXECUTABLE}") -endif() - -function(create_glslc_shader_target TARGET SOURCE_DIR OUTPUT_DIR) - file(MAKE_DIRECTORY ${OUTPUT_DIR}) - message(STATUS "GLSL Shader output directory: ${OUTPUT_DIR}") - file (GLOB SHADER_FILES "${SOURCE_DIR}/*.vert") - file(GLOB FRAG_FILES "${SOURCE_DIR}/*.frag") - list(APPEND SHADER_FILES ${FRAG_FILES}) - message(STATUS "Found glsl shaders: ${SHADER_FILES}") - set(OUTPUT_FILES "") - foreach(SHADER_FILE ${SHADER_FILES}) - get_filename_component(SHADER_NAME ${SHADER_FILE} NAME) - set(OUTPUT_FILE "${OUTPUT_DIR}/${SHADER_NAME}.spv") - list(APPEND OUTPUT_FILES ${OUTPUT_FILE}) - message(STATUS "Compiling ${SHADER_FILE} to ${OUTPUT_FILE}") - add_custom_command ( - OUTPUT ${OUTPUT_FILE} - COMMAND ${GLSLC_EXECUTABLE} ${SHADER_FILE} -o ${OUTPUT_FILE} - DEPENDS ${SHADER_FILE} - COMMENT "Compiling ${SHADER_FILE} -> ${OUTPUT_FILE}" - VERBATIM - ) - endforeach() - add_custom_target(${TARGET} ALL DEPENDS ${OUTPUT_FILES}) -endfunction() - -create_glslc_shader_target(glsl_shaders - "${SHADERS_DIR}" - "${CMAKE_CURRENT_BINARY_DIR}/${SHADERS_DIR}" -) diff --git a/cmake/slang-src.cmake b/cmake/slang-src.cmake new file mode 100755 index 0000000..10a9155 --- /dev/null +++ b/cmake/slang-src.cmake @@ -0,0 +1,49 @@ +set(SLANG_ENABLE_CUDA OFF CACHE BOOL "") +set(SLANG_ENABLE_OPTIX OFF CACHE BOOL "") +set(SLANG_ENABLE_NVAPI OFF CACHE BOOL "") +set(SLANG_ENABLE_XLIB OFF CACHE BOOL "") +set(SLANG_ENABLE_AFTERMATH OFF CACHE BOOL "") +set(SLANG_ENABLE_DX_ON_VK OFF CACHE BOOL "") +set(SLANG_ENABLE_GFX OFF CACHE BOOL "") +set(SLANG_ENABLE_SLANG_RHI OFF CACHE BOOL "") +set(SLANG_ENABLE_SLANGC ON CACHE BOOL "") +set(SLANG_ENABLE_SLANGRT ON CACHE BOOL "") +set(SLANG_ENABLE_SLANG_GLSLANG OFF CACHE BOOL "") +set(SLANG_ENABLE_TESTS OFF CACHE BOOL "") +set(SLANG_ENABLE_EXAMPLES OFF CACHE BOOL "") +set(SLANG_ENABLE_REPLAYER OFF CACHE BOOL "") +set(SLANG_ENABLE_PREBUILT_BINARIES OFF CACHE BOOL "") +set(SLANG_EMBED_CORE_MODULE_SOURCE OFF CACHE BOOL "") +set(SLANG_ENABLE_DXIL OFF CACHE BOOL "") +set(SLANG_LIB_TYPE STATIC CACHE STRING "") +set(SLANG_RHI_ENABLE_D3D11 OFF CACHE BOOL "") +set(SLANG_RHI_ENABLE_D3D12 OFF CACHE BOOL "") +set(SLANG_RHI_ENABLE_METAL OFF CACHE BOOL "") +set(SLANG_RHI_ENABLE_CUDA OFF CACHE BOOL "") +set(SLANG_RHI_ENABLE_WGPU OFF CACHE BOOL "") + +CPMAddPackage( + URI "gh:shader-slang/slang@2026.14" + OPTIONS "SLANG_ENABLE_CUDA OFF" + OPTIONS "SLANG_ENABLE_OPTIX OFF" + OPTIONS "SLANG_ENABLE_NVAPI OFF" + OPTIONS "SLANG_ENABLE_XLIB OFF" + OPTIONS "SLANG_ENABLE_AFTERMATH OFF" + OPTIONS "SLANG_ENABLE_DX_ON_VK OFF" + OPTIONS "SLANG_ENABLE_GFX OFF" + OPTIONS "SLANG_ENABLE_SLANG_RHI OFF" + OPTIONS "SLANG_ENABLE_SLANGC ON" + OPTIONS "SLANG_ENABLE_SLANGRT ON" + OPTIONS "SLANG_ENABLE_SLANG_GLSLANG OFF" + OPTIONS "SLANG_ENABLE_TESTS OFF" + OPTIONS "SLANG_ENABLE_REPLAYER OFF" + OPTIONS "SLANG_ENABLE_PREBUILT_BINARIES OFF" + OPTIONS "SLANG_EMBED_CORE_MODULE_SOURCE OFF" + OPTIONS "SLANG_ENABLE_DXIL OFF" + OPTIONS "SLANG_LIB_TYPE STATIC" + OPTIONS "SLANG_RHI_ENABLE_D3D11 OFF" + OPTIONS "SLANG_RHI_ENABLE_D3D12 OFF" + OPTIONS "SLANG_RHI_ENABLE_METAL OFF" + OPTIONS "SLANG_RHI_ENABLE_CUDA OFF" + OPTIONS "SLANG_RHI_ENABLE_WGPU OFF" +) \ No newline at end of file diff --git a/cmake/slang.cmake b/cmake/slang.cmake deleted file mode 100755 index 9ce9b92..0000000 --- a/cmake/slang.cmake +++ /dev/null @@ -1,36 +0,0 @@ -option(SHADERS_DIR "Directory to look for SLANG shaders" "assets/shaders") - -find_program(SLANGC_EXECUTABLE NAMES slangc) -if(NOT SLANGC_EXECUTABLE) - message(FATAL_ERROR "slangc executable not found.") -else() - message(STATUS "Found slangc executable: ${SLANGC_EXECUTABLE}") -endif() - -function(create_slang_shader_target TARGET SOURCE_DIR OUTPUT_DIR) - file(MAKE_DIRECTORY ${OUTPUT_DIR}) - message(STATUS "Shader output directory: ${OUTPUT_DIR}") - file(GLOB SHADER_FILES "${SOURCE_DIR}/*.slang") - message(STATUS "Found shaders: ${SHADER_FILES}") - set(ENTRY_POINTS -entry vertMain -entry fragMain) - set(OUTPUT_FILES "") - foreach(SHADER_FILE ${SHADER_FILES}) - get_filename_component(SHADER_NAME ${SHADER_FILE} NAME_WE) - set(OUTPUT_FILE "${OUTPUT_DIR}/${SHADER_NAME}.spv") - list(APPEND OUTPUT_FILES ${OUTPUT_FILE}) - message(STATUS "Compiling ${SHADER_FILE} to ${OUTPUT_FILE}") - add_custom_command( - OUTPUT ${OUTPUT_FILE} - COMMAND ${SLANGC_EXECUTABLE} ${SHADER_FILE} -target spirv -profile spirv_1_4 -emit-spirv-directly -fvk-use-entrypoint-name ${ENTRY_POINTS} -o ${OUTPUT_FILE} - DEPENDS ${SHADER_FILE} - COMMENT "Compiling ${SHADER_FILE} -> ${OUTPUT_FILE}" - VERBATIM - ) - endforeach() - add_custom_target(${TARGET} ALL DEPENDS ${OUTPUT_FILES}) -endfunction() - -create_slang_shader_target(slang_shaders - "${SHADERS_DIR}" - "${CMAKE_CURRENT_BINARY_DIR}/${SHADERS_DIR}" -) diff --git a/cmake/spirv-headers.cmake b/cmake/spirv-headers.cmake new file mode 100644 index 0000000..5d91c8b --- /dev/null +++ b/cmake/spirv-headers.cmake @@ -0,0 +1,7 @@ +CPMAddPackage( + URL "https://github.com/KhronosGroup/SPIRV-Headers/archive/refs/tags/vulkan-sdk-1.4.357.0.zip" + NAME SPIRV-Headers + OPTIONS "SPIRV_SKIP_TESTS TRUE" + OPTIONS "SPIRV_SKIP_EXECUTABLES TRUE" + OPTIONS "SPIRV_WERROR FALSE" +) diff --git a/cmake/spirv-reflect.cmake b/cmake/spirv-reflect.cmake new file mode 100644 index 0000000..3ba9f30 --- /dev/null +++ b/cmake/spirv-reflect.cmake @@ -0,0 +1,9 @@ +CPMAddPackage( + URI "https://github.com/KhronosGroup/SPIRV-Reflect/archive/refs/tags/vulkan-sdk-1.4.357.0.zip" + NAME SPIRV-Reflect + OPTIONS "SPIRV_SKIP_TESTS ON" + OPTIONS "SPIRV_SKIP_EXECUTABLES ON" + OPTIONS "SPIRV_WERROR OFF" + OPTIONS "SPIRV_REFLECT_EXECUTABLE OFF" + OPTIONS "SPIRV_REFLECT_STATIC_LIB ON" +) diff --git a/cmake/spirv-tools.cmake b/cmake/spirv-tools.cmake new file mode 100644 index 0000000..634c4da --- /dev/null +++ b/cmake/spirv-tools.cmake @@ -0,0 +1,11 @@ +CPMAddPackage( + NAME SPIRV-Tools + GIT_REPOSITORY "https://github.com/KhronosGroup/SPIRV-Tools" + GIT_TAG "vulkan-sdk-1.4.357" + OPTIONS "SPIRV_SKIP_TESTS ON" + OPTIONS "SPIRV_SKIP_EXECUTABLES ON" + OPTIONS "SPIRV_WERROR OFF" +) +if (TARGET spirv-tools-check-python-tests) + set_target_properties(spirv-tools-check-python-tests PROPERTIES EXCLUDE_FROM_ALL ON) +endif () diff --git a/src/app.h b/src/app.h index a2b8ef2..31a8c25 100644 --- a/src/app.h +++ b/src/app.h @@ -2,6 +2,8 @@ // INCLUDES // // Include vulkan +#include "slang.h" + #include #include @@ -106,7 +108,9 @@ private: // Shader // static std::vector readFile(const std::string &filename); - [[nodiscard]] vk::raii::ShaderModule createShaderModule(const std::vector &code) const; + [[nodiscard]] vk::raii::ShaderModule createShaderModule(const std::vector &code) const; + static void compileShaderSlang(slang::IGlobalSession *&slangGlobalSession, const char* code, const char* entryPointName, std::vector *outSPIRV); + static void optimizeSPIRV(std::vector *inoutSPIRV); // Pipeline // void createGraphicsPipeline(); diff --git a/src/main.cpp b/src/main.cpp index 0fde943..7e6280b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,8 @@ int main() { // Create the application Application app; + // TODO: Add slang global session destroy + try { // Run le app app.run(); diff --git a/src/pipeline.cpp b/src/pipeline.cpp index d85455c..cee8c20 100644 --- a/src/pipeline.cpp +++ b/src/pipeline.cpp @@ -1,21 +1,30 @@ +#include "app.h" +#include "slang-com-ptr.h" +#include "vulkan/vulkan.hpp" #include #include #include -#include "app.h" -#include "vulkan/vulkan.hpp" void Application::createGraphicsPipeline() { // Load in the shader - auto shaderCode = readFile("assets/shaders/shader.spv"); - // Create the shader module - vk::raii::ShaderModule shaderModule = createShaderModule(shaderCode); + auto shaderCode = readFile("assets/shaders/shader.slang"); + std::vector vertCode; + std::vector fragCode; + Slang::ComPtr slangGlobalSession; + compileShaderSlang(*slangGlobalSession.writeRef(), shaderCode.data(), "vertMain", &vertCode); + compileShaderSlang(*slangGlobalSession.writeRef(), shaderCode.data(), "fragMain", &fragCode); + + // Create the vertex shader module + vk::raii::ShaderModule vertModule = createShaderModule(vertCode); + // Create the fragment shader module + vk::raii::ShaderModule fragModule = createShaderModule(fragCode); // Define the fragment and vertex shader stages, making sure to specify "vertMain" and "fragMain" are the entry // points vk::PipelineShaderStageCreateInfo vertShaderStageInfo{ - .stage = vk::ShaderStageFlagBits::eVertex, .module = shaderModule, .pName = "vertMain"}; + .stage = vk::ShaderStageFlagBits::eVertex, .module = vertModule, .pName = "vertMain"}; vk::PipelineShaderStageCreateInfo fragShaderStageInfo{ - .stage = vk::ShaderStageFlagBits::eFragment, .module = shaderModule, .pName = "fragMain"}; + .stage = vk::ShaderStageFlagBits::eFragment, .module = fragModule, .pName = "fragMain"}; // Make sure the stages are in an array so its easier to pass on later on vk::PipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo}; diff --git a/src/shader.cpp b/src/shader.cpp index 8a9ad12..9dbd702 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -1,7 +1,13 @@ -#include -#include #include "app.h" #include "vulkan/vulkan.hpp" +#include +#include +#include +#include +#include +#include +#include +#include std::vector Application::readFile(const std::string &filename) { // Load the file in, checking to make sure it openned without errors @@ -21,8 +27,8 @@ std::vector Application::readFile(const std::string &filename) { return buffer; } -vk::raii::ShaderModule Application::createShaderModule(const std::vector &code) const { - // Create the shader module (feel like this is self explainatory enough to not need a comment at all...) +vk::raii::ShaderModule Application::createShaderModule(const std::vector &code) const { + // Create the shader module (feel like this is self explanatory enough to not need a comment at all...) vk::ShaderModuleCreateInfo createInfo{.codeSize = code.size() * sizeof(char), .pCode = reinterpret_cast(code.data())}; @@ -30,3 +36,121 @@ vk::raii::ShaderModule Application::createShaderModule(const std::vector & return shaderModule; } + +void Application::compileShaderSlang(slang::IGlobalSession *&slangGlobalSession, + const char *code, + const char *entryPointName, + std::vector *outSPIRV) { + if (!slangGlobalSession) { + Slang::ComPtr globalSession; + if (SLANG_FAILED(slang::createGlobalSession(globalSession.writeRef()))) { + throw std::runtime_error("Failed to create slang global session"); + } + slangGlobalSession = globalSession.detach(); + } + + // clang-format off + const slang::CompilerOptionEntry compilerOptions[] = { + {.name = slang::CompilerOptionName::Capability, .value = {.kind = slang::CompilerOptionValueKind::String, .stringValue0 = "SPV_GOOGLE_user_type"}}, + {.name = slang::CompilerOptionName::Capability, .value = {.kind = slang::CompilerOptionValueKind::String, .stringValue0 = "spvDerivativeControl"}}, + {.name = slang::CompilerOptionName::Capability, .value = {.kind = slang::CompilerOptionValueKind::String, .stringValue0 = "spvImageQuery"}}, + {.name = slang::CompilerOptionName::Capability, .value = {.kind = slang::CompilerOptionValueKind::String, .stringValue0 = "spvImageGatherExtended"}}, + {.name = slang::CompilerOptionName::Capability, .value = {.kind = slang::CompilerOptionValueKind::String, .stringValue0 = "spvSparseResidency"}}, + {.name = slang::CompilerOptionName::Capability, .value = {.kind = slang::CompilerOptionValueKind::String, .stringValue0 = "spvMinLog"}}, + {.name = slang::CompilerOptionName::Capability, .value = {.kind = slang::CompilerOptionValueKind::String, .stringValue0 = "spvFragmentFullyCoveredEXT"}}, + {.name = slang::CompilerOptionName::Capability, .value = {.kind = slang::CompilerOptionValueKind::String, .stringValue0 = "spvRayTracingPositionFetchKHR"}}, + {.name = slang::CompilerOptionName::Capability, .value = {.kind = slang::CompilerOptionValueKind::String, .stringValue0 = "spvRayQueryKHR"}}, + {.name = slang::CompilerOptionName::Capability, .value = {.kind = slang::CompilerOptionValueKind::String, .stringValue0 = "spvInt64Atomics"}}, + }; + // clang-format on + + const slang::TargetDesc targetDesc = { + .format = SLANG_SPIRV, + .profile = slangGlobalSession->findProfile("spirv_1_6"), + .flags = SLANG_TARGET_FLAG_GENERATE_SPIRV_DIRECTLY, + .forceGLSLScalarBufferLayout = true, + .compilerOptionEntries = &compilerOptions[0], + // You really should have a function that figures out the size of an + // array, but honestly even this function is beyond the scope of this + // project so im just hardcoding it for now. + .compilerOptionEntryCount = 10, + }; + + const slang::CompilerOptionEntry sessionOptions[] = { + { + .name = slang::CompilerOptionName::DisableWarning, + .value = {.kind = slang::CompilerOptionValueKind::String, .stringValue0 = "39001"}, + }, + }; + + const slang::SessionDesc sessionDesc = { + .targets = &targetDesc, + .targetCount = 1, + .compilerOptionEntries = sessionOptions, + // The same goes here as above, this *should* be automated. + .compilerOptionEntryCount = 1, + }; + + Slang::ComPtr session; + if (SLANG_FAILED(slangGlobalSession->createSession(sessionDesc, session.writeRef()))) { + throw std::runtime_error("Failed to create slang session."); + } + + slang::IModule *slangModule = nullptr; + { + Slang::ComPtr diagnosticBlob; + slangModule = session->loadModuleFromSourceString("", "", code, diagnosticBlob.writeRef()); + if (diagnosticBlob) + printf("%s", static_cast(diagnosticBlob->getBufferPointer())); + if (!slangModule) + throw std::runtime_error("Failed to load slang module from source string."); + } + + Slang::ComPtr entryPoint; + if (SLANG_FAILED(slangModule->findEntryPointByName(entryPointName, entryPoint.writeRef()))) + throw std::runtime_error("Failed to find slang shader entry point."); + + Slang::List componentTypes; + componentTypes.add(slangModule); + componentTypes.add(entryPoint); + + Slang::ComPtr composedProgram; + { + Slang::ComPtr diagnosticBlob; + SlangResult result = session->createCompositeComponentType(componentTypes.getBuffer(), componentTypes.getCount(), composedProgram.writeRef(), diagnosticBlob.writeRef()); + if (diagnosticBlob) + printf("%s\n", static_cast(diagnosticBlob->getBufferPointer())); + if (SLANG_FAILED(result)) + throw std::runtime_error("Failed to create slang composite component type."); + } + + Slang::ComPtr spirvCode; + { + Slang::ComPtr diagnosticBlob; + constexpr int entryPointIndex = 0; + const SlangResult result = composedProgram->getEntryPointCode(entryPointIndex, 0, spirvCode.writeRef(), diagnosticBlob.writeRef()); + if (diagnosticBlob) + printf("%s\n", static_cast(diagnosticBlob->getBufferPointer())); + if (SLANG_FAILED(result)) + throw std::runtime_error("Failed to get code entry point."); + } + + const auto *ptr = reinterpret_cast(spirvCode->getBufferPointer()); + *outSPIRV = std::vector(ptr, ptr + spirvCode->getBufferSize()); +} + +void Application::optimizeSPIRV(std::vector *inoutSPIRV) { + spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_4); + optimizer.RegisterPerformancePasses(); + optimizer.SetMessageConsumer([](spv_message_level_t level, const char*, const spv_position_t &, const char* msg) { + if (level <= SPV_MSG_WARNING) + printf("SPIRV-Opt: %s\n", msg); + }); + + std::vector optimized; + if (!optimizer.Run(reinterpret_cast(inoutSPIRV->data()), inoutSPIRV->size() / sizeof(uint32_t), &optimized)) + throw std::runtime_error("Failed to run spirv-opt"); + + const auto *p = reinterpret_cast(optimized.data()); + inoutSPIRV->assign(p, p + optimized.size() * sizeof(uint32_t)); +}