From fb5558b07691fac50f949aa6b8602cd9fcb6a1de Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Sun, 20 Feb 2022 22:51:05 -0500 Subject: [PATCH] A huge overhaul of how hosted shader compilers work Now it's much more usable, you are forced to use a hosted shader compiler on a platform that needs it (for example, iOS) and now CMake will error when it's missing. Now every platform is very specific on which languages it needs to be translated to, and whether a hosted compiler is needed. No more manually copying over shaders! --- CMakeLists.txt | 27 +++++++++++++++++++++++++ cmake/BuildShaders.cmake | 38 +++++++++++++++++------------------ tools/shadercompiler/main.cpp | 33 ++++++++++++++++++++---------- 3 files changed, 68 insertions(+), 30 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c7631d4..87e9e51 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,9 @@ include(${CMAKE_CURRENT_LIST_DIR}/cmake/Common.cmake) include(${CMAKE_CURRENT_LIST_DIR}/cmake/AddPlatformExecutable.cmake) include(FetchContent) +#set(SHADER_COMPILER_COMMAND $) +# set(SHADER_COMPILER_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/../build/bin/Debug/ShaderCompilerTool") + if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") message("Linux build detected!") @@ -17,6 +20,9 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(ENABLE_VULKAN TRUE) 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) @@ -30,6 +36,8 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" AND NOT IOS) set(ENABLE_METAL TRUE) set(CMAKE_XCODE_GENERATE_SCHEME OFF) + set(NEEDS_HOSTED_SHADER_COMPILER FALSE) + set(REQUIRED_SHADER_LANGUAGE "msl") endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "iOS") @@ -39,6 +47,10 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "iOS") set(ENABLE_DARWIN TRUE) set(ENABLE_IOS TRUE) set(ENABLE_METAL TRUE) + + set(NEEDS_HOSTED_SHADER_COMPILER TRUE) + set(REQUIRED_SHADER_LANGUAGE "msl") + set(EXTRA_PLATFORM_ARG "mobile") endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "tvOS") @@ -48,6 +60,10 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "tvOS") set(ENABLE_DARWIN TRUE) set(ENABLE_TVOS TRUE) set(ENABLE_METAL TRUE) + + set(NEEDS_HOSTED_SHADER_COMPILER TRUE) + set(REQUIRED_SHADER_LANGUAGE "msl") + set(EXTRA_PLATFORM_ARG "mobile") endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") @@ -57,12 +73,16 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") set(ENABLE_WINDOWS TRUE) set(ENABLE_VULKAN TRUE) + + set(NEEDS_HOSTED_SHADER_COMPILER FALSE) + set(REQUIRED_SHADER_LANGUAGE "spirv") endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "WindowsStore") message("UWP build detected!") set(ENABLE_UWP TRUE) + set(NEEDS_HOSTED_SHADER_COMPILER TRUE) endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten") @@ -72,6 +92,13 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten") set(ENABLE_WEB TRUE) set(ENABLE_WEBGPU TRUE) + + set(NEEDS_HOSTED_SHADER_COMPILER TRUE) + set(REQUIRED_SHADER_LANGUAGE "wgsl") +endif() + +if(NEEDS_HOSTED_SHADER_COMPILER AND (NOT DEFINED SHADER_COMPILER_LOCATION)) + message(FATAL_ERROR "You are building for a platform that needs a hosted shader compiler. Please specify the path in SHADER_COMPILER_LOCATION!") endif() set(CROSS_LIBS diff --git a/cmake/BuildShaders.cmake b/cmake/BuildShaders.cmake index a243329..1288778 100755 --- a/cmake/BuildShaders.cmake +++ b/cmake/BuildShaders.cmake @@ -4,18 +4,15 @@ function(add_shader_command) cmake_path(REMOVE_EXTENSION ARGS_FILENAME LAST_ONLY OUTPUT_VARIABLE FILENAME_WITHOUT_EXT) - set(SHADER_COMPILER_COMMAND $) - set(EXTRA_PLATFORM_ARG "0") - - # if targeting ios, we want to use the host's shader compiler - if(ENABLE_IOS OR ENABLE_TVOS) - set(SHADER_COMPILER_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/../build/bin/Debug/ShaderCompilerTool") - set(EXTRA_PLATFORM_ARG "1") - endif() - set(SRC_FILENAME ${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_FILENAME}) set(OUTPUT_FILENAME ${CMAKE_BINARY_DIR}/${FILENAME_WITHOUT_EXT}) + if(NEEDS_HOSTED_SHADER_COMPILER) + set(SHADER_COMPILER_COMMAND ${SHADER_COMPILER_LOCATION}) + else() + 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) @@ -25,7 +22,7 @@ function(add_shader_command) add_custom_command( OUTPUT ${OUTPUT_FILENAME} - COMMAND ${SHADER_COMPILER_COMMAND} ${SRC_FILENAME} ${OUTPUT_FILENAME} ${EXTRA_PLATFORM_ARG} + COMMAND ${SHADER_COMPILER_COMMAND} ${SRC_FILENAME} ${OUTPUT_FILENAME} ${REQUIRED_SHADER_LANGUAGE} ${EXTRA_PLATFORM_ARG} DEPENDS ${SRC_FILENAME} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/shaders) @@ -35,21 +32,24 @@ endfunction() # add shaders to target function(add_shaders) - if(NOT ENABLE_IOS AND NOT ENABLE_TVOS AND NOT ENABLE_WEB) - cmake_parse_arguments(ARGS "" "TARGET" "SHADERS" ${ARGN}) + 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_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) + add_shader_command(FILENAME ${SHADER_FILENAME} OUT DST_FILENAME) - list(APPEND SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER_FILENAME}) - list(APPEND DST_FILES ${DST_FILENAME}) - endforeach() + list(APPEND SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER_FILENAME}) + list(APPEND DST_FILES ${DST_FILENAME}) + endforeach() + if(NOT NEEDS_HOSTED_SHADER_COMPILER) add_custom_target(BuildShaders DEPENDS ShaderCompilerTool ${DST_FILES}) - add_dependencies(${ARGS_TARGET} BuildShaders) + else() + add_custom_target(BuildShaders DEPENDS ${DST_FILES}) endif() + + add_dependencies(${ARGS_TARGET} BuildShaders) endfunction() # make the shader directory if it doesnt exist already diff --git a/tools/shadercompiler/main.cpp b/tools/shadercompiler/main.cpp index dada7a8..bfe784b 100755 --- a/tools/shadercompiler/main.cpp +++ b/tools/shadercompiler/main.cpp @@ -4,6 +4,7 @@ #include "shadercompiler.hpp" #include "log.hpp" #include "string_utils.hpp" +#include "utility.hpp" bool has_extension(const std::filesystem::path& path, const std::string_view extension) { return string_contains(path.filename().string(), extension); @@ -16,10 +17,28 @@ int main(int argc, char* argv[]) { } shader_compiler.set_include_path(std::filesystem::current_path().string()); - + std::filesystem::path source_path = argv[1]; std::filesystem::path destination_path = argv[2]; + ShaderLanguage language = ShaderLanguage::SPIRV; + std::string_view shader_language_string = argv[3]; + if(shader_language_string == "spirv") { + language = ShaderLanguage::SPIRV; + } else if(shader_language_string == "msl") { + language = ShaderLanguage::MSL; + } else if(shader_language_string == "wgsl") { + language = ShaderLanguage::WGSL; + } else if(shader_language_string == "glsl") { + language = ShaderLanguage::GLSL; + } + + CompileOptions options; + + std::string_view extra_options = argc > 4 ? argv[4] : ""; + if(extra_options == "mobile") + options.is_apple_mobile = true; + std::ifstream t(source_path); std::stringstream buffer; buffer << t.rdbuf(); @@ -38,16 +57,6 @@ int main(int argc, char* argv[]) { else if(has_extension(source_path, ".comp")) stage = ShaderStage::Compute; - ShaderLanguage language; - CompileOptions options; -#ifdef PLATFORM_MACOS - options.is_apple_mobile = (bool)argv[3]; - - language = ShaderLanguage::MSL; -#else - language = ShaderLanguage::SPIRV; -#endif - const auto compiled_source = shader_compiler.compile(ShaderLanguage::GLSL, stage, ShaderSource(buffer.str()), language, options); if(!compiled_source.has_value()) { prism::log("Error when compiling {}!", source_path.string()); @@ -55,6 +64,8 @@ int main(int argc, char* argv[]) { } switch(language) { + // right now, WGSL is outputted as SPIR-V with some WGSL compatibility stuff included + case ShaderLanguage::WGSL: case ShaderLanguage::SPIRV: { const auto spirv = compiled_source->as_bytecode();