Archived
1
Fork 0

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!
This commit is contained in:
Joshua Goins 2022-02-20 22:51:05 -05:00
parent c557c51eb6
commit fb5558b076
3 changed files with 68 additions and 30 deletions

View file

@ -10,6 +10,9 @@ include(${CMAKE_CURRENT_LIST_DIR}/cmake/Common.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/cmake/AddPlatformExecutable.cmake) include(${CMAKE_CURRENT_LIST_DIR}/cmake/AddPlatformExecutable.cmake)
include(FetchContent) include(FetchContent)
#set(SHADER_COMPILER_COMMAND $<TARGET_FILE:ShaderCompilerTool>)
# set(SHADER_COMPILER_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/../build/bin/Debug/ShaderCompilerTool")
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
message("Linux build detected!") message("Linux build detected!")
@ -17,6 +20,9 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(ENABLE_VULKAN TRUE) set(ENABLE_VULKAN TRUE)
set(ENABLE_LINUX TRUE) set(ENABLE_LINUX TRUE)
set(NEEDS_HOSTED_SHADER_COMPILER FALSE)
set(REQUIRED_SHADER_LANGUAGE "spirv")
endif() endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" AND NOT IOS) 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(ENABLE_METAL TRUE)
set(CMAKE_XCODE_GENERATE_SCHEME OFF) set(CMAKE_XCODE_GENERATE_SCHEME OFF)
set(NEEDS_HOSTED_SHADER_COMPILER FALSE)
set(REQUIRED_SHADER_LANGUAGE "msl")
endif() endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "iOS") if(${CMAKE_SYSTEM_NAME} STREQUAL "iOS")
@ -39,6 +47,10 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "iOS")
set(ENABLE_DARWIN TRUE) set(ENABLE_DARWIN TRUE)
set(ENABLE_IOS TRUE) set(ENABLE_IOS TRUE)
set(ENABLE_METAL TRUE) set(ENABLE_METAL TRUE)
set(NEEDS_HOSTED_SHADER_COMPILER TRUE)
set(REQUIRED_SHADER_LANGUAGE "msl")
set(EXTRA_PLATFORM_ARG "mobile")
endif() endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "tvOS") if(${CMAKE_SYSTEM_NAME} STREQUAL "tvOS")
@ -48,6 +60,10 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "tvOS")
set(ENABLE_DARWIN TRUE) set(ENABLE_DARWIN TRUE)
set(ENABLE_TVOS TRUE) set(ENABLE_TVOS TRUE)
set(ENABLE_METAL TRUE) set(ENABLE_METAL TRUE)
set(NEEDS_HOSTED_SHADER_COMPILER TRUE)
set(REQUIRED_SHADER_LANGUAGE "msl")
set(EXTRA_PLATFORM_ARG "mobile")
endif() endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
@ -57,12 +73,16 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
set(ENABLE_WINDOWS TRUE) set(ENABLE_WINDOWS TRUE)
set(ENABLE_VULKAN TRUE) set(ENABLE_VULKAN TRUE)
set(NEEDS_HOSTED_SHADER_COMPILER FALSE)
set(REQUIRED_SHADER_LANGUAGE "spirv")
endif() endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "WindowsStore") if(${CMAKE_SYSTEM_NAME} STREQUAL "WindowsStore")
message("UWP build detected!") message("UWP build detected!")
set(ENABLE_UWP TRUE) set(ENABLE_UWP TRUE)
set(NEEDS_HOSTED_SHADER_COMPILER TRUE)
endif() endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten") if(${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten")
@ -72,6 +92,13 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten")
set(ENABLE_WEB TRUE) set(ENABLE_WEB TRUE)
set(ENABLE_WEBGPU 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() endif()
set(CROSS_LIBS set(CROSS_LIBS

View file

@ -4,18 +4,15 @@ function(add_shader_command)
cmake_path(REMOVE_EXTENSION ARGS_FILENAME LAST_ONLY OUTPUT_VARIABLE FILENAME_WITHOUT_EXT) cmake_path(REMOVE_EXTENSION ARGS_FILENAME LAST_ONLY OUTPUT_VARIABLE FILENAME_WITHOUT_EXT)
set(SHADER_COMPILER_COMMAND $<TARGET_FILE:ShaderCompilerTool>)
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(SRC_FILENAME ${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_FILENAME})
set(OUTPUT_FILENAME ${CMAKE_BINARY_DIR}/${FILENAME_WITHOUT_EXT}) 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 $<TARGET_FILE:ShaderCompilerTool>)
endif()
# we want to remove the .nocompile extension just like the tool does, if it exists # 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) cmake_path(GET FILENAME_WITHOUT_EXT EXTENSION LAST_ONLY LAST_EXT)
@ -25,7 +22,7 @@ function(add_shader_command)
add_custom_command( add_custom_command(
OUTPUT ${OUTPUT_FILENAME} 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} DEPENDS ${SRC_FILENAME}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/shaders) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/shaders)
@ -35,21 +32,24 @@ endfunction()
# add shaders to target # add shaders to target
function(add_shaders) 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}) foreach(SHADER_FILENAME ${ARGS_SHADERS})
cmake_path(REMOVE_EXTENSION SHADER_FILENAME LAST_ONLY OUTPUT_VARIABLE FILENAME_WITHOUT_EXT) 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 SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER_FILENAME})
list(APPEND DST_FILES ${DST_FILENAME}) list(APPEND DST_FILES ${DST_FILENAME})
endforeach() endforeach()
if(NOT NEEDS_HOSTED_SHADER_COMPILER)
add_custom_target(BuildShaders DEPENDS ShaderCompilerTool ${DST_FILES}) add_custom_target(BuildShaders DEPENDS ShaderCompilerTool ${DST_FILES})
add_dependencies(${ARGS_TARGET} BuildShaders) else()
add_custom_target(BuildShaders DEPENDS ${DST_FILES})
endif() endif()
add_dependencies(${ARGS_TARGET} BuildShaders)
endfunction() endfunction()
# make the shader directory if it doesnt exist already # make the shader directory if it doesnt exist already

View file

@ -4,6 +4,7 @@
#include "shadercompiler.hpp" #include "shadercompiler.hpp"
#include "log.hpp" #include "log.hpp"
#include "string_utils.hpp" #include "string_utils.hpp"
#include "utility.hpp"
bool has_extension(const std::filesystem::path& path, const std::string_view extension) { bool has_extension(const std::filesystem::path& path, const std::string_view extension) {
return string_contains(path.filename().string(), 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()); shader_compiler.set_include_path(std::filesystem::current_path().string());
std::filesystem::path source_path = argv[1]; std::filesystem::path source_path = argv[1];
std::filesystem::path destination_path = argv[2]; 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::ifstream t(source_path);
std::stringstream buffer; std::stringstream buffer;
buffer << t.rdbuf(); buffer << t.rdbuf();
@ -38,16 +57,6 @@ int main(int argc, char* argv[]) {
else if(has_extension(source_path, ".comp")) else if(has_extension(source_path, ".comp"))
stage = ShaderStage::Compute; 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); const auto compiled_source = shader_compiler.compile(ShaderLanguage::GLSL, stage, ShaderSource(buffer.str()), language, options);
if(!compiled_source.has_value()) { if(!compiled_source.has_value()) {
prism::log("Error when compiling {}!", source_path.string()); prism::log("Error when compiling {}!", source_path.string());
@ -55,6 +64,8 @@ int main(int argc, char* argv[]) {
} }
switch(language) { switch(language) {
// right now, WGSL is outputted as SPIR-V with some WGSL compatibility stuff included
case ShaderLanguage::WGSL:
case ShaderLanguage::SPIRV: case ShaderLanguage::SPIRV:
{ {
const auto spirv = compiled_source->as_bytecode(); const auto spirv = compiled_source->as_bytecode();