From e1c688bea79ad4f444649651d7814d7aa982989e Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Mon, 21 Feb 2022 18:07:22 -0500 Subject: [PATCH] Completely overhaul shader generation, again Now it's even simpler, and it now generates multiple shader languages at once! The copying mechanism is now much simpler on non-mac platforms as well. HLSL is also now a supported shader target language. --- CMakeLists.txt | 19 ++++++--- cmake/BuildShaders.cmake | 44 +++++++++++++------- engine/shadercompiler/CMakeLists.txt | 1 + engine/shadercompiler/src/shadercompiler.cpp | 14 +++++-- extern/CMakeLists.txt | 2 +- platforms/sdl/CMakeLists.txt | 21 +++------- tools/shadercompiler/main.cpp | 14 +++++-- 7 files changed, 71 insertions(+), 44 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cb7f5c..710d0d3 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,6 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(ENABLE_LINUX TRUE) set(NEEDS_HOSTED_SHADER_COMPILER FALSE) - set(REQUIRED_SHADER_LANGUAGE "spirv") endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" AND NOT IOS) @@ -40,7 +39,6 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" AND NOT IOS) set(CMAKE_XCODE_GENERATE_SCHEME OFF) set(NEEDS_HOSTED_SHADER_COMPILER FALSE) - set(REQUIRED_SHADER_LANGUAGE "msl") endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "iOS") @@ -52,7 +50,6 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "iOS") set(ENABLE_METAL TRUE) set(NEEDS_HOSTED_SHADER_COMPILER TRUE) - set(REQUIRED_SHADER_LANGUAGE "msl") set(EXTRA_PLATFORM_ARG "mobile") endif() @@ -65,7 +62,6 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "tvOS") set(ENABLE_METAL TRUE) set(NEEDS_HOSTED_SHADER_COMPILER TRUE) - set(REQUIRED_SHADER_LANGUAGE "msl") set(EXTRA_PLATFORM_ARG "mobile") endif() @@ -79,7 +75,6 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") set(ENABLE_DX12 TRUE) set(NEEDS_HOSTED_SHADER_COMPILER FALSE) - set(REQUIRED_SHADER_LANGUAGE "spirv") endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "WindowsStore") @@ -98,11 +93,23 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten") set(ENABLE_WEBGPU TRUE) set(NEEDS_HOSTED_SHADER_COMPILER TRUE) - set(REQUIRED_SHADER_LANGUAGE "wgsl") endif() if(ENABLE_VULKAN) find_package(Vulkan REQUIRED) + list(APPEND SHADER_LANGUAGES "spv") +endif() + +if(ENABLE_DX12) + list(APPEND SHADER_LANGUAGES "hlsl") +endif() + +if(ENABLE_WEBGPU) + list(APPEND SHADER_LANGUAGES "wgsl") +endif() + +if(ENABLE_METAL) + list(APPEND SHADER_LANGUAGES "msl") endif() if(NEEDS_HOSTED_SHADER_COMPILER AND (NOT DEFINED SHADER_COMPILER_LOCATION)) diff --git a/cmake/BuildShaders.cmake b/cmake/BuildShaders.cmake index 1288778..6ccf5da 100755 --- a/cmake/BuildShaders.cmake +++ b/cmake/BuildShaders.cmake @@ -1,11 +1,14 @@ # add custom command to output compiled shader function(add_shader_command) - cmake_parse_arguments(ARGS "" "FILENAME;OUT" "" ${ARGN}) + cmake_parse_arguments(ARGS "" "FILENAME;OUT;LANG" "" ${ARGN}) cmake_path(REMOVE_EXTENSION ARGS_FILENAME LAST_ONLY OUTPUT_VARIABLE FILENAME_WITHOUT_EXT) set(SRC_FILENAME ${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_FILENAME}) - set(OUTPUT_FILENAME ${CMAKE_BINARY_DIR}/${FILENAME_WITHOUT_EXT}) + set(OUTPUT_FILENAME ${CMAKE_BINARY_DIR}/bin/${FILENAME_WITHOUT_EXT}.${ARGS_LANG}) + + message(${SRC_FILENAME}) + message("new output filename " .. ${OUTPUT_FILENAME}) if(NEEDS_HOSTED_SHADER_COMPILER) set(SHADER_COMPILER_COMMAND ${SHADER_COMPILER_LOCATION}) @@ -13,19 +16,14 @@ function(add_shader_command) set(SHADER_COMPILER_COMMAND $) endif() - # we want to remove the .nocompile extension just like the tool does, if it exists - cmake_path(GET FILENAME_WITHOUT_EXT EXTENSION LAST_ONLY LAST_EXT) - - if(LAST_EXT STREQUAL ".nocompile") - cmake_path(REPLACE_EXTENSION OUTPUT_FILENAME LAST_ONLY glsl) - endif() - add_custom_command( OUTPUT ${OUTPUT_FILENAME} - COMMAND ${SHADER_COMPILER_COMMAND} ${SRC_FILENAME} ${OUTPUT_FILENAME} ${REQUIRED_SHADER_LANGUAGE} ${EXTRA_PLATFORM_ARG} + COMMAND ${SHADER_COMPILER_COMMAND} ${SRC_FILENAME} ${OUTPUT_FILENAME} ${ARGS_LANG} ${EXTRA_PLATFORM_ARG} DEPENDS ${SRC_FILENAME} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/shaders) + message(${SRC_FILENAME}) + # return the actual filename set(${ARGS_OUT} ${OUTPUT_FILENAME} PARENT_SCOPE) endfunction() @@ -34,13 +32,25 @@ endfunction() function(add_shaders) cmake_parse_arguments(ARGS "" "TARGET" "SHADERS" ${ARGN}) - foreach(SHADER_FILENAME ${ARGS_SHADERS}) - cmake_path(REMOVE_EXTENSION SHADER_FILENAME LAST_ONLY OUTPUT_VARIABLE FILENAME_WITHOUT_EXT) + foreach(SHADER_LANG ${SHADER_LANGUAGES}) + message(${SHADER_LANG}) + foreach(SHADER_FILENAME ${ARGS_SHADERS}) + cmake_path(REMOVE_EXTENSION SHADER_FILENAME LAST_ONLY OUTPUT_VARIABLE FILENAME_WITHOUT_EXT) - add_shader_command(FILENAME ${SHADER_FILENAME} OUT DST_FILENAME) + # we want to remove the .nocompile extension just like the tool does, if it exists + cmake_path(GET FILENAME_WITHOUT_EXT EXTENSION LAST_ONLY LAST_EXT) - list(APPEND SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER_FILENAME}) - list(APPEND DST_FILES ${DST_FILENAME}) + set(NEW_SHADER_LANG ${SHADER_LANG}) + if(LAST_EXT STREQUAL ".nocompile") + set(NEW_SHADER_LANG glsl) + cmake_path(REPLACE_EXTENSION FILENAME_WITHOUT_EXT LAST_ONLY glsl) + endif() + + add_shader_command(FILENAME ${SHADER_FILENAME} OUT DST_FILENAME LANG ${NEW_SHADER_LANG}) + + list(APPEND SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER_FILENAME}) + list(APPEND DST_FILES ${DST_FILENAME}) + endforeach() endforeach() if(NOT NEEDS_HOSTED_SHADER_COMPILER) @@ -49,8 +59,10 @@ function(add_shaders) add_custom_target(BuildShaders DEPENDS ${DST_FILES}) endif() + message(${DST_FILES}) + add_dependencies(${ARGS_TARGET} BuildShaders) endfunction() # make the shader directory if it doesnt exist already -file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/shaders) +file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin/shaders) diff --git a/engine/shadercompiler/CMakeLists.txt b/engine/shadercompiler/CMakeLists.txt index 39dffdf..38dbda5 100755 --- a/engine/shadercompiler/CMakeLists.txt +++ b/engine/shadercompiler/CMakeLists.txt @@ -15,6 +15,7 @@ target_link_libraries(ShaderCompiler spirv-cross-core spirv-cross-glsl spirv-cross-msl + spirv-cross-hlsl glslang SPIRV) target_include_directories(ShaderCompiler PUBLIC include PRIVATE src) diff --git a/engine/shadercompiler/src/shadercompiler.cpp b/engine/shadercompiler/src/shadercompiler.cpp index 93e7e33..0c5a6be 100755 --- a/engine/shadercompiler/src/shadercompiler.cpp +++ b/engine/shadercompiler/src/shadercompiler.cpp @@ -7,6 +7,7 @@ #include "string_utils.hpp" #include "includer.hpp" #include "defaultresources.hpp" +#include "spirv_hlsl.hpp" static inline std::vector include_path; @@ -132,9 +133,16 @@ std::optional ShaderCompiler::compile(const ShaderLanguage from_la return ShaderSource(msl.compile()); } - case ShaderLanguage::HLSL: - prism::log("Unimplemented shader language: HLSL"); - return ShaderSource(spirv); + case ShaderLanguage::HLSL: { + spirv_cross::CompilerHLSL hlsl(std::move(spirv)); + + spirv_cross::CompilerHLSL::Options opts; + opts.shader_model = 60; + + hlsl.set_hlsl_options(opts); + + return ShaderSource(hlsl.compile()); + } default: return {}; } diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index 0128b39..815048b 100755 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -44,7 +44,7 @@ set(SPIRV_CROSS_SKIP_INSTALL ON CACHE BOOL "" FORCE) set(BUILD_EXTERNAL OFF CACHE BOOL "" FORCE) set(SPIRV_CROSS_CLI OFF CACHE BOOL "" FORCE) set(SPIRV_CROSS_ENABLE_TESTS OFF CACHE BOOL "" FORCE) -set(SPIRV_CROSS_ENABLE_HLSL OFF CACHE BOOL "" FORCE) +set(SPIRV_CROSS_ENABLE_HLSL ON CACHE BOOL "" FORCE) set(SPIRV_CROSS_ENABLE_CPP OFF CACHE BOOL "" FORCE) set(SPIRV_CROSS_ENABLE_REFLECT OFF CACHE BOOL "" FORCE) set(SPIRV_CROSS_ENABLE_C_API OFF CACHE BOOL "" FORCE) diff --git a/platforms/sdl/CMakeLists.txt b/platforms/sdl/CMakeLists.txt index 766149c..21913eb 100644 --- a/platforms/sdl/CMakeLists.txt +++ b/platforms/sdl/CMakeLists.txt @@ -44,27 +44,18 @@ add_platform( ) function(add_platform_commands target) - # we HAVE to create this dummy target to convince CMake to properly copy over shader files. - # before you ask, we have used POST_BUILD before but that only runs if the TARGET specified is built. - # when you change a shader source file on disk, BuildShaders is triggered but that doesn't retrigger your actual - # app target to be rebuilt, so the shaders are never copied correctly. With this (dumb) system, we ensure they - # always are. WHY CMAKE WHY - set(DUMMY_NAME ${target}-CopyShaders) - - add_custom_target(${DUMMY_NAME} ALL DEPENDS ${CMAKE_BINARY_DIR}/${target}-dummy) - if(ENABLE_MACOS) + set(DUMMY_NAME ${target}-CopyShaders) + + add_custom_target(${DUMMY_NAME} ALL DEPENDS ${CMAKE_BINARY_DIR}/${target}-dummy) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${target}-dummy COMMAND ${CMAKE_COMMAND} -E make_directory $/../Resources/shaders COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $/../Resources/shaders ) - else() - add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${target}-dummy - COMMAND ${CMAKE_COMMAND} -E make_directory $/shaders - COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $/shaders - ) + + add_dependencies(${target} ${DUMMY_NAME}) endif() - add_dependencies(${target} ${DUMMY_NAME}) if(NOT SKIP_DATA) add_custom_target(${target}_copy_assets diff --git a/tools/shadercompiler/main.cpp b/tools/shadercompiler/main.cpp index 1107229..63f5dd7 100755 --- a/tools/shadercompiler/main.cpp +++ b/tools/shadercompiler/main.cpp @@ -22,7 +22,7 @@ int main(int argc, char* argv[]) { ShaderLanguage language = ShaderLanguage::SPIRV; std::string_view shader_language_string = argv[3]; - if(shader_language_string == "spirv") { + if(shader_language_string == "spv") { language = ShaderLanguage::SPIRV; } else if(shader_language_string == "msl") { language = ShaderLanguage::MSL; @@ -30,6 +30,8 @@ int main(int argc, char* argv[]) { language = ShaderLanguage::WGSL; } else if(shader_language_string == "glsl") { language = ShaderLanguage::GLSL; + } else if(shader_language_string == "hlsl") { + language = ShaderLanguage::HLSL; } CompileOptions options; @@ -69,13 +71,19 @@ int main(int argc, char* argv[]) { { const auto spirv = compiled_source->as_bytecode(); - std::ofstream out(destination_path.replace_extension(destination_path.extension().string() + ".spv"), std::ios::binary); // remove .glsl + std::ofstream out(destination_path, std::ios::binary); // remove .glsl out.write((char*)spirv.data(), spirv.size() * sizeof(uint32_t)); } break; case ShaderLanguage::MSL: { - std::ofstream out(destination_path.replace_extension(destination_path.extension().string() + ".msl")); // remove .glsl + std::ofstream out(destination_path); // remove .glsl + out << compiled_source->as_string(); + } + break; + case ShaderLanguage::HLSL: + { + std::ofstream out(destination_path); // remove .glsl out << compiled_source->as_string(); } break;