Archived
1
Fork 0

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.
This commit is contained in:
Joshua Goins 2022-02-21 18:07:22 -05:00
parent e03d0eceac
commit e1c688bea7
7 changed files with 71 additions and 44 deletions

View file

@ -25,7 +25,6 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(ENABLE_LINUX TRUE) set(ENABLE_LINUX TRUE)
set(NEEDS_HOSTED_SHADER_COMPILER FALSE) 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)
@ -40,7 +39,6 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" AND NOT IOS)
set(CMAKE_XCODE_GENERATE_SCHEME OFF) set(CMAKE_XCODE_GENERATE_SCHEME OFF)
set(NEEDS_HOSTED_SHADER_COMPILER FALSE) 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")
@ -52,7 +50,6 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "iOS")
set(ENABLE_METAL TRUE) set(ENABLE_METAL TRUE)
set(NEEDS_HOSTED_SHADER_COMPILER TRUE) set(NEEDS_HOSTED_SHADER_COMPILER TRUE)
set(REQUIRED_SHADER_LANGUAGE "msl")
set(EXTRA_PLATFORM_ARG "mobile") set(EXTRA_PLATFORM_ARG "mobile")
endif() endif()
@ -65,7 +62,6 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "tvOS")
set(ENABLE_METAL TRUE) set(ENABLE_METAL TRUE)
set(NEEDS_HOSTED_SHADER_COMPILER TRUE) set(NEEDS_HOSTED_SHADER_COMPILER TRUE)
set(REQUIRED_SHADER_LANGUAGE "msl")
set(EXTRA_PLATFORM_ARG "mobile") set(EXTRA_PLATFORM_ARG "mobile")
endif() endif()
@ -79,7 +75,6 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
set(ENABLE_DX12 TRUE) set(ENABLE_DX12 TRUE)
set(NEEDS_HOSTED_SHADER_COMPILER FALSE) 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")
@ -98,11 +93,23 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten")
set(ENABLE_WEBGPU TRUE) set(ENABLE_WEBGPU TRUE)
set(NEEDS_HOSTED_SHADER_COMPILER TRUE) set(NEEDS_HOSTED_SHADER_COMPILER TRUE)
set(REQUIRED_SHADER_LANGUAGE "wgsl")
endif() endif()
if(ENABLE_VULKAN) if(ENABLE_VULKAN)
find_package(Vulkan REQUIRED) 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() endif()
if(NEEDS_HOSTED_SHADER_COMPILER AND (NOT DEFINED SHADER_COMPILER_LOCATION)) if(NEEDS_HOSTED_SHADER_COMPILER AND (NOT DEFINED SHADER_COMPILER_LOCATION))

View file

@ -1,11 +1,14 @@
# add custom command to output compiled shader # add custom command to output compiled shader
function(add_shader_command) 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) cmake_path(REMOVE_EXTENSION ARGS_FILENAME LAST_ONLY OUTPUT_VARIABLE FILENAME_WITHOUT_EXT)
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}/bin/${FILENAME_WITHOUT_EXT}.${ARGS_LANG})
message(${SRC_FILENAME})
message("new output filename " .. ${OUTPUT_FILENAME})
if(NEEDS_HOSTED_SHADER_COMPILER) if(NEEDS_HOSTED_SHADER_COMPILER)
set(SHADER_COMPILER_COMMAND ${SHADER_COMPILER_LOCATION}) set(SHADER_COMPILER_COMMAND ${SHADER_COMPILER_LOCATION})
@ -13,19 +16,14 @@ function(add_shader_command)
set(SHADER_COMPILER_COMMAND $<TARGET_FILE:ShaderCompilerTool>) set(SHADER_COMPILER_COMMAND $<TARGET_FILE:ShaderCompilerTool>)
endif() 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( add_custom_command(
OUTPUT ${OUTPUT_FILENAME} 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} DEPENDS ${SRC_FILENAME}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/shaders) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/shaders)
message(${SRC_FILENAME})
# return the actual filename # return the actual filename
set(${ARGS_OUT} ${OUTPUT_FILENAME} PARENT_SCOPE) set(${ARGS_OUT} ${OUTPUT_FILENAME} PARENT_SCOPE)
endfunction() endfunction()
@ -34,14 +32,26 @@ endfunction()
function(add_shaders) function(add_shaders)
cmake_parse_arguments(ARGS "" "TARGET" "SHADERS" ${ARGN}) cmake_parse_arguments(ARGS "" "TARGET" "SHADERS" ${ARGN})
foreach(SHADER_LANG ${SHADER_LANGUAGES})
message(${SHADER_LANG})
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) # 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)
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 SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER_FILENAME})
list(APPEND DST_FILES ${DST_FILENAME}) list(APPEND DST_FILES ${DST_FILENAME})
endforeach() endforeach()
endforeach()
if(NOT NEEDS_HOSTED_SHADER_COMPILER) if(NOT NEEDS_HOSTED_SHADER_COMPILER)
add_custom_target(BuildShaders DEPENDS ShaderCompilerTool ${DST_FILES}) add_custom_target(BuildShaders DEPENDS ShaderCompilerTool ${DST_FILES})
@ -49,8 +59,10 @@ function(add_shaders)
add_custom_target(BuildShaders DEPENDS ${DST_FILES}) add_custom_target(BuildShaders DEPENDS ${DST_FILES})
endif() endif()
message(${DST_FILES})
add_dependencies(${ARGS_TARGET} BuildShaders) 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
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/shaders) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin/shaders)

View file

@ -15,6 +15,7 @@ target_link_libraries(ShaderCompiler
spirv-cross-core spirv-cross-core
spirv-cross-glsl spirv-cross-glsl
spirv-cross-msl spirv-cross-msl
spirv-cross-hlsl
glslang glslang
SPIRV) SPIRV)
target_include_directories(ShaderCompiler PUBLIC include PRIVATE src) target_include_directories(ShaderCompiler PUBLIC include PRIVATE src)

View file

@ -7,6 +7,7 @@
#include "string_utils.hpp" #include "string_utils.hpp"
#include "includer.hpp" #include "includer.hpp"
#include "defaultresources.hpp" #include "defaultresources.hpp"
#include "spirv_hlsl.hpp"
static inline std::vector<std::string> include_path; static inline std::vector<std::string> include_path;
@ -132,9 +133,16 @@ std::optional<ShaderSource> ShaderCompiler::compile(const ShaderLanguage from_la
return ShaderSource(msl.compile()); return ShaderSource(msl.compile());
} }
case ShaderLanguage::HLSL: case ShaderLanguage::HLSL: {
prism::log("Unimplemented shader language: HLSL"); spirv_cross::CompilerHLSL hlsl(std::move(spirv));
return ShaderSource(spirv);
spirv_cross::CompilerHLSL::Options opts;
opts.shader_model = 60;
hlsl.set_hlsl_options(opts);
return ShaderSource(hlsl.compile());
}
default: default:
return {}; return {};
} }

View file

@ -44,7 +44,7 @@ set(SPIRV_CROSS_SKIP_INSTALL ON CACHE BOOL "" FORCE)
set(BUILD_EXTERNAL OFF CACHE BOOL "" FORCE) set(BUILD_EXTERNAL OFF CACHE BOOL "" FORCE)
set(SPIRV_CROSS_CLI 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_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_CPP OFF CACHE BOOL "" FORCE)
set(SPIRV_CROSS_ENABLE_REFLECT OFF CACHE BOOL "" FORCE) set(SPIRV_CROSS_ENABLE_REFLECT OFF CACHE BOOL "" FORCE)
set(SPIRV_CROSS_ENABLE_C_API OFF CACHE BOOL "" FORCE) set(SPIRV_CROSS_ENABLE_C_API OFF CACHE BOOL "" FORCE)

View file

@ -44,27 +44,18 @@ add_platform(
) )
function(add_platform_commands target) function(add_platform_commands target)
# we HAVE to create this dummy target to convince CMake to properly copy over shader files. if(ENABLE_MACOS)
# 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) set(DUMMY_NAME ${target}-CopyShaders)
add_custom_target(${DUMMY_NAME} ALL DEPENDS ${CMAKE_BINARY_DIR}/${target}-dummy) add_custom_target(${DUMMY_NAME} ALL DEPENDS ${CMAKE_BINARY_DIR}/${target}-dummy)
if(ENABLE_MACOS)
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${target}-dummy add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${target}-dummy
COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:${target}>/../Resources/shaders COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:${target}>/../Resources/shaders
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $<TARGET_FILE_DIR:${target}>/../Resources/shaders COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $<TARGET_FILE_DIR:${target}>/../Resources/shaders
) )
else()
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${target}-dummy
COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:${target}>/shaders
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $<TARGET_FILE_DIR:${target}>/shaders
)
endif()
add_dependencies(${target} ${DUMMY_NAME}) add_dependencies(${target} ${DUMMY_NAME})
endif()
if(NOT SKIP_DATA) if(NOT SKIP_DATA)
add_custom_target(${target}_copy_assets add_custom_target(${target}_copy_assets

View file

@ -22,7 +22,7 @@ int main(int argc, char* argv[]) {
ShaderLanguage language = ShaderLanguage::SPIRV; ShaderLanguage language = ShaderLanguage::SPIRV;
std::string_view shader_language_string = argv[3]; std::string_view shader_language_string = argv[3];
if(shader_language_string == "spirv") { if(shader_language_string == "spv") {
language = ShaderLanguage::SPIRV; language = ShaderLanguage::SPIRV;
} else if(shader_language_string == "msl") { } else if(shader_language_string == "msl") {
language = ShaderLanguage::MSL; language = ShaderLanguage::MSL;
@ -30,6 +30,8 @@ int main(int argc, char* argv[]) {
language = ShaderLanguage::WGSL; language = ShaderLanguage::WGSL;
} else if(shader_language_string == "glsl") { } else if(shader_language_string == "glsl") {
language = ShaderLanguage::GLSL; language = ShaderLanguage::GLSL;
} else if(shader_language_string == "hlsl") {
language = ShaderLanguage::HLSL;
} }
CompileOptions options; CompileOptions options;
@ -69,13 +71,19 @@ int main(int argc, char* argv[]) {
{ {
const auto spirv = compiled_source->as_bytecode(); 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)); out.write((char*)spirv.data(), spirv.size() * sizeof(uint32_t));
} }
break; break;
case ShaderLanguage::MSL: 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(); out << compiled_source->as_string();
} }
break; break;